Most of the articles about reducing javascript bundle size, generated by webpack, show how to reduce plain text size: removing big and duplicated dependencies, adding tree-shaking, splitting chunks, async loading of javascript, etc. But there is another, even more important step: compression of your javascript files.

In development (i.e. with webpack-dev-server) you usually serve plain javascript, but on production your server checks Accept-Encoding HTTP-header and decides what to do. In most cases this header contains at least gzip, deflate value. Translating to human language, browser says: "Hey, I have a question for you and I can understand, if you respond in gzip format!". So at this step your server generates gzip version of you javascript file and responds with it. Also it saves this .gz file to some cache instead of compressing it each time.

But there is another option. Let’s help our server: we can prepare this compressed .gz file on build step and upload it to the server. In this case your server will see, that there are two files: you-bundle.js and your-bundle.js.gz , so it will just use this .gz file for the answer.

Let’s use react-redux-universal-hot-example to show, what we can do. It is javascript application with webpack and several dependencies. If you run npm run build you will find production bundle in static/dist folder. Size of this bundle is 700K:

Generation of gzip using webpack could be achieved using compression-plugin. We don’t need to compress our assets in development, so let’s add this plugin to our production config:

Now after running npm run build we will find .gz version for each javascript, css and svg file. Size of gzip bundle is 204K:

Not bad, but don’t forget that in most cases we have this file generated by server. Why did we start it if we had the same result before? Let’s do it better.

Zopfli

Generating of gzip is usually done by zlib. In most cases you get pretty good compression and spend not a lot of time calculating it. But you can spend a bit more time with zopfli to have better result! It is compression algorithm by Google, that generates more efficient, backward-compatible gzip. So, all browsers support it out of the box. Let’s try it! Furthermore, zopfli is supported by compression-webpack-plugin, so we just change algorithm option:

And after running npm run build size of gz bundle is 196K:

We’ve got 4% improvement for free! Google says that the output generated by zopfli is typically 3–8% smaller compared to zlib.

Brotli

Have you noticed that that article about zopfli was published in 2013? But it is already 2017 and google engineers had at least 4 years to make the web better. And they did it!

We can use brotli as a compression algorithm. It is similar in speed with deflate but offers more dense compression. Since it is new format (not gzip) some old browsers doesn’t support it:

Caniuse brotli?

In terms of browser ⇄ server conversation it works the same way, as gzip: browser adds br to Accept-Encoding header and server can answer with content of .br file.

Similarly to gzip compression, we just add the plugin to our production config:

And after npm run build we see:

Brotli is just 160K, that is 16% more efficient than zopfli!

Few notes

First of all, you can do the same without webpack, I’ve used it just as example, because it is most popular way to build JS now.

As you can see we reduced size of our bundle by 77% using this advanced compression. It sounds amazing, but it is not always possible to just add brotli to your application, because:

Brotli is HTTPS only. Find the reason in the end of this chromium issue;

Your server should support brotli. For example, nginx should include brotli plugin;

If you use any CDN — again, it should support brotli.

Now you know how to improve speed of your application in one simple step. Let’s do the web better 💪