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 web pack and several dependencies. If you run npm run build
you will find production-ready bundle, and size of this bundle is 700K:
https://gist.github.com/885ab3c1c585f5468fcd8e1376b12cdf
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:
https://gist.github.com/e8216b256cbdc416f1625f45750e9021
Now after running npm run build
we will find .gz
version for each javascript, css and svg file. Size of gzip bundle is 204K:
https://gist.github.com/6804d0956fbb640f4f53537a7b8db6a2
Not bad, but don't forget that in most cases we have this file, but it is generated by server. So, why did we start it if we had the same result before? A lot of developers stop at this point, but we won't.
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:
https://gist.github.com/b2697b5854921c6740b7682c0f0af64b
And after running npm run build
size of gz
bundle is 196K:
https://gist.github.com/719038fe98725c9fd71147c33449986c
We've got 4% improvement for free! Google says that the output generated by zopfli is typically 3–8% smaller compared to zlib.
https://media.giphy.com/media/D3OdaKTGlpTBC/giphy.gif
[image:43FBBEBB-07CB-46BD-9A50-74654016B3ED-93647-0001646EF62CED96/google-brotli-algorithm-2016-01-20-01.jpg]
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! And now we can use brotli as a compression algorithm. It is similar in speed with deflate but offers more dense compression. Since it is not gzip, some old browsers doesn't support it:
[image:8490438C-D7A3-46F3-BB04-1FC104E4608D-93647-00015C4CE3B3B530/Screen Shot 2017-06-14 at 15.19.31.png]
In terms of browser ⇄ server conversation it works the same way, as gzip: browser adds br
to Accept-Encoding
and server can answer with content of .br
file.
Similarly to gzip compression, we just add this plugin to our production config:
https://gist.github.com/e466cc473bf14e4d2795f90da373051d
And after npm run build
we see:
https://gist.github.com/fc17ebb85a857bf0351dfeab2808bdf6
Brotli is just 160K, that is 16% more efficient than zopfli!
First of all, you can do the same without webpack, I've used it just as example, because now it is most popular way to build JS.
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 💪