- 7 minutes read

A friend of mine claims a successful website must load in 400 milliseconds. What an ambitious claim! BeyondJava.net is not even close. In North America, it loads within two seconds.

The name of the Brotli compression algorithm has been inspired by the Swiss-German word for bread roll. Image published by Pixabay under a free Pexels license on https://www.pexels.com/de-de/foto/brot-lebensmittel-gesund-fruhstuck-2436/Truth to tell, the situation isn't that bad. My blog loads in less than a second in Europe. Most readers already have some of the files in their browser cache, so BeyondJava.net is even faster. My own browser even reports half a second when I activate caching. Not too bad for an Angular application. But still, I'm always looking for ways to speed up things.

One of the many secrets to unleashing performance is compression. Today, let's talk about Brotli and gzip. In particular, let's talk about activating Brotli on a cheap Apache httpd server.

What is Brotli?

Cutting a long story short, there are many compression algorithms. Gzip, Zopfli, and Brotli are popular on the web because these algorithms are fast. It seems to be so cheap to add gzip to the equation that the standard approach is to compress every file with gzip when it's delivered. I'm not even sure the average Apache server caches the compressed files.

Zopfli is a successor to gzip, and Brotli is even better. The Brotli implementation I've found offers eleven levels of compression. You can fine-tune it for maximum speed, for maximum compression, and for a compromise that suits your needs.

Oh, and I've learned that both Zopfli and Brotli are named after Swiss bread specialties. So I have to re-learn the pronunciation. I've grown accustomed to pronounce the algorithms like an American (well - as good as I can, I'm not a native speaker). Maybe I should try to pronounce the algorithms like a Swiss-German. I can't say I proficient at that, either. :)

How to activate gzip

If you're using a server like Nginx or the Express framework running on node.js, you're lucky. Activating Brotli is simply a matter of minutes. This article is for the rest of us. For what it's worth, I've bought a cheap web server using an Apache httpd server. It was easy to activate gzip. Too bad I didn't find out how to activate Brotli. So I had to go to some length to activate it.

Let's start with the easy stuff. Almost every httpd installation allows you to add gzip in the .htaccess file. Just in case you're not familiar with this file: it's a hidden file in the root folder of your server. You can use to do many things: adjusting the caching settings, enabling the favorite URL style of the Angular router, configuring your PHP engine, and even installing a simple firewall. In a nutshell, the .htaccess allows you to fine-tune the response of your server.

In most installations, activating gzip is simply a matter of adding two lines to the .htaccess file:

SetOutputFilter DEFLATE AddOutputFilterByType DEFLATE text/html text/plain text/xml application/json application/ld+json

The example activates gzip for a couple of file types: HTML pages, simple text files, and Json objects.

The downside of this approach is that the files are compressed on-the-fly. They are compressed each time a clients requests the data. That's a lot of wasted CPU time. However, the gzip algorithm is so efficient, almost nobody cares. In the age of an accelerating climate change, that's a shame. But I've tried: zipping the files in advance doesn't save a lot of time. More precisely, I believe delivering the page must have been faster, but I could hardly measure any difference. So I abandoned the pre-compression approach because it meant a lot of work to me.

Ahead-of-time compression is attractive with Brotli

Things are a little different using Brotli. I've already mentioned I didn't find out how to activate the on-the-fly-compression on my server. But even if I'd found out, compressing the files in advance is attractive. Compressing files on-the-fly has to be fast. So it's always a compromise between speed and file size.

Compressing the files at deployment time allows you to choose a more expensive level of compression. So I've opted for maximum compression. That results in a ten to twenty percent reduction compared to gzip, and roughly 70 percent compared to the original files. Of course, the precise numbers vary for each file. Most images even suffer from compression because they already are compressed. Compressing them a second time only adds some overhead, making the images even larger.

After doing all this, my website loads roughly 0.2 seconds faster. In other words, it's got a 10% performance boost. That's not that much, but on the other hand, adding Brotli to the equation is cheap, and every bit counts.

How to compress files in advance

I've just read that starting with node.js 11.7.0, node.js includes a Brotli compression algorithm natively. Chances are the algorithm I'm describing below can be simplified. I'll update the article when I've found out how to do it. Stay tuned!

I've written a little script compressing the files. You can easily integrate it with your build process. Just add the compression in an npm postbuild script like so:

"scripts": { "build": "ng build --prod", "postbuild": "node compress-with-brotli.js", }

The compression algorithm has two dependencies we need to install:

npm install brotli --save-dev npm install node-dir --save-dev

The compression algorithm itself is pretty straight-forward:

dir.files('dist', function(err, files) { if (err) throw err; files.forEach(f => compress(f)); }); function compress(file) { if (file.endsWith('.js') || file.endsWith('.css')) { const content = fs.readFileSync(file); if (content.length > 1000) { const result = brotli.compress(content, { mode: 0, // 0 = generic, 1 = text, 2 = font (WOFF2) quality: 11, // 0 - 11 lgwin: 22 // window size }); if (result != null && result.length < content.length) { fs.writeFileSync(file + '.br', result); } } } }

The idea is to scan the dist folder recursively, to compress every JavaScript and CSS file, and to store the compressed version of every file in the same folder, with the same name, plus the suffix .br.

Note that I didn't compress every file with Brotli. For some reason unknown, the library fails with tiny files. So I've added a threshold of 1000 characters. Sometimes Brotli even results in increasing file size, so I've added guard checking the resulting file size.

How to activate Brotli

We're almost there. The rest is some arcane .htaccess configuration. Well, it's just standard Apache httpd configuration. IMHO it's not exactly intuitive if you don't do it every day:

ExpiresActive On ExpiresByType text/css "access plus 1 month" ExpiresByType application/javascript "access plus 1 month" AddType "application/javascript" .br AddEncoding br .br AddType "text/css" .br AddEncoding br .br RewriteCond %{HTTP:Accept-Encoding} br RewriteCond %{REQUEST_FILENAME}.br -f RewriteRule ^(.*)$ $1.br [L]

Wrapping it up

If you're using a sufficiently modern and well-documented server like Nginx or the express framework running on node.js, you're well off. You can benefit from the advanced Brotli algorithm with just a few keystrokes.

However, the rest of us using a cheap and poorly documented web server can also benefit from Brotli. I've shown how to employ it with the Apache httpd server. All you need is the .htaccess file. You can store pre-compressed files on the server. That, in turn, is probably faster than compressing the files on-the-fly. You can opt for maximum compression - because the files are compressed once and for all - and on-the-fly compression also takes some time.

On my website, the pre-compressed Brotli files result in 10 percent improved performance. That's not much, but every bit counts. Plus, people using a decent smartphone with a slow 3G connection probably benefit even more.

Nonetheless, pre-compressing files with Brotli is something you should only consider after everything else. For example, https://tinypng.com/ is a marvellous tool to reduce the size of your images. Today, I've managed to speed up our corporate blog just by compressing a single image by 25%. That's a simple and fast option, so you should do that first!


Comments