Image for SEO With Hugo (7) Javascript Optimization hero section
  • CLIENTI: Bullaki
  • PRODUCER: Samuele Lilliu
  • SOFTWARE: Hugo, HTML, JavaScript

Overview

A webpage that loads quickly is highly valued by search engines because it provides a better user experience for the visitors. Search engines, such as Google, prioritize website that load faster in their search results because it is an indicator of a high-quality website. Here are some reasons why a faster loading webpage is rewarded by search engines:

  • User Experience: Search engines prioritize websites that provide a positive user experience. A webpage that loads quickly is more likely to keep visitors engaged and reduce bounce rates.
  • Mobile Optimization: With the increase in mobile usage, search engines also consider the loading speed on mobile devices. Slow loading webpages on mobile can lead to poor user experience and higher bounce rates.
  • Page Speed as a Ranking Factor: Page speed is a ranking factor in search engine algorithms. A webpage that loads quickly is more likely to rank higher in search results than one that takes longer to load.
  • Increased Crawl Efficiency: Search engines use web crawlers to index websites and gather information about them. A faster loading webpage allows web crawlers to index the website more efficiently and effectively.
  • Improved Conversion Rates: A faster loading webpage can lead to improved conversion rates as visitors are more likely to stay on the website, which can lead to increased lead generation and sales.

Static Sites are faster than Dynamic Sites

Using a static website generator like Hugo can result in faster loading speeds compared to dynamic website builders like WordPress. The main reason for this is that static website generators generate a fixed version of the website, whereas dynamic website builders generate the website on-the-fly every time a user requests it.

When a user requests a webpage from a dynamic website builder like WordPress, the server has to go through a series of steps before it can display the webpage. These steps include querying the database, running the PHP code, and generating the HTML. This process can take longer compared to serving a pre-built HTML file from a static website generator.

Static website generators like Hugo, on the other hand, generate a fixed version of the website, which is then served to the user. This means that the server does not have to go through the same process of querying the database, running code, and generating HTML. Instead, it can simply serve the pre-built HTML file, which results in faster loading speeds.

Furthermore, static website generators also have fewer security vulnerabilities as they don’t rely on a database or server-side code, which can be exploited by malicious actors. Also, because there is no need for the server to perform any dynamic processing, the server’s resources can be used more efficiently, leading to faster loading speeds.

In summary, using a static website generator like Hugo can result in faster loading speeds compared to dynamic website builders like WordPress because it generates a fixed version of the website, which is served to the user. Unlike dynamic website builders, static website generators don’t need to go through the process of querying the database, running code, and generating HTML, and have fewer security vulnerabilities.

Optimizing JavaScript

Optimizing JavaScript is an important aspect of website performance and can greatly improve the load time of a webpage. Here are some tips to optimize JavaScript on your website:

  • Minify your JavaScript code. This means removing any unnecessary whitespace and comments, which can greatly reduce the file size of your JavaScript files.
  • Use a Content Delivery Network (CDN) to serve your JavaScript files. CDNs are networks of servers that are distributed around the world, which can help reduce the load time of your JavaScript files by serving them from a location that is closer to your users.
  • Defer the loading of JavaScript files that are not critical to the initial rendering of your webpage. This means that the JavaScript files will only be loaded after the initial content of the webpage has been rendered, which can help reduce the load time of the webpage.
  • Use code splitting to break up your JavaScript code into smaller, more manageable chunks. This can help reduce the amount of JavaScript code that needs to be loaded and parsed by the browser, which can improve the load time of the webpage.
  • Use browser caching to store your JavaScript files in the user’s browser. This can help reduce the load time of your webpage by allowing the browser to load the JavaScript files from its cache, rather than having to request them from the server.
  • By following these tips, you can greatly improve the load time of your webpage by optimizing the JavaScript that is used on your website.

By following these tips, you can greatly improve the load time of your webpage by optimizing the JavaScript that is used on your website.

Optimising JavaScript with Hugo

Deferring JavaScript

Deferring JavaScript in a webpage means that the JavaScript files are loaded and executed after the initial content of the webpage has been rendered. This is in contrast to loading JavaScript synchronously, where the JavaScript files are loaded and executed before the initial content of the webpage is rendered.

When JavaScript is loaded synchronously, the browser has to wait for the JavaScript files to be loaded and executed before it can render the initial content of the webpage. This can lead to slower load times, as the browser has to wait for the JavaScript files to be loaded and executed before it can display the initial content of the webpage to the user.

By deferring the loading of JavaScript files, the browser can begin to render the initial content of the webpage while the JavaScript files are being loaded in the background. This can result in faster load times, as the initial content of the webpage is displayed to the user sooner.

To defer JavaScript, you can use the “defer” attribute on the script tag in your HTML. This tells the browser to execute the script after the initial rendering of the page. You can also use “async” attribute to load the scripts asynchronously, which means it will download the script file while parsing the HTML and execute the script when it is available.

Deferring JavaScript is a good practice to improve the loading speed of your webpage, and it can be a powerful way to improve the user experience. However, it’s important to consider the order of the script execution and how they may affect the website.

I haven’t deferred JavaScript in this website, but I have opted for a better solution, which is tree shaking.

Tree Shaking

JavaScript tree shaking is a technique used to remove unused code from a JavaScript application. It is typically used in the context of modern JavaScript development, where applications are built using a combination of third-party libraries and modules written by the developer.

The idea behind tree shaking is that, during the build process, the tooling can analyze the code and determine which parts of the code are actually being used and which parts are not. Unused code is then removed from the final bundle, resulting in a smaller, more efficient codebase. This process is called “dead code elimination”.

Tree shaking is typically used in conjunction with a module bundler, such as Webpack, Rollup, or Parcel. These tools can analyze the dependencies between modules and determine which modules are actually being used. Unused modules can then be eliminated from the final bundle.

The benefits of tree shaking are improved performance, faster load times, and reduced file size of the final bundle. With tree shaking, you can remove unnecessary code and dependencies that would otherwise slow down your application and bloat the final bundle size.

It’s important to note that tree shaking requires strict adherence to the ECMAScript module syntax, otherwise, the tools won’t be able to determine which code is being used and which is not. Additionally, tree shaking can’t remove the code that is dynamically imported or that is used in a way that can’t be statically analyzed.

ESBuild is a JavaScript bundler and minifier that is designed to be extremely fast. It is an alternative to popular bundlers like Webpack and Parcel.

ESBuild is written in Go, which makes it a lot faster than other bundlers written in JavaScript. It uses a technique called “whole-program analysis” to analyze all the code in the application at once, which allows it to make more accurate and efficient decisions about which code to include in the final bundle.

ESBuild supports features like tree shaking, code splitting, and minification, which are commonly used to reduce the size of the final bundle and improve the performance of the application. It also support JSX, TSX and other languages that transpile to JavaScript.

One of the major advantages of ESBuild is its speed, it can process large and complex codebases in a fraction of the time it takes other bundlers to do the same job. This can be a significant advantage for developers working on large applications or for those who need to rebuild their application frequently.

ESBuild is a relatively new tool and it’s still in the early stages of development, but it has already gained a lot of traction and is being used in production by some companies. It can be used as a command-line tool or as a library that can be integrated into existing build pipelines.

This implement this with Hugo we first need to make sure we have the following libraries installed:

npm install boostrap

We need to create a new folder assets and include a subfolder js with two files assets.js and vendor.js:

folders structure

We will now import the Bootstrap JavaScript files in vendor.js selectively, rather than loading all of them from the CDN:

import {
  // Alert,
  Button,
  // Carousel,
  Collapse,
  // Dropdown,
  // Modal,
  // Offcanvas,
  // Popover,
  // ScrollSpy,
  // Tab,
  // Toast,
  // Tooltip
} from 'bootstrap';

The trick here is that we can selectively import just what we need from Bootstrap, for example just Button and Collapse.

Now we need to load vendor.js in footer-script.js (which is loaded in baseof.html right before </body>).

{{ partial "esbuild" "js/vendor.js" . }}

This is esbuild.html:

{{- $opts := dict "minify" true "target" "es2015" -}}
{{- if eq hugo.Environment "development" -}}
{{- $opts = dict "sourceMap" "inline" "target" "es2015" -}}
{{- end -}}
{{- $built := resources.Get . | js.Build $opts | fingerprint -}}
<script type="text/javascript" src="{{ $built.RelPermalink }}" integrity="{{ $built.Data.Integrity}}" defer></script>
Here we are choosing to minify only when we are not running in development mode, which is useful for debugging. You can find more information in Hugo pipes js. We are outputting JavaScript in es2015. ECMAScript 2015 (also known as ES6 or ECMAScript 6) is the sixth major version of the ECMAScript language, which is the standard that JavaScript is based on. It was released in June 2015, and it brought a number of new features and improvements to the JavaScript language. ECMAScript standards are updated annually, and since ES2015, the versioning is done by year. The latest version is ES2022 (ES11).

You can check how JavaScript is rendered in development or in production mode by inspecting the code with the browser.

We also implementing fingerprinting. Fingerprinting in JavaScript can be used to improve security and protect against hacking and data integrity issues in several ways. It can be used to ensure the integrity of the data being transmitted between the browser and the server. By including a fingerprint of the data in the transmission and then comparing the fingerprint of the received data with the original fingerprint, it’s possible to detect any tampering or modification that may have occurred during transmission. It’s worth to mention that Fingerprinting is not a panacea, as it can be evaded by sophisticated attackers and it’s not a substitute for other security measures such as encryption and secure communication protocols. Additionally, as mentioned before, it raises privacy concerns and it’s important to be transparent and respect users’ privacy rights.

We can now use the same method to load other JavaScript files from script-footer.html. The following is an example of selectively loading a JavaScript file only when we are in the Contact page:

{{ if eq .Type "contact" }}
  {{ partial "esbuild" "js/contact.js" . }}
{{ end }}

I’ve loaded JavaScript selectively when plotting a graph using Plotly as described in this article. Here the JavaScript files are loaded is certain parameters are set in the markdown file of a specific page:

{{ if in .Params.loadjs "citation-plot"}}
  <script src="https://cdn.plot.ly/plotly-2.16.1.min.js"></script>
  {{ partial "esbuild" "js/citation-plot.js" . }}
{{end}}