# Other optimizations

There are plenty of general optimizations that didn't fit the previous categories or improve multiple areas of the application.

# Avoid render-blocking resources 📙

Render-blocking resources are scripts, stylesheets, and other imports in the <head> that delay the browser from rendering page content to the screen until they are downloaded and parsed. Such resources delay the First Paint - time needed for the browser to render something (i.e., background colors, borders, text, or images) for the first time. To prevent that:

  • add the defer or async attribute to the <script>,
  • use disabled or media attributes for the stylesheets.

Nuxt is deferring every bundle script it generates. If you want to deffer third party scripts, just add them in the nuxt.config as shown in the example below:

// nuxt.config.js

export default {
  head: {
    script: [
      {
        src: `https://www.google-analytics.com/analytics.js`,
        defer: true
      }
    ]
  }
};

Additionally, you can use media-dependent (opens new window) import in your CSS if you have stylesheets for specific resolutions or device types. This way browser only loads stylesheets for that particular device, and you can make main stylesheets smaller.

/* main.scss */

@import '@/assets/print.scss' print;
@import '@/assets/landscape.scss' screen and (orientation:landscape);

# Inline critical CSS 📒

Consider delivering critical CSS inline and deferring all non-critical assets. You can reduce the size of your pages by only shipping the styles that the browser needs at the given time.

Move the styles required for the first paint to a <style> block in the <head> of the HTML page and load the rest of them asynchronously using the preload link.

# Use font placeholders while others are loading 📒

Leverage the font-display CSS feature to ensure that the text is visible to the user while web fonts are loading.

@font-face {
  font-family: 'Arial';
  font-display: swap;
}

The font-display API specifies how a font is displayed. The swap value tells the browser that the text using this font should be displayed immediately using a system font. Once the custom font is ready, it replaces the system font.

If you are using Google Fonts, add the &display=swap parameter to the end to the Google Fonts URL:

<link href="https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap" rel="stylesheet">

If you are using the @nuxtjs/google-fonts package, you can use the display (opens new window) property.

# Avoid using more than one library version 📒

Check if your website doesn't use multiple versions of the same library. This will make the user download unnecessary data and slow down your page. Clean up the code and make sure you only use one version by running the following command to generate a report of what's in the final bundle.

yarn nuxt build --analyze

You can also use the duplicate-package-checker-webpack-plugin (opens new window) library to warn you if it detects multiple versions of the same package:

export default {
  build: {
    plugins: [
      new webpack.DefinePlugin({
        'process.VERSION': JSON.stringify({
          DuplicatePackageCheckerPlugin: require('duplicate-package-checker-webpack-plugin'),
        })
      })
    ]
  }
} 

# Compress your files 📒

Ensure you compress HTML, JSON, JavaScript, CSS, and SVG. It will save bandwidth for you and the user and make the page load faster.

There are two ways you can do that:

# Don't close connection used multiple times 📘

By default, HTTP connections close after each request. When the user enters your website, the browser needs to create a new connection for every resource that makes up your web pages (JavaScript, CSS, images, etc.).

To prevent this, use the HTTP keep-alive header to maintain a connection between the user browser and your server, reducing the time needed to serve these assets. This will reduce the number of TCP and SSL/TLS connection requests, leading to a drop in round trip time (RTT).

  • The HTTP/1.0 clients request persistent connection by sending the Connection: keep-alive request header to the server.
  • In HTTP/1.1, all connections are considered persistent unless declared otherwise.
  • In HTTP/2 connection and Keep-Alive headers are not allowed. Chrome and Firefox ignore them, but Safari will not load the web page if the server returns these headers in error.
Example:
GET /echo HTTP/1.0
Host: vuestorefront.io
Connection: keep-alive
Keep-Alive: timeout=5, max=100

# Preconnect with external domains like your CDN or fonts provider 📒

If a critical resource needed to render a page is not on your domain, you can consider preconnecting to that domain. The browser will create the connections, so it's ready when the resource is needed.

Consider adding preconnect or dns-prefetch resource hints to establish early connections to important third-party origins. dns-prefetch works similarly to preconnect but has broader browser support.

<link rel="preconnect" href="https://example.com">
<link rel="dns-prefetch" href="https://example.com">

In many cases, "preconnect" can negatively impact the performance, so you should make an informed decision about whether to use it or not. Additionally, because browsers close connections not used in the last 10 seconds, you should avoid preconnecting to a domain not used immediately.

# Avoid multiple redirects 📘

Redirects introduce additional delays before the browser can load the page. If you can't avoid redirects, it's better to do them on the server side.

# Avoid large network payloads 📒

Remember that it costs users real money to download large network resources such as images, movies, JSON files, or API responses. For this reason, you should:

  • Defer requests until they're needed.
  • Don't fetch unnecessary data. Limit your responses to a minimum.
  • Optimize requests to be as small as possible, minimize and compress them.
  • Cache requests, so the page doesn't re-download the resources on repeat visits.