Speeding up static websites with PJAX
How to improve the performances and enhance the user's experience of static websites (Hugo, Jekyll..) using the PJAX technique.
With the fast-growing trend of static websites, many people are moving their blogs from WordPress, Medium, etc, to static websites built with Hugo or Jekyll. And there is a good reason for that. One of the reasons is security, cutting down server costs, ease of maintenance, performances, and many others. But in this article, I would like to focus on performances.
As everybody knows, static websites offer out-of-the-box very fast performances without any configuration. You have no database, no dynamically generated content, just serving HTML files from your hosting. As simple as that. But using the PJAX technique we can improve loading performances and enhance the user’s experience a lot!
What is PJAX and how it works?
PJAX technique is using PushState and AJAX. Basically, on a page request, we will manually update the URL and inject the new content on the page, thus avoiding reloading your page’s layout or any resources (JS, CSS), giving a fast page load.
Here are the steps of the process with Barba.js:
- Check if the link is valid and eligible for PJAX. If yes, prevent normal browser behavior.
- Change the URL using the push state API.
- Start fetching the new page via an XMLHttpRequest.
- Create a new transition instance.
- As soon the new page is loaded, barba.js parses the new HTML (taking .barba-container) and puts the new content on the DOM inside #barba-wrapper.
- The transition instance will take care of hiding the old container and showing the new one.
- As soon as the transition is finished, the old container is removed from the DOM.
How to implement PJAX on a website?
There are many PJAX libraries, like Barba.js, Senna.js, Turbolinks, Pjax, etc. Usually, they all offer extremely easy implementation, I prefer using Barba.js for simple websites and Senna.js for more complex ones as it has a better API. In this article, I will use Barba.js
The implementation consists of 2 parts: Setting up DOM markup Script initialization.
Setting up DOM markup
Barba.js needs to know how your website is set up, so it will need a few HTML attributes:
<body data-barba="wrapper">
<!-- put here content that will not change
between your pages, like <header> or <nav> -->
<main data-barba="container">
<!-- put here the content you wish to change
between your pages, like your main content <h1> or <p> -->
</main>
<!-- put here content that will not change
between your pages, like <footer> -->
</body>
The wrapper is the main Barba section that contains all your page structure and the Barba container. The container defines a section in which content is updated automatically when you navigate between your pages.
Script initialization
After setting up the DOM attributes we simply include Barba.js script in the head of the document and initialize the script:
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@barba/core" async onload="barba.init({})"></script>
That’s it.
Conclusion
This approach will give a SPA-like feeling of the website since there are much fewer server requests.