← back to the blog

Setting Up Your New Blog in Keystone.js - Part III

Posted on May 3rd, 2016 in browser, frontend, performance, tuning, above-the-fold, tutorial

In the previous post I showed how to set up Ansible and Jenkins. Now that everything is finished and automated I will focus on the front-end code and I will show how to achieve a better performance on the landing page.

One problem that people might encounter that even after following the guidelines on how to make their landing page well structured (external CSS links in the header, external JS links in the footer, CDN hosted images) their page load time is still too slow. It turns out that the run-to-completion nature of Javascript can still cause a problem in page loading even if the page is well structured. This becomes clearly visible when you run a test on pingdom and you take a look at how much part of the time the CSS loading takes.

Above the Fold

To understand what's happening here, you have to take a look at the steps the browser takes to load HTML content. Let's say that you want to render the following HTML snippet:

<!DOCTYPE html>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Blog</title>
    <link  href="/images/favicon/favicon.ico" rel="shortcut icon" type="image/x-icon">
    <link href="/styles/styles.css" rel="stylesheet">
    <div id="body">
        Welcome to my page!
    <script src="/js/site/video.js"></script>
    <script src="/js/site/index.js"></script>
    <script src="/js/site/googlemap.js"></script>

This will cause the browser to take the following steps:

  1. Send an HTTP get request to the server
  2. If the content is HTML than start parsing and tokenizing it
  3. Parsing reaches <link href="/images/favicon/favicon.ico"> and starts downloading it
  4. Parsing reaches <link href="/styles/styles.css"> and starts downloading it
  5. Parsing applies styles.css
  6. ...
  7. Parsing reaches <script src="/js/site/video.js"> so it starts downloading and executing it
  8. Parsing reaches <script src="/js/site/index.js"> so it starts downloading and executing it
  9. Parsing reaches <script src="/js/site/googlemap.js"> so it starts downloading and executing it
  10. By taking the previously parsed tokens one by one, the browser is creating a DOM tree which reflects the HTML tags in the source file and creates new DOM elements on the fly as necessary

This can be summarized with the following image: Parsing mode overview

As you can see these are just simple sequential steps running synchronously one after each other. Because of the greedy nature of the browser, the browser applies the cascading style immediately after downloading. This is bad for the user experience since the user can't interact with the DOM tree until the parsing is completely done and the DOM tree is ready. And this means that the more styles you apply, the longer the browser hangs. Even PageSpeed Insights keeps complaining about it: 'None of the above-the-fold content on your page could be rendered without waiting for the following resources to load. Try to defer or asynchronously load blocking resources, or inline the critical portions of those resources directly in the HTML.'

So you have to apply all the style rules in the stylesheet to make the whole page look good. But to make it fast you must not apply those rules: which sounds like a contradiction. Luckily there is a solution for this, which might resolve this contradiction, and the key to the problem is the word "whole". When you open a page in your browser you can't see the whole page from top to bottom. You only see a narrow lane of it on the top. Hence the idea: instead of eagerly loading all the applying CSS rules, let's cherry-pick those which you will need on page load. First you have to find the critical part of your page:

  1. Create a new folder find-critical-css on your local machine and navigate into it
    mkdir find-critical-css
    cd find-critical-css
  2. Create a new package.json by running npm init and answering all the questions
  3. Edit package.json and add the following:
    "name": "find-critical-css",
    "version": "1.0.0",
    "description": "Find critical CSS",
    "main": "find-critical-css.js"
    Note that there is a main property which is referring to a javascript file
  4. Create a new file find-critical-css.js and add the following content:
    var request = require('request');
    var path = require( 'path' );
    var criticalcss = require('criticalcss');
    var fs = require('fs');
    var tmpDir = require('os').tmpdir();
    var cssUrl = 'https://#{your-domain-name-here}/styles/style.css';
    var cssPath = path.join( tmpDir, 'style.css' );
    request(cssUrl).pipe(fs.createWriteStream(cssPath)).on('close', function() {
    criticalcss.getRules(cssPath, function(err, output) {
     if (err) {
       throw new Error(err);
     } else {
       criticalcss.findCritical("http://#{your-domain-name-here}/", { rules: JSON.parse(output) }, function(err, output) {
         if (err) {
           throw new Error(err);
         } else {
           fs.writeFileSync("#{your-output-path-here}/output.css", output);
  5. Execute find-critical-css.js
    node find-critical-css.js

After running these steps you will have the output.css file containing above the fold elements' CSS rules collected. To make these and only these rules applied, now you have to split the CSS rules into two groups: critical and non-critical. This might be cumbersome since earlier nothing really required to hold these rules grouped together, so quite possibly it will take quite some time to separate those rules. But still, it's worth the time since applying this simple trick will make the page loaded 2-3 times faster.

  1. Navigate to your local Keystone application folder
  2. Navigate to public/styles and create a new file critical.scss
  3. Navigate to public/styles and create a new file non-critical.scss
  4. Open critical.scss and copy the previously identified critical parts of site.scss into critical.scss
  5. Open non-critical.scss and copy the previously identified non-critical parts of site.scss into non-critical.scss
  6. Navigate to templates/layouts and open default.jade
  7. Modify default.jade and replace:

    link(href="/styles/site.css", rel="stylesheet")


    link(href="/styles/critical.css", rel="stylesheet")
  8. Scroll to the end of default.jade and add the following before the block js section:

     * Modified for brevity from
     * loadCSS: load a CSS file asynchronously.
     * [c]2014 @scottjehl, Filament Group, Inc.
     * Licensed MIT
     function loadCSS(href){
         var ss = window.document.createElement('link'),
         ref = window.document.getElementsByTagName('head')[0];
         ss.rel = 'stylesheet';
         ss.href = href;
         // temporarily, set media to something non-matching to ensure it'll
         // fetch without blocking render = 'only x';
         ref.parentNode.insertBefore(ss, ref);
         setTimeout( function(){
             // set media back to `all` so that the stylesheet applies once it loads
    = 'all';
     // We load non-critical part asynchronously
    //- In case the user agent doesn't use javascript we load the stylesheet synchronously
     #[link(href="/styles/non-critical.css", rel="stylesheet")]

    That's it. From now on, every time when your landing page loads, the browser will eagerly and synchronously load the critical CSS rules and apply them, while it will hold on loading non-critical CSS rules until it is reaching the bottom of the page and then it loads those rules asynchronously.

Caching in Keystone.js

One more thing which will greatly improve the site's page load is caching. While the first page load takes time proportional to the amount of downloaded data, the subsequent page loads must not take that much time when the static content is the same with the previous request.

Since Keystone.js is just a fancy Express.js application, and Express.js has it's own caching mechanism called the 'serve-static middleware', you just have to configure and instruct Keystone to cache the public static assets.

  1. Navigate to the local Keystone application project
  2. Open keystone.js and add the following content:
     'static': [
     'static options': {
         'maxAge': '7d'
     'favicon': 'public/favicon.ico',
     'views': 'templates/views'
    This will basically instruct Keystone to cache all the static assets in the public folder for 7 days if there were no changes.