NuxtJS Static Assets Compression with nuxt-compress

Leonardo Vinsen
4 min readDec 19, 2020

--

If you’ve ever ran a Google Lighthouse audit on your static website built with NuxtJS and saw the “Enable text compression” suggestion, then you’ve come to the right place.

In theory, you can significantly reduce your js, css, and html files by compressing them into gzip or brotli format. Thankfully there’s a package that abstracts this task called nuxt-compress available on Github.

However, compressing your assets during the build process is only the first step; you also have to configure your web server to serve compressed assets instead of your uncompressed assets. In addition, .html files are not automatically compressed by nuxt-compress (more on this later).

Let’s start!

Installation

  1. Install the module
npm install nuxt-compressORyarn add nuxt-compress

2. Add nuxt-compress to your buildModules

module.exports = {
buildModules: ["nuxt-compress"]
};

If you’re using Nuxt < 2.9, you’ll need to add it to your modules instead.

module.exports = {
modules: ["nuxt-compress"]
};

3. Run your build script (e.g. npm run generate) and your files will be automatically compressed.

Check your built .js files (mine is in dist/_nuxt) and you should see files ending in .gz and .br

Compressed js files

My .html files are not being compressed!

You should probably notice that .html files are untouched (read about the issue here). In the meantime, as a workaround run these two commands after the files are built.

// run gzip compression
find <build_folder> -type f -iname *.html -exec gzip -k {} ';'
// run brotli compression
find <build_folder> -type f -iname *.html -exec brotli {} ';'

Or as a package.json script:

"scripts": {    "postbuild": "find <build_folder> -type f -iname *.html -exec gzip -k {} ';' ; find <build_folder> -type f -iname *.html -exec brotli --best {} ';'"}.//Please note the ; in between commands for gzip and brotli

Explanation:

  • find <build_folder> -type f -iname *.html searches for all .html files in your build folder (replace <build_folder> with the path to your build folder.
  • -exec performs the command you specify after it
  • {} is the file(s) that satisfies the find query.
  • gzip -k {} ';' runs gzip compression on the file(s). -k flag tells gzip not to delete the original file. Single quotes ';' are added to the delimiter because sometimes the terminal may not recognize that it’s a delimiter.
  • Similarly, brotli {} ';' runs brotli compression on the file(s). However, by default original files are not deleted after being compressed.
  • Optionally you can add --best flag to use the best compression quality. See man pages for gzip and brotli to learn more.

You’ve now learnt how to compress your static assets, but there is still one last step — configuring your web server to serve the compressed files instead of the original files.

Configuring an Apache Web server

Disclaimer: the following code snippet is taken from a blogpost written by Laurent Desgrange.

Add these lines to .htaccess file on your web server root folder.

RewriteEngine on# Brotli
# If the web browser accept brotli encoding…
RewriteCond %{HTTP:Accept-encoding} br
# …and the web browser is fetching a probably pre-compressed file…
RewriteCond %{REQUEST_URI} .*\.(css|html|js)
# …and a matching pre-compressed file exists…
RewriteCond %{REQUEST_FILENAME}.br -s
# …then rewrite the request to deliver the brotli file
RewriteRule ^(.+) $1.br
# For each file format set the correct mime type (otherwise brotli mime type is returned) and prevent Apache for recompressing the files
RewriteRule "\.css\.br$" "-" [T=text/css,E=no-brotli,E=no-gzip]
RewriteRule "\.html\.br$" "-" [T=text/html,E=no-brotli,E=no-gzip]
RewriteRule "\.js\.br$" "-" [T=application/javascript,E=no-brotli,E=no-gzip]

# Gzip
# If the web browser accept gzip encoding…
RewriteCond %{HTTP:Accept-Encoding} gzip
# …and the web browser is fetching a probably pre-compressed file…
RewriteCond %{REQUEST_URI} .*\.(css|html|js)
# …and a matching pre-compressed file exists…
RewriteCond %{REQUEST_FILENAME}.gz -s
# …then rewrite the request to deliver the gzip file
RewriteRule ^(.+) $1.gz
# For each file format set the correct mime type (otherwise gzip mime type is returned) and prevent Apache for recompressing the files
RewriteRule "\.css\.gz$" "-" [T=text/css,E=no-brotli,E=no-gzip]
RewriteRule "\.html\.gz$" "-" [T=text/html,E=no-brotli,E=no-gzip]
RewriteRule "\.js\.gz$" "-" [T=application/javascript,E=no-brotli,E=no-gzip]
<FilesMatch "\.(css|html|js)\.br$">
# Prevent mime module to set brazilian language header (because the file ends with .br)
RemoveLanguage .br
# Set the correct encoding type
Header set Content-Encoding br
# Force proxies to cache brotli & non-brotli files separately
Header append Vary Accept-Encoding
</FilesMatch>
<FilesMatch "\.(css|html|js)\.gz$">
# Serve correct encoding type
Header set Content-Encoding gzip
# Force proxies to cache gzip & non-gzip files separately
Header append Vary Accept-Encoding
</FilesMatch>

Verify that your webserver is now serving compressed assets by looking at Response Headers of one of your js , css or html file, and checking if it contains the header Content-Encoding: br or Content-Encoding: gzip

Checking response headers for Content-Encoding: br; previously the file was ~300kB in size!

That’s all!

References

--

--