Speed tweaking my website.

A few things I did to make my website faster.

Posted by Matthew Regis on Thu, Nov 17, 2016
In Development, Web
Tags go, golang, web, javascript, css, html, development, gulp, webpack, hugo

Overview

After publishing my website build with Hugo I thought I’d have a look at how the speed performance was. The results weren’t awful, I’ve seen alot worse but this was a static website and I wanted it to be fast. I knew ways of improving web performance so I decided to use that knowledge and try and make my site Go even faster.

Analysis

The main tool I used to perform analysis on my site was Google’s Pagespeed Insights and the chrome dev tools.

This is the results from using Chrome dev tools. I had disabled the cache and set the throtteling to Regular 2G.

Chrome dev tools speed test

Then I ran my site against Pagespeed insights. This is the mobile results.

Page insights speed test mobile

This is the desktop results.

Page insights speed test desktop

Analysis Summary

Like I said previously, not the worst I’ve seen but definetly room for improvemnt. From the chrome dev tools you can see which the main culprits are, each one of the background images which take longer to load. 24 requests, 2.9MB transfered, Finish 1.6min, DOMContentLoaded 6.94s | Load 1.6min.

From pagespeed insights on mobile I had a lower score because I had css links in the head section. This would impact loading the page as it would have to make the request for these resources before rendering the page.

Speed Tweaks

As the saying goes there are many ways to skin a cat as in web development there are many ways improve website performance, so I have tried to break it down into the type of speed tweak and then into more details about the tweaks.

Bundleing

This process is about taking all your seperate files and bundleing them into one file. The benifits of this is that there is only one file needed too transfer over the network. Let’s say you had 20 scripts, the browser is handling those scripts 6 at a time for most browsers which in turn can slow down the loading of your webpage.

Webpack

Webpack is more than just about bundleing but here I’ll just go over bundling.

To Install globally

npm install webpack -g

I set mine to local though by obmitting the -g. This will install the node modules locally to the path you ran the command.

npm install webpack

Then I created my config which should be normally named webpack.config.js. This is what mine looks like.

module.exports = {
    entry: ["./jquery.js", "./bootstrap.js", "./clean-blog.js"],
    output: {
        filename: "../static/js/bundle.js"
    }
};

In my example I had some javascript depending on other javascript. For example both bootstrap.js and clean-blog.js required jquery.js. So to do this I added something like a required statement at the top of the js that needed it. Be mindful of the path as it states what path it is in, ‘.’ denotes the current folder.

window.jQuery = window.$ = require('./jquery.min.js');

Then to run the bundle run the command “webpack” and watch the magic happen.

webpack

or in my case the command below because I didn’t set the NODE_PATH. Now I have a bundle.js in my /static/js/ folder.

node_modules/.bin/webpack

Lazy Loading / Defering

There are things you can do quite easily to help increase the rendering of your page

defer or async tags

These are easy to do and can help your site html to load faster. Async tells the browser to load this resouce asynchrony, that means rendering of the page won’t wait for the resouce to be fully loaded before continuing.

Defer is similar to async but if you have lots of resources using async they could all be loaded at diffrent times where you might want it to run in a certain sequence. This is were the Defer tag is usful. Here’s what I did for my site.

<script src="https://matthewregis.com/js/bundle.min.js" defer></script>

Lazy loading

Lazy loading is a design pattern that’s used in all types of software. It’s the process of defering an object or resource to when it’s actally needed. In my websites case, I use it to lazy load fonts and images.

On my homepage I have 3 background images, the one I care about the most is the first one because that’s the first one people will see, but for the other images it doesn’t matter because it’s out of view.

To do this I have this piece of javascript that I use for img tags and the top block of the code was created specifically to target my background images.

function init() {

    var imgBgDefer = document.getElementsByClassName('bg-img');
    for (var i = 0; i < imgBgDefer.length; i++) {
        if (imgBgDefer[i].getAttribute('data-src')) {
            imgBgDefer[i].style.backgroundImage = "url('" + imgBgDefer[i].getAttribute('data-src') + "')";
        }
    }

    var imgDefer = document.getElementsByTagName('img');
    for (var i = 0; i < imgDefer.length; i++) {
        if (imgDefer[i].getAttribute('data-src')) {
            imgDefer[i].setAttribute('src', imgDefer[i].getAttribute('data-src'));
        }
    }
}
window.onload = init;

And the markup I have to apply to the image is this.

    <img class="section-img" src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=" data-src="{{ .Site.BaseURL }}/img/what-i-can-do.gif"> </img>

In img src you can see a base64 image, this is quick and easy to use to preload and image. Then you have “data-src”. In the javascript you can see it looks for the img tag looks for the attribute “data-src” and if it exsits uses it to replace the “src” attribute.

And I do a similar thing to get fonts from google fonts. This script is in the head section, what it does is create the css links and adds it to the header section.

var loadCss = function() {
            var cssFont = document.createElement('link');
            cssFont.rel = 'stylesheet';
            cssFont.href = '//fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic';

            var cssFont1 = document.createElement('link');
            cssFont1.rel = 'stylesheet';
            cssFont1.href = '//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800';

            var head = document.getElementsByTagName('head')[0];
            head.parentNode.insertBefore(cssFont, head);
            head.parentNode.insertBefore(cssFont1, head);
        };

        //call function on window load
        window.addEventListener('load', loadCss);

Because the css and images are getting fetched via javascript, it doesn’t block the html from rendering, so you see the webpage faster.

Minifying

Minifying is the process of reducing all that whitespace in your files to reduce the size of your file. I have two files that I needed to minify my javascript and my css.

minify

Because my needs where simple I didn’t use webpack or gulp to minify my css and javascript instead I used a extention for Visual Studio Code (which is the code editor I use) called minify

All I had to do was have the file highlighted press F1 or fn+F1 on mac and type Minify and it produces a minified js file. In my case bundle.min.js and bundle.min.css

Gulp minify html

For removing whitespace in html I found this script for gulp. Hugo generates all the static files in the public folder. What this gulp script does is look in the public folder and minify html files.

gulpfile.babel.js

import gulp from 'gulp'
import htmlmin from 'gulp-htmlmin'
import runSequence from 'run-sequence'
import shell from 'gulp-shell'

gulp.task('hugo-build', shell.task(['hugo']))

gulp.task('minify-html', () => {
  return gulp.src('public/**/*.html')
    .pipe(htmlmin({
      collapseWhitespace: true,
      minifyCSS: true,
      minifyJS: true,
      removeComments: true,
      useShortDoctype: true,
    }))
    .pipe(gulp.dest('./public'))
})

gulp.task('build', ['hugo-build'], (callback) => {
  runSequence('minify-html', callback)
})

packages.json

{
  "private": true,
  "scripts": {
    "build": "gulp build"
  },
  "devDependencies": {
    "babel-preset-es2015": "^6.5.0",
    "babel-register": "^6.5.2",
    "gulp": "^3.9.1",
    "gulp-cli": "^1.2.1",
    "gulp-htmlmin": "^1.3.0",
    "gulp-shell": "^0.5.2",
    "run-sequence": "^1.1.5"
  },
  "babel": {
    "presets": [
      "es2015"
    ]
  }
}

Then run these commands and what you get at the end is a beautiful mess. Just take a look at my source code for this site.

npm install
npm run build

Image optimisation

This is an easy one that I should of done to all my images, but if you look in the chrome dev tools above in the tests you can see one image was 1.2MB (oops).

GIMP

For me I like to fine comb my images before I deem them ready for the web. Most of the time I want to alter the image in some way. The tool I use for this is GIMP. It’s a image editing software that does alot more than just compressing an image but won’t go too much detail in to that. The benifit of this tool is I use it to resize, crop, and compress most images and even add some effects if I want.

Gulp minify image

There are many ways to minify an image, have a look here for nodejs packages and see which one you might like the look of.

For me I used gulp-imagemin. Now buildling on from my gulp minify tasks I just added the releavent changes. So my packages.json now looks like the following notice the addition of “gulp-imagemin”.

{
    "private": true,
    "scripts": {
        "build": "gulp build"
    },
    "devDependencies": {
        "babel-preset-es2015": "^6.5.0",
        "babel-register": "^6.5.2",
        "gulp": "^3.9.1",
        "gulp-cli": "^1.2.1",
        "gulp-htmlmin": "^1.3.0",
        "gulp-shell": "^0.5.2",
        "gulp-imagemin": "^3.1.1",
        "run-sequence": "^1.1.5"
    },
    "babel": {
        "presets": [
            "es2015"
        ]
    }
}

And my gulpfile.babel.js looks like:

import gulp from 'gulp'
import htmlmin from 'gulp-htmlmin'
import runSequence from 'run-sequence'
import shell from 'gulp-shell'
import imagemin from 'gulp-imagemin';

gulp.task('hugo-build', shell.task(['hugo']))

gulp.task('minify-html', () => {
    return gulp.src('public/**/*.html')
        .pipe(htmlmin({
            collapseWhitespace: true,
            minifyCSS: true,
            minifyJS: true,
            removeComments: true,
            useShortDoctype: true,
        }))
        .pipe(gulp.dest('./public'))
})

gulp.task('img', () => {
    return gulp.src('public/img/*')
        .pipe(imagemin({
            progressive: true,
            svgoPlugins: [{ removeViewBox: false }],
        }))
        .pipe(gulp.dest('public/img'));
})


gulp.task('build', ['hugo-build', 'img'], (callback) => {
    runSequence('minify-html', callback)
})

And all i need to do again like before is.

npm install
npm run build

Now I have image being optimised and my html being minified in the same command.

At time of this writing I know hugo is going to include its own minification process here which means I’ll get rid of some of my gulp tasks in the future.

Inlining Code

This is the process of including code on the page so a clients browser doesn’t have to make a request which in turns adds overhead to the overall process of rendering a page.

Inline CSS

I ran Google pagespeed insights and it didn’t like that I had one css link still in my head section. What I did was take my css and just embed it in the head section and hey presto page insights didnt complain to much and bumped up my score.

Now to do this for everypage without having to copy and paste my css everywhere. I used what is know as a partial in Hugo which this site was built with. I put all my css in partisls\css.html and then in my header section I used:

{{ partial "css.html" . }}

This just outputs whatever is in css.html in part of my header section.

Dead Code Elimination

This is the process of eliminating dead code. It’s one of the things I didn’t use as at this time but would like to in the future.

Tree shaking

Sounds like a cool thing to visualise, dead code falling out of your code. The place where I am keeping my eye on is Webpack 2 which at time of this writing has work still in progress, but i think you can try the beta releases.

Results

So what did all this tweaking around get me. Here are the results.

From 24 requests, 2.9MB transfered, Finish 1.6min, DOMContentLoaded 6.94s | Load 1.6min.

To 22 requests, 1.2MB transfered, Finish 40.64s, DOMContentLoaded 5.11s | Load 13.27s.

I reduced the amount of actual requests down to 18 because if you look at the screenshots of chrome dev tool you can see the base64 images as requests but it tool 0ms to execute, this was preloading images mentioned above. I managed to reduce 2.4MB to 1.2MB which was the same size of just one of my background images previously.

Chrome dev tools speed results

I got 96100 for user experiemce and 99100 for speed on mobile.

Page insights speed test mobile results

On desktop I got 99100.

Page insights speed test desktop results

I got one recomendation to leverage browser caching for the following cacheable resource which was to do with analytics.

https://www.google-analytics.com/analytics.js

Since I dont have much control of changing how caching works on Googles servers, I thought it was ok to leave. I also got some recomendations to improve the content on mobile devices, some of my content was 412px wide and the viewport was 411px, so 1px out.

Summary

It’s a good start and it’s all about keeping the right balance for you. Before I tried lazy loading my css instead of inlining it but the results looked horrible. The page looked broken for a split second and that’s why I used inline style instead.

There’s probably other tweaks I can do aswell and I’ll keep playing around to try and make my website faster while also trying to maintain the uniqueness of my site that I want to use, like the typing titles. One way to make it faster is to then simplify it even futher, but that would mean using less images, only using styles just for that page, trying to eliminate any use of javascript and I’m just not ready for that yet.

Web development always moves fast and things tend to be more focused on speed and responsivness at the moment which is a good thing, so some of these tweaks are handy to know.

Webpack and Gulp are probably the most used for running tasks like bundleing or minification which is why I wanted to try both, but Webpack more specifically because I know it seems to be the one most supported for .Net core.

Including all improvements I made I also run my website behind Cloudflare which is a fast CDN. All these things combined make for a decent fast website.


comments powered by Disqus