vite.js to precompress your .js and .css bundles in brotli and gzip format

Vite.js bills itself as a “Next Generation Frontend Tooling”, in simpler words this is something to replace your webpack bundler with (for your next project) as most modern browsers suppport ESM which make bundling easier and faster. I’ve started using it for some of my projects and could not find an example for brotli and gzip compression quickly enough online hence this post that shows how to do it.

Please note that if you use Content Delivery Network (CDN) like Amazon Cloudfront or Cloudflare or others, this functionality is already provided (you have to enable it for your distribution). So you don’t technically have to handle this as part of your vite.js build. However, for several reasons it may make more sense to actually precompress assets as part of your build:

  • this leaves you with a greater degree of mobility if you would need to switch CDNs
  • per Cloudfront docs -> sometimes CloudFront might not compress your files even if configured to do so. I dont want to find out what rare means in cloudfront

(In rare cases, CloudFront might skip compression and send the uncompressed object to the viewer.)

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.htmlhttps://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html

Down to the code, everything is self-explanatory.

Vite.js is abased on rollup and thus you can simply use rollup plugins in the vite.config.js file. Simply import rollup-plugin-brotli, zlib, and rollup-plugin-gzip and configure these plugins (or not) and you are all set. We are importing zlib only to configure brotli plugin.

Note that after you have your statics compressed your webserver has to be configured to support that, here is an example for nginx:

Code to configure vite.js to precompress your .js and .css bundles in brotli and gzip format

import { defineConfig } from 'vite'
import * as path from 'path'
import brotli from "rollup-plugin-brotli";
import zlib from "zlib";
import gzipPlugin from 'rollup-plugin-gzip';

// vite.config.js
export default defineConfig({
  plugins: [
      //Brotli plugin with some defaults.
      brotli({
        test: /\.(js|css|html|txt|xml|json|svg)$/, // file extensions to compress (default is shown)
        options: {
            params: {
                [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_GENERIC,
                [zlib.constants.BROTLI_PARAM_QUALITY]: 7 // turn down the quality, resulting in a faster compression (default is 11)
            }
            // ... see all options https://nodejs.org/api/zlib.html#zlib_class_brotlioptions
        },
      
        // Ignore files smaller than this.
        //1000 is what cloudfront does: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html
        minSize: 1000
      }),

      //Gzip plugin with some defaults.
      gzipPlugin({
        gzipOptions: {
          //Gzip compression level 
          level: 9,

          //Dont compress files that are too small as it can just make them larger
          minSize: 1000
        }
      })
  ],
  root: path.join(__dirname, "src"),
  base: '/',

  //Purely per official docs:
  //https://getbootstrap.com/docs/5.2/getting-started/vite/
  resolve: {
    alias: {
      '~bootstrap': path.resolve(__dirname, 'node_modules/bootstrap'),
      '~node_modules': path.resolve(__dirname, 'node_modules'),
    }
  },
  build: {
    emptyOutDir: true,

    // generate manifest.json in outDir -> we need this in all envs
    manifest: true,

    rollupOptions: {
      input: {
        //JS bundles
        'default':           '/js/bundles/default.mjs',
        'contact':           '/js/bundles/contact.mjs',

        //SCSS bundles
        'style-default':    '/scss/default.scss',
        'style-contact':     '/scss/contact.scss',
      },
    },
  
    sourcemap: true,
  },
})

This is it, thanks for reading.

Leave a Comment