{"id":253419,"date":"2017-04-12T05:46:25","date_gmt":"2017-04-12T12:46:25","guid":{"rendered":"http:\/\/css-tricks.com\/?p=253419"},"modified":"2019-07-04T16:46:09","modified_gmt":"2019-07-04T23:46:09","slug":"brotli-static-compression","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/brotli-static-compression\/","title":{"rendered":"Brotli and Static Compression"},"content":{"rendered":"
Content compression can be as simple as flipping a switch, but there’s a lot to consider beyond that. We pretty well know what<\/em> we need to compress, but what about configuring compression? Or static versus dynamic compression? What about Brotli?<\/p>\n <\/p>\n By now, Brotli enjoys support in a good chunk of browsers in use. While it provides performance advantages in many situations, there are some ins and outs that can prove challenging. At its highest compression setting, Brotli provides superior compression ratios to gzip, but the compression speed at this setting is slow enough that the benefit is squandered when content is dynamically compressed. What you really want in cases such as these is static compression. If you’re unaware of the differences between static and dynamic compression, here’s a quick refresher: <\/p>\n The big issue with dynamic compression is that the server can’t reply to the pending content request until the compression is done. This is no big deal at default compression levels. If you’re cranking up the compression level to shrink assets as much as possible, though, it can hold up the show while the server waits for the compressor to finish. Even if you realize significantly lower file sizes, the delay of dynamic compression may end up being a performance liability.<\/p>\n The answer to this problem is, predictably, static compression, a concept which is no stranger to tech bloggers. In this short article, you’ll get to learn about setting up your site to statically compress files for optimal compression performance, and see real world results of this powerful technique.<\/p>\n How you use static compression depends on which web server you use. As this blogger points out<\/a>, Nginx has static compression capability for Brotli is built right in. If you use Express<\/a>, the shrink-ray node module<\/a> will provide this benefit through its own caching mechanism.<\/p>\n With other servers like Apache, however, it may not be so simple. Apache’s unofficial So what do you use to pre-compress assets? You could manually do it using a binary in bash, but automating that work with gulp is much more convenient. Let’s say you want to pre-compress all HTML, CSS, JavaScript and SVG images in a project and spit them out into a different folder:<\/p>\n The This will process all the assets matched by the file glob (specified in the So what’s the next piece? This is where a bit of Apache configuration knowledge comes in handy. This blogger’s technique<\/a> works magnificently:<\/p>\n You can also specify gzip-encoded versions for those browsers that can’t understand Brotli encoding:<\/p>\n From here, you need a couple With these rules, the browser will serve pre-compressed Brotli content to browsers that specify it in their As you might guess, taking the cost of on-the-fly compression out of the equation confers a performance benefit for the user. To test this out, I deployed this change to a client’s static site and ran some tests. This site was roughly ~900 KB in total size with a number of stylesheets and scripts (including a sizable CSS\/JS framework), some SVG images and some decently sized HTML. Using sitespeed.io<\/a>, I ran 50 iterations on each of four scenarios:<\/p>\n The effects on back end time were quite noticeable:<\/p>\n\n
How do I statically compress content?<\/h3>\n
mod_brotli<\/code> module<\/a> (and even its official
mod_deflate<\/code> module for gzip) doesn’t provide static compression functionality. You don’t necessarily need a server module to accomplish this goal, though. You can statically compress assets on the disk beforehand, and then configure the server to serve those pre-compressed assets from the disk using
mod_rewrite<\/code>.<\/p>\n
const brotliCompress = () => {\r\n let src = \"src\/**\/*.{html,js,css,svg}\",\r\n dest = \"dist\";\r\n\r\n return gulp.src(src)\r\n .pipe(brotli.compress({\r\n extension: \"br\",\r\n quality: 11\r\n }))\r\n .pipe(gulp.dest(dest));\r\n};\r\n\r\nexports.brotliCompress = brotliCompress;<\/code><\/pre>\n
brotliCompress<\/code> task is then invoked like this:<\/p>\n
gulp brotliCompress<\/code><\/pre>\n
src<\/code> variable) and output Brotli compressed versions to the destination directory (specified in the
dest<\/code> variable).
styles.css<\/code> will be compressed to
styles.css.br<\/code>,
scripts.js<\/code> will be
scripts.js.br<\/code> and et cetera. Best of all, the quality setting of 11 yields the best possible compression ratio. It’s also possible for you to generate pre-compressed gzip assets to serve to browsers that don’t support Brotli with gulp-gzip. Its syntax is largely similar to gulp-brotli, and you can use a level setting of 9 to max out your gains from that compression method as well.<\/p>\n
# Specify Brotli-encoded assets\r\n<Files *.js.br>\r\n AddType \"text\/javascript\" .br\r\n AddEncoding br .br\r\n<\/Files>\r\n<Files *.css.br>\r\n AddType \"text\/css\" .br\r\n AddEncoding br .br\r\n<\/Files>\r\n<Files *.svg.br>\r\n AddType \"image\/svg+xml\" .br\r\n AddEncoding br .br\r\n<\/Files>\r\n<Files *.html.br>\r\n AddType \"text\/html\" .br\r\n AddEncoding br .br\r\n<\/Files><\/code><\/pre>\n
# Specify gzip-encoded assets\r\n<Files *.js.gz>\r\n AddType \"text\/javascript\" .gz\r\n AddEncoding gz .gz\r\n<\/Files>\r\n<Files *.css.gz>\r\n AddType \"text\/css\" .gz\r\n AddEncoding gz .gz\r\n<\/Files>\r\n<Files *.svg.gz>\r\n AddType \"image\/svg+xml\" .gz\r\n AddEncoding gz .gz\r\n<\/Files>\r\n<Files *.html.gz>\r\n AddType \"text\/html\" .gz\r\n AddEncoding gz .gz\r\n<\/Files><\/code><\/pre>\n
mod_rewrite<\/code> rules to detect what encodings are available in the browser’s
Accept-Encoding<\/code> request header and then serve the appropriately encoded asset to the user:<\/p>\n
# Turn on mod_rewrite\r\nRewriteEngine On\r\n\r\n# Serve pre-compressed Brotli assets\r\nRewriteCond %{HTTP:Accept-Encoding} br\r\nRewriteCond %{REQUEST_FILENAME}.br -f\r\nRewriteRule ^(.*)$ $1.br [L]\r\n\r\n# Serve pre-compressed gzip assets\r\nRewriteCond %{HTTP:Accept-Encoding} gzip\r\nRewriteCond %{REQUEST_FILENAME}.gz -f\r\nRewriteRule ^(.*)$ $1.gz [L]<\/code><\/pre>\n
Accept-Encoding<\/code> request headers. Other browsers will get statically compressed gzip versions. That’s it. You just learned how to serve statically compressed assets to users in a browser that doesn’t support it.<\/p>\n
How does this affect performance?<\/h3>\n
\n
quality<\/code> setting of
11<\/code>.<\/li>\n
quality<\/code> setting).<\/li>\n
level<\/code> setting of
9<\/code>.<\/li>\n
level<\/code> setting).<\/li>\n<\/ol>\n