First there was PJAX

On February 26, 2011, Chris Wanstrath, the co-founder of Github made an initial commit to jquery-pjax, — “A jQuery plugin that uses AJAX and pushState to deliver a fast browsing experience with real permalinks, page titles, and a working back button.“

The idea is that whenever a user clicks a link, the plugin takes control, fetches all the required assets, and updates the page with the new resources. It's like using patch and diff on the web.

This was the first serious attempt to turn a website to a single-page application. Unfortunately, this project was eventually abandoned.

Seven months later, On September 26, 2012, the developers of Basecamp released Turbolinks to get “The performance benefits of a single-page application without the added complexity of a client-side JavaScript framework.“

It ditched jQuery, integrated to Ruby On Rails, and is actively maintained. Slowly it's active usage surpassed PJAX.

The SPA takeover

In the past six years, the rise of single-page applications has been incredible, but only with “real” desktop-like applications. The original idea of pjax, to turn your content-heavy website to a single-page app, became a thing only for a hobbyist.

This article brings this extremely powerful technique back to the forefront and introduces some new tricks to make page loading even faster.

This website is a live demonstration of this power. Please click any of the links to get a sense of the speed — even when the pages are loaded directly from a $5.00 server in Falkenstein (a 3,388 people village in Bavaria, Germany) and without using a content delivery network.

Google trends for PJAX (blue), Turbolinks (red), and React.js (yellow)

View on trends.google.com

Taking things further

The basic idea in PJAX and Turbolinks is to load assets with XMLHttpRequest and change the URL with history.pushState . Put the library in place, and you should get fast page loads out of the box. However, you can take things further.

CSS speed bump

When we switch pages we load all the required stylesheets on the background and insert them on the page. We saw a big speed increase on speed when taking advantage of the disabled property of a link tag. Instead of removing the undeeded stylesheets, we set them disabled instead. Coupled with aggressive caching all the successive page switches now take less than 10 milliseconds to execute. This is so quick that it feels almost wrong: the web is not supposed to be this fast.

Mousoever prefetching

Whenever a visitor hovers a link on a desktop browser we fetch the corresponding page into memory so when the click event happens we already have the page available. This shaves off a few more milliseconds.

Dynamic components

The bulk content of this website is statically served by Nginx. However, this website is far from static. You can, for example, post comments, suggest new features, join mailing lists and try the product demo. These dynamic components are handled by a cluster of Node servers behind Nginx.

Custom page lifecycle

All the components listen to a set of custom events when a page is initialized. They are fired in the following order:

SPA lifecycle events on page load

route — when the URL changes and the page HTML is rendered metadata — when page metadata via “front matter” is available data — when backend data is loaded and before the components are mounted load — when all the assets are loaded and components are mounted unload — when the page is unloaded and the components are unmounted

Progressive enhancement

The 30K of JavaScript is completely optional. Turn off JavaScript and you see the content-only version, turn it back and you'll get the full experience with all the dynamic components. By implementing the page in this way the added SPA functionality won't break the page if the client does not support JavaScript.

Breakdown of the various assets on this page

We know it's a bit weird that fonts make the biggest impact on page load, but we try to optimize our site for maximum readability. The dynamic parts and search engine optimization comes second.

Was it worth it?

This was not a small job, but was it worth the effort? Should we take this even further? Maybe start using CDN or leave out all the custom fonts?

We built Volument to answer these tricky questions. We wanted to know if our work does more good than harm. For every tweak we do, we want to see in detail how it impacted the user experience and conversions.

Volument blog

We write about analytics, minimalism, and development.

View all blog entries