Over the past year I’ve been slowly improving the performance of this website and Webworke.rs.
I’ve put a lot of work into my sites, but many of the performance improvements couldn’t have been made so easily without the great ecosystem of open source software and free services available to me. To say that I’m thankful for this is a gross understatement.
Both of my sites are built with a combination of Jekyll and Grunt. They’re hosted on GitHub Pages and their DNS is served by CloudFlare. I wholeheartedly endorse this tech stack for anyone wanting a static website.
What follows is an overview of some performance best practices and how I’ve been able to adhere to them with my development and production setup.
HTML
Minify HTML
The HTML gets minified by grunt-contrib-htmlmin, which collapses whitespace and removes comments, amongst other small improvements.
- It also minifies inline JavaScript (with UglifyJS) and inline CSS (with clean-css)
- And there’s an option to
keepClosingSlash
, which are needed for my inline SVGs.
CSS
Lint CSS
My Sass is linted with grunt-scss-lint, which ensures that I don’t introduce any inconsistencies, poor practices, or general cruft into my CSS. This results in a well organized stylesheet.
Use Autoprefixer
All the vendor prefixes are managed by grunt-autoprefixer so that I have effortless control over which browsers I support when writing my CSS. I no longer need to worry about having unnecessary vendor prefixes in my CSS rules.
Concatenate CSS
The CSS is written in Sass and organized via partials that compile to one stylesheet. If my CSS were in multiple files, I’d use grunt-usemin to send those files to grunt-contrib-concat for concatenation.
Sort CSS
My compiled CSS is sorted with grunt-csscomb to improve gzip compression, although my styles are lean enough that this hasn’t made any difference.
Read about the benefits of sorting CSS properties at Reduce file size with CSS Sorting.
Minify CSS
The CSS gets minified by grunt-contrib-cssmin, which uses clean-css under the hood.
Inline Critical CSS
The above the fold CSS is generated with grunt-penthouse and inlined into the <head>
with an include.
Load CSS Asynchronously
The whole stylesheet is loaded asynchronously with loadCSS. An improvement could be made here to only load the styles that weren’t inlined, although I haven’t found a good way to do that.
Fonts
I only support the WOFF and WOFF2 font formats and have them asynchronously loaded with fontloader.js (and its loadFont() function) so that they’re no longer blocking the page from loading.
More information about this technique (and related ones) at Better webfont loading with using localStorage and providing WOFF2 support.
JavaScript
Lint JavaScript
My JavaScript is validated with grunt-contrib-jshint, which helps ensure that its error free. I also don’t have very much of it since my websites are relatively simple functionality-wise.
Concatenate JavaScript
I use grunt-usemin to send my JavaScript files to grunt-contrib-concat for concatenation.
Minify JavaScript
A plugin of many talents, grunt-usemin sends the JavaScript to grunt-contrib-uglify to be minified.
Load JavaScript Last
Save for the aforementioned loadCSS() and loadFont() functions, the rest of my JavaScript is loaded just before the closing </body>
tag.
Images
Optimize Images
For this website, I use grunt-contrib-imagemin to compress the size of my images. For Webworke.rs I use grunt-imageoptim and find the latter plugin results in smaller filesizes.
Serve Scaled Images
For Webworke.rs I’ve implemented jekyll-picture-tag and that allows me to use the <picture>
element with picturefill polyfill.
SVG
Minify SVGs
My SVGs get minified by grunt-svgmin, although I also do some editing by hand before committing them into version control.
Inline SVGs
I inline all my SVGs with Jekyll, so I save requests at the expense of browsers I don’t support. I’d consider using grunticon for less feature rich browsers.
Server
Hosting on GitHub Pages
In and of itself, GitHub Pages is incredibly fast and reliable, as well as free! It makes a lot of sense to take advantage of the hosting, especially when your site’s source code is already put into version control and stored on GitHub.
CloudFlare for Everything Else
I host my DNS with CloudFlare, which opens up a whole world of server-side optimizations. I get my site served by a CDN, compression of my assets via gzip, the ability to set the TTL for static resources (the whole site, basically) for browser caching, and SSL (even though the connection from GitHub Pages to CloudFlare is unencrypted, but hey beggars can’t be choosers).
Results
WebPagetest
Google PageSpeed Insights
YSlow
Todo
I still have work to do and the following is my shortlist of improvements to implement in these coming months:
- lazy load my images
- switch to grunt-imageoptim (for this site)
- start using the
srcset
by finding a good workflow to generate the images and markup