Optimizing Site Performance: Gulp, Caching, and more

August 17, 2014

Having a fast site is important. Being able to ensure that a page is ready for the user to read in under 1 second can make all the difference in the world. There’s a bunch of fixes I applied on this site that I’d like to talk about. There’s tons of resources out there, but I’d like to talk about a few core ones that I missed and my approach.

GTmetrix after my optimizations. I originally scored about 80%.

To find out what I could still improve on my website, I used GTmetrix which uses YSlow (by Yahoo) and Page Speed (by Google) and assigns scores depending on certain factors.

It also shows the page load time, total page size and total number of requests. (Lower is better for all these three numbers.) These numbers do not seem to have any large impact on the speed grade, yet are very important to the user.

Limit amount of CSS and JS files

Minified files are the best. They are small and easier to download. Having a workflow that combines Javascript/CSS into single files and then minifies them can impact the load speed of your site by minimizing the amount of requests the browser needs to make.

For instance, I have the following stylesheets in one of my larger projects:

  • main.scss
  • grid.scss
  • media-queries.scss
  • variables.scss

That’s four stylesheets you’d have to load. However, I can use @import as one of Sass’ features which will make one large main.css file that contains the contents of all these files.

@import 'variables'
@import 'grid'
// Insert CSS here
@import 'media-queries'

Unlike the native CSS @import functionality (which should always be at the top of the CSS file), the @import that Sass handles can be anywhere you want in your file.1

Gulp for minification, uglification

You’ll need npm (Node Package Manager) for Gulp. Let’s install it:

$ npm install -g gulp

First, you’ll want to ensure you have a package.json file, and add some of the dependencies to it:

$ npm install --save-dev gulp-minify-css gulp-notify gulp-rename gulp-uglify

This will fill your package.json file. If you ever want to reinstall these, just run npm install when in the folder where package.json is located.

{
   "devDependencies": {
      "gulp": "^3.8.7",
      "gulp-minify-css": "^0.3.7",
      "gulp-notify": "^1.4.2",
      "gulp-rename": "^1.2.0",
      "gulp-uglify": "^0.3.1"
   }
}

Next up is setting up a gulpfile.js. This is what mine looks like.

// Requirements
var gulp = require('gulp');
var minifycss = require('gulp-minify-css');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var notify = require('gulp-notify');

// Set up paths
var paths = {
    css: 'public/css/src/main.css',
    js: 'public/js/src/*.js'
};

// Minify CSS, and rename to .min.css
gulp.task('css', function(){
   return gulp.src(paths.css)
       .pipe(minifycss())
       .pipe(rename({extname:'.min.css'}))
       .pipe(gulp.dest('public/css'))
       .pipe(notify({message : "Modifications to the CSS files have been minified." }));
});

// Uglify Javascript, and rename to .min.js
gulp.task('js', function(){
    return gulp.src(paths.js)
        .pipe(uglify())
        .pipe(rename({extname:'.min.js'}))
        .pipe(gulp.dest('public/js'))
        .pipe(notify({message : "Modifications to the JS files have been uglified & minified." }));
});

// Set up watcher
gulp.task('watch', function() {
    gulp.watch(paths.css, ['css']);
    gulp.watch(paths.js, ['js']);
});

// Set up default task
gulp.task('default', ['watch', 'css', 'js']);

It does some operations, but also watches if files are changed. To run it:

$ gulp

That’s all, it should work.

Image optimizations

ImageOptim is your best friend for image optimizations (if you are on a Mac).

ImageOptim in action, making snapshots made with VLC smaller, without any quality loss.

It does what it says it does. It losslessly optimizes images, so that they are smaller. This can sometimes halve (!) your image size, so I recommend this wholeheartedly.

Browser caching by leveraging Apache’s Expires header

This one is server-side, so if you are on shared hosting you might be out of luck. You’ll need to enable some apache modules:

$ sudo a2enmod expires

This is so that the Expires functionality works. But this module relies on us being able to change headers. So if your headers module is not enabled, enable it now:

$ sudo a2enmod headers

Finally, restart the apache service.

$ sudo service apache2 restart

Next up, you can set the Expires headers on your files, which browsers will use to remember that they can keep your image cached and don’t need to fetch it again until the period you choose. This is done in the .htaccess file.

<filesMatch "\.(ico|gif|jpg|png)$">
  ExpiresActive On
  ExpiresDefault "access plus 6 month"
  Header append Cache-Control "public"
</filesMatch>
<filesMatch "\.(css|js)$">
  ExpiresActive On
  ExpiresDefault "access plus 1 week"
  Header append Cache-Control "public"
</filesMatch>

You can verify whether your files are being cached by taking a look at the requests in Google Chrome and checking out the headers.

Getting rid of @import for Google Web Fonts

Do you use Google Web Fonts as an external style sheet? Good. If you use @import, you might be slowing down your site ever so slowly.

The relevant piece:

For 90%+ of the cases you likely want the <link> tag. As a rule of thumb, you want to avoid @import rules because they defer the loading of the included resource until the file is fetched.. and if you have a build process which "flattens" the @import's, then you create another problem with webfonts: dynamic providers like Google WebFonts serve platform specific versions of the fonts, so if you simply inline the content, then you'll end up with broken fonts on some platforms. — igrigorik

I picked this up via StackOverflow, which is a post about including a link or using import with Google Web Fonts. It’s a small but meaningful improvement that speeds up your pages.

Conclusion

Making use of some or all of these improvements will definitely improve your site’s performance and caching, especially when using slower connections, like mobile devices have to fall back on Edge/3G. In any case, it’s a major benefit to have your site load faster.

Users expect a site to load in less than 5 seconds, and the most optimal load time is about ~1 sec. However, there’s still websites that score good on the test, but have load times of up to or more than 30 seconds, which is completely unacceptable for a website.


  1. Don’t confuse the @import, which is a part of Sass, with the @import functionality of CSS. Sass actually compiles the original file inside your main.css file, whereas a classic @import will merely link to the other file. (Which means more XHttpRequests, which in turn slows down your site.)