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.
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:
- Scoring 100 on Google’s PageSpeed Insights with Jekyll
- How to get your Jekyll + GitHub pages website to pass Google’s PageSpeed Tests
- Optimized Jekyll site with Grunt
The Results
I’ve provided my resulting Gulpfile below, though it’s 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');2122// Jekyll23gulp.task('jekyll', function() {24 return gulp.src('index.html', { read: false })25 .pipe(shell(['jekyll build']));26});2728// HTML29gulp.task('optimize-html', function() {30 return gulp.src('_site/**/*.html')31 .pipe(minifyHTML({32 quotes: true33 }))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});4041// Javascript42gulp.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});4748// CSS49gulp.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});5960// Eliminate render-blocking CSS61gulp.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});6970// Eliminate render-blocking CSS in above-the-fold content71gulp.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});8283// Optimize Images84gulp.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});9394// Purge cache95gulp.task('purge-cache', function() {96 var options = {97 token: config.cloudflareToken,98 email: config.cloudflareEmail,99 domain: config.cloudflareDomain100 };101 cloudflare(options);102});103104// Remove unused CSS105gulp.task('uncss', function() {106 return gulp.src([107 'css/style.scss'108 ])109 .pipe(uncss({110 html: [111 // your site pages here112 'http://127.0.0.1:4000/',113 ]114 }))115 .pipe(gulp.dest('css/uncss/'));116});117118// Google Analytics119gulp.task('fetch-analytics', function() {120 return download('https://www.google-analytics.com/analytics.js')121 .pipe(gulp.dest('assets/'));122});123124// Run (Default)125gulp.task('default', ['javascript', 'optimize-css', 'include-css', 'optimize-html', 'optimize-images', 'styles:critical', 'fetch-analytics']);126127// Run: Build128gulp.task('build', ['javascript', 'optimize-css', 'include-css', 'optimize-html', 'optimize-images', 'styles:critical', 'fetch-analytics']);129130// Run: Clean131gulp.task('clean', ['uncss']);
Updates
Leveraging browser caching
Since sharing my original post, I’ve since found a way to resolve the persistent “Leverage browser caching” issue, which was ironically referencing Google’s own analytics tools.
1// Google Analytics2gulp.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 in5});
This way, a new version of the analytics.js
file is downloaded on each deployment, rather than utilizing Google’s remote file. Therefore, you should also instead include your local analytics.js
file in your html.