Lazy Loading

As with the CityLab redesign, we switched over to using a JavaScript dependency manager. While Webpack is the most popular, we decided to use JSPM and SystemJS. This allows us to write modern JavaScript, transpile it with Babel and use SystemJS client-side to load our modules on-demand. Being able to load our less critical JavaScript packages lets us reduce the file size of our initial payload as well as reduce the parse and execution time.

We use the compatibility layer between Jinja and Nunjucks to write universal components. JSPM also allowed us to bundle all our component assets together. The lazysizes include plugin allowed us to lazy load the components when scrolled into view. For components that are important to the page but still out of view like the author bio or footer, we kept the HTML on the page but lazy loaded the CSS.

Preloading

Preloading critical assets was important in our redesign. We took advantage of the new browser spec to make sure we start loading our fonts as soon as possible. When it came to preloading other assets like our JavaScript packages, we first tested what the performance implications were and if there was a benefit. Originally, we preloaded our ad code. However, synthetic tests showed that this delayed our Time to First Ad however.

Service Worker

One of our technical goals was to launch the redesign as a PWA. One of the requirements for a PWA is a Service Worker. Since this would be our first Service Worker going to production, we were cautious about our caching strategy. Things that made sense for us to cache were our fonts and JavaScript libraries that would not change. We also cache assets that do change. Our Django CMS will add a cache busting key to all our static assets, this allows us to constantly prune and update the cache when our core JavaScript is updated.

Since we’re registering the Service Worker late on the first page load, the benefits don’t kick in until the third page view. Note the order of operations:

Register the Service Worker on the first page view. During the second page view, the registered Service Worker intercepts the network requests and caches the assets. Finally, on the third page view, the Service Worker responds with the cached assets.

Our dedicated readers get a lightning fast site. If you don’t read more than one article on The Atlantic, you should!

Polyfilling

Instead of adding a bunch of code to support old browsers — mainly IE11 — we added a new file to our pipeline called polyfill.js . This file contains all the polyfill’s needed for IE. Inspired by this post by Philip Walton, we used the nomodule attribute for script tags. According to Can I Use, support is pretty good. Old browsers get a synchronous download but maintain support and modern browsers simply skip the declaration. Win, win.

Minify Everything

As a part of our build process, we are able to minify our HTML templates too. Minifying our HTML as well as our inlined CSS helped us keep our page weight down.

With every new feature that was built out for the redesign, we were able to build in the ability to disable the feature individually using a query string. This allowed us to validate our assumptions. Want to confirm that inlining the CSS was faster? Just run a test with Critical CSS enabled and disabled and compare.

Numbers

These are a sampling from a random article on The Atlantic. The tests were run on Webpage Test with the following configuration:

The Moto G4 is a middle of the road device which would better replicate JavaScript parse and execution times for our users. Most of our user base is in the United States and have access to at least a fast 3G connection. If our users consisted of a more wide demographic, that would dictate a different connection. The default number of runs for WPT is 3. For us, 3 felt too low and 9 was too much. Running between 5–7 tests got us the results we were looking for. We didn’t do too much with the repeat view information but it’s good to have if you need it. It was important for us to always capture the video when testing different features, because it was often used to demonstrate how drastic of an improvement we were making with each new feature or how the redesign compared to our old site.

Take everything I write with a grain of salt. You can run these tests a thousand different ways and get a thousand different results. Our load times can vary wildly depending on what ads are targeted that day or when third party packages are loaded. Generally, we’ve seen significant improvements in every metric we measure.