Optimizing Jekyll

Optimizing Jekyll

For a more up-to-date and comprehensive explanation this subject has been revisited here

Upon launching my new redesigned website, I've been spending the some time optimizing the site performance and load speeds using **[Google PageSpeed Insights]**. Therefore, I thought I would take a second to share with you my discoveries and also recommend a few helpful resources for improving the performance of your own Jekyll website. Using these methods, I have managed to receive the following PageSpeed rating. Though this is still a work-in-progress, and I will be adding [updates](#updates) as I explore this topic further.

PageSpeed

In an effort not to repeat the information in the articles listed below, I'll only share findings that weren't explicitly discussed in any of the following resources.

Optimize your own images

As with most websites, when I first launched the new design, the biggest hindrance to my websites loading speed was the size of the images on my page. Though, after observing the disappointing quality of the optimized images provided by PageSpeed Insights, I instead elected to use GIMP to manually decrease and compress my images to preserve the image quality until PageSpeeds requirements were satisfied. I would highly recommend doing the same, particularly for images that are featured in various places throughout your website.


Resources:


The Results

Ive provided my resulting Gulpfile below, though its also available via gist.

1var gulp = require('gulp'),
2 shell = require('gulp-shell'),
3 minifyHTML = require('gulp-minify-html'),
4 minifyCSS = require('gulp-minify-css'),
5 sass = require('gulp-sass'),
6 importCss = require('gulp-import-css'),
7 autoprefixer = require('gulp-autoprefixer'),
8 rename = require('gulp-rename'),
9 imagemin = require('gulp-imagemin'),
10 pngquant = require('imagemin-pngquant'),
11 jpegtran = require('imagemin-jpegtran'),
12 gifsicle = require('imagemin-gifsicle'),
13 optipng = require('imagemin-optipng'),
14 replace = require('gulp-replace'),
15 glob = require('glob'),
16 fs = require('fs'),
17 concat = require('gulp-concat-util'),
18 uncss = require('gulp-uncss'),
19 critical = require('critical');
20 download = require('gulp-download');
21
22// Jekyll
23gulp.task('jekyll', function() {
24 return gulp.src('index.html', { read: false })
25 .pipe(shell(['jekyll build']));
26});
27
28// HTML
29gulp.task('optimize-html', function() {
30 return gulp.src('_site/**/*.html')
31 .pipe(minifyHTML({
32 quotes: true
33 }))
34 .pipe(replace(/<link href=\"\/css\/style.scss\"[^>]*>/, function(s) {
35 var style = fs.readFileSync('_site/css/style.scss', 'utf8');
36 return '<style>\n' + style + '\n</style>';
37 }))
38 .pipe(gulp.dest('_site/'));
39});
40
41// Javascript
42gulp.task('javascript', ['jekyll'], function() {
43 return gulp.src('js/main.js', { read: false })
44 .pipe(shell(['jspm install']))
45 .pipe(shell(['jspm bundle-sfx js/main _site/js/min.js --minify --no-mangle']));
46});
47
48// CSS
49gulp.task('optimize-css', function() {
50 return gulp.src('_site/css/style.scss')
51 .pipe(autoprefixer())
52 .pipe(uncss({
53 html: ['_site/**/*.html'],
54 ignore: []
55 }))
56 .pipe(minifyCss({keepBreaks: false}))
57 .pipe(gulp.dest('_site/css/'));
58});
59
60// Eliminate render-blocking CSS
61gulp.task('include-css', function() {
62 return gulp.src('_site/**/*.html')
63 .pipe(replace(/<link href=\"\/css\/style.scss\"[^>]*>/, function(s) {
64 var style = fs.readFileSync('_site/css/style.scss', 'utf8');
65 return '<style>\n' + style + '\n</style>';
66 }))
67 .pipe(gulp.dest('_site/'));
68});
69
70// Eliminate render-blocking CSS in above-the-fold content
71gulp.task('styles:critical', function() {
72 return gulp.src('src/sass/critical.css')
73 .pipe(minifyCSS())
74 .pipe(concat.header('<style>'))
75 .pipe(concat.footer('</style>'))
76 .pipe(rename({
77 basename: 'criticalCSS',
78 extname: '.html'
79 }))
80 .pipe(gulp.dest('_includes/'));
81});
82
83// Optimize Images
84gulp.task('optimize-images', function () {
85 return gulp.src(['_site/**/*.jpg', '_site/**/*.jpeg', '_site/**/*.gif', '_site/**/*.png'])
86 .pipe(imagemin({
87 progressive: false,
88 svgoPlugins: [{removeViewBox: false}],
89 use: [pngquant(), jpegtran(), gifsicle()]
90 }))
91 .pipe(gulp.dest('_site/'));
92});
93
94// Purge cache
95gulp.task('purge-cache', function() {
96 var options = {
97 token: config.cloudflareToken,
98 email: config.cloudflareEmail,
99 domain: config.cloudflareDomain
100 };
101 cloudflare(options);
102});
103
104// Remove unused CSS
105gulp.task('uncss', function() {
106 return gulp.src([
107 'css/style.scss'
108 ])
109 .pipe(uncss({
110 html: [
111 // your site pages here
112 'http://127.0.0.1:4000/',
113 ]
114 }))
115 .pipe(gulp.dest('css/uncss/'));
116});
117
118// Google Analytics
119gulp.task('fetch-analytics', function() {
120 return download('https://www.google-analytics.com/analytics.js')
121 .pipe(gulp.dest('assets/'));
122});
123
124// Run (Default)
125gulp.task('default', ['javascript', 'optimize-css', 'include-css', 'optimize-html', 'optimize-images', 'styles:critical', 'fetch-analytics']);
126
127// Run: Build
128gulp.task('build', ['javascript', 'optimize-css', 'include-css', 'optimize-html', 'optimize-images', 'styles:critical', 'fetch-analytics']);
129
130// Run: Clean
131gulp.task('clean', ['uncss']);

Updates

Leveraging browser caching

Since sharing my original post, Ive since found a way to resolve the persistent Leverage browser caching issue, which was ironically referencing Googles own analytics tools.

1// Google Analytics
2gulp.task('fetch-analytics', function() {
3 return download('https://www.google-analytics.com/analytics.js')
4 .pipe(gulp.dest('assets/')); // or whatever folder you want it in
5});

This way, a new version of the analytics.js file is downloaded on each deployment, rather than utilizing Googles remote file. Therefore, you should also instead include your local analytics.js file in your html.