Optimize your site for a 100/100 score in Google PageSpeed with Gulp & plugins
There are multiple reasons why you want to consider the speed of your webpage:
- Everybody hates slow webpages.
- Page speed is a Google ranking factor
- The average visitor has 10 seconds of patience for your website before they leave.
In this article I’ll share the code I use to speed up pages and get a 100% score on Google Pagespeed Insights.
First run the test
Just run PageSpeed Insights and see what you get. If you’re reading this post, you’ve probably already done so.
CSS: Minify resources + leverage browser caching
This piece of code uses CSS minification and implements revisioning for cached files (cache busting). This way we can set stylesheets to never expire, and force the browser download a newer version if it’s available. This depends on header configurations (see below).
# Command-line:
npm install --save-dev gulp-clean-css gulp-rename gulp-rev
// gulpfile.js
var cleancss = require('gulp-clean-css'),
rename = require('gulp-rename'),
rev = require('gulp-rev');
gulp.task('build-css' , function(){
return gulp.src(['src/css/*.css'])
.pipe(cleancss())
.pipe(rename({ suffix:'.min' }))
.pipe(rev())
.pipe(gulp.dest('dist/css'))
.pipe(rev.manifest({ merge:true }))
.pipe(gulp.dest('./'));
});
Javascript: Minify resources + leverage browser caching
This is essentially the same as the CSS minification and cache busting, but for Javascript.
# Command-line:
npm install --save-dev gulp-rev gulp-uglify
// gulpfile.js
var rev = require('gulp-rev'),
uglify = require('gulp-uglify');
gulp.task('build-js', function () {
return gulp.src(['src/js/*.js'])
.pipe(rev())
.pipe(uglify())
.pipe(gulp.dest('dist/js'))
.pipe(rev.manifest({ merge: true }))
.pipe(gulp.dest('./'));
});
Optimize images
Unfortunately, just using an optimizer like Imagemin with default settings doesn’t do the trick. I’ve tweaked these settings to get the best trade-off between file size and quality.
Please also check the image sizes and the size you’re actually using! Don’t serve a 1080p image if it’s only displayed at 300px height.
# Command-line:
npm install --save-dev gulp-imagemin imagemin-mozjpeg imagemin-optipng
// gulpfile.js
var imagemin = require('gulp-imagemin'),
imageminMozjpeg = require('imagemin-mozjpeg'),
imageminOptipng = require('imagemin-optipng');
gulp.task('images', function(){
// optimize all images
return gulp.src([
'dist/img/**/*.jpg',
'dist/img/**/*.jpeg',
'dist/img/**/*.png',
'dist/img/**/*.gif'
])
.pipe(imagemin(
[
imagemin.gifsicle({ interlaced: true }),
imageminMozjpeg({
quality: 85,
progressive: true
}),
imageminOptipng({ optimizationLevel: 5 }),
imagemin.svgo({ plugins: [{ removeViewBox: false }] })
], {
verbose: true
}
))
.pipe(gulp.dest('dist/img'));
})
Optimize CSS Delivery + Prioritize visible content
Now, if your CSS is minified and concatenated into a single file, what’s left to do? One trick is to move the essential CSS out of your CSS file and inlining it in the document itself. Luckily, there’s an app for that!
# Command-line:
npm install --save-dev critical
// gulpfile.js
var critical = require('critical').stream,
gutil = require('gulp-util');
gulp.task('critical', function () {
return gulp.src('dist/*.html')
.pipe(critical({
base: 'dist/',
inline: true,
minify: true,
width: 1200,
timeout: 30000,
height: 900
}))
.on('error', function(err) { gutil.log(gutil.colors.red(err.message)); })
.pipe(gulp.dest('_temp'));
});
Please note that I’m copying this into a temporary directory. I was getting performance issues without this.
The performance gained by inlining the CSS is debatable. It adds a few lines of code to each page, that would normally only be downloaded once (but later). On the other hand, the page isn’t as jumpy when it loads - which adds to the overall experience.
HTML: Remove render-blocking JavaScript & use asynchronous scripts
Move as many Javascript calls to the bottom of the HTML document as possible. There are only a few reasons why you might want let Javascript block the rendering process. Then make sure the scripts you are including have the ‘async’ attribute:
<!-- Change this: -->
<script type=“text/javascript“ src=“somescript.js“></script>
<!– To this: –>
<script async type=“text/javascript“ src=“somescript.js“></script>
:hexoPostRenderEscape–>Server settings: Leverage browser caching
Now, this is server-specific. You’re looking for the expiration headers for your server. For Apache servers, the easiest way is to set it up using a .htaccess file. I’ve found this a very valuable resource: Apache Server Configs.
For caching purposes, you should look for the mod_expires.c section. Remove or comment-out any file type you don’t want to support. Double-check if the MIME type is supported by default - take a look at the mod_mime.c section in the example.
Please beware that you should use this in conjunction with cache busting or your CSS/JS changes will not be visible! In the examples above I’m using gulp-rev to handle this.
Server settings: Enable compression
This means gzip/deflate should be enabled. It’s a common module for most servers. For most servers I’ve encountered, it was enabled by default. If you need to enable it, check out the mod_deflate.c section at Apache Server Configs.
Improve server response time
Uh-oh, this means your application is slow in general. There’s no quick answer here. Check settings of databases & web server. Use server-side caching whenever possible and optimise your code where possible.
Avoid landing page redirects
Pretty self-explanatory. You want yourdomain.com to serve a page immediately. If you’re using a multi-language page, choose a default language or display a “Please select your language” page (the latter may have SEO implications).
Final note: Use common sense. Shave off whatever you can.
- Image resolution v.s. used resolution: don’t serve a 1080p image if it’s only displayed at 300px height. Only serve @2x images for displays that support them (this could be a 50% reduction).
- Big headers, background images and video backgrounds can look very nice, but they are expensive.
- Take a look at your web fonts usage, especially icon fonts: why download all the icons if you’re only using 10% of them?
- Javascript libraries (jQuery, jQuery UI): they are very convenient, but may not be necessary. Consider using plain Javascript.
- Unused CSS: organise your CSS (SMACSS, OOCSS) so you use your CSS efficiently. When using frameworks like Bootstrap or Foundation, make sure it doesn’t include components you’re not using.
- Use lazy loading or chunking for large pages: don’t load the full page upfront if you don’t expect users to scroll all the way down. Why download an image a visitor is never going to see?
Sources
- PageSpeed Insights Rules
- Image courtesy: Google PageSpeed Insights