Using Gulp.js to Optimize Our Frontend Workflow (v2.0 Code Journal)

We're progressively building a full v2.0 for our frontend shopping cart. In the "v2.0 Code Journal" entries, we'll expose some of our development tools and methods for doing so. Chances are this stuff will be useful to a dev or two out there.

We're keen on performance and automatization here at Snipcart. And we know most developers in our audience must also be pretty fond of those things. So we decided to turn to our blog to address both these topics from a frontend perspective. Hopefully, this post will help you optimize your frontend workflow with a tool we've come to love: Gulp. ​ Previously, we had already used Grunt to automate specific tasks. However, when developing our new dashboard, our new website, and starting the rehaul of our shopping cart, we switched to Gulp.

snipcart-gulp-optimize-frontend-workflow
By leveraging node streams, Gulp helps us build efficient and easier task automatization code. Today, I'm going to discuss how we use it to maximize productivity & performance for our frontend workflow. More specifically, I'm going to show how to use four different, useful Gulp plugins. ​

You can find all the code used for this post in our GitHub repo. ​

Setting up Gulp

First, let's set up Gulp's streaming build system. ​ We'll need to create a package.json to install Gulp via npm later on. Once this is done, we'll be able to easily add all the plugins we want. If you haven't installed npm yet, here's how. npm is the package manager for node; it's a must-have for a proper frontend setup. ​ Below is a basic package.json you can use. You can notice we use CoffeeScript. A lot of Gulp examples are done with classic JavaScript, but CoffeeScript provides a cleaner source code for gulpfile. ​

{
  "name": "Snipcart",
  "version": "0.0.1",
  "description": "Snipcart Frontend Gulp frontend workflow",
  "author": "Snipcart",
  "devDependencies": {
    "coffee-script": "1.10.x",
    "gulp": "~3.9.x"
  },
  "license": "MIT"
}
​

​ Now, install that package: npm install && npm install -g gulp. ​ Okay, now let's go play with some kickass Gulp plugins! ​ ​

Browsersync

Browsersync is the one plugin that helps us improve frontend productivity the most. It creates a local server that automatically reloads web pages when source code changes are saved. Oh, and it also synchronizes every local page together: ​ snipcart-gulp-optimize-frontend-workflow-browsersync ​ Imagine you want to test and iterate on your brand new website's responsiveness. You just start Browsersync on your desktop, access the external URL provided in the terminal with your smartphone or tablet, and let the magic happen. It's pretty awesome. ​ Did I mention that it fills forms on every device too? ​ Now for the installation: ​ Since this is our first task we're setting up here, we'll need an empty gulpfile. Let's name it ... gulpfile.coffee. ​ We now need to install the browser-sync plugin. Again, npm makes it super easy: npm install browser-sync --save-dev ​ The save-dev part will fill for us the package dependencies into the package.json. Here's how you'd integrate a Browsersync task into your gulpfile: ​

# Requirement
### Define variables for each gulp plugin ###
gulp = require 'gulp'
​
browserSync = require 'browser-sync'
bs1 = browserSync.create("first server")
​
# Paths
### You can also use a local url, in that case, use browserSync.init proxy: local ###
local = { baseDir: "./" }
​
### Define all your source files here ###
sync = 
    css: 'stylesheets/**/*.css'
    html: '**/*.html'
​
# Tasks
### On each source file change, trigger a browsersync.reload ###
gulp.task 'browser-sync', ->
    bs1.init({
        port: 3014,
        server: "./"
    })
    gulp.watch(sync.css).on('change', bs1.reload);
    gulp.watch(sync.html).on('change', bs1.reload);

​ Now, all you have to do is run gulp browser-sync on your favorite command line interface. And you're synched! ​ ​

Autoprefixer

Autoprefixer is a powerful tool that wasn't originally designed as a Gulp plugin. It was created as a PostCSS plugin at first (if you haven't heard about PostCSS, take a look, it may just be the future of CSS tasks automatization). ​ Based on the canIUse database, it automatically provides vendor's prefix for your CSS properties if you need them. How does it know you need them? You just have to ask it! You want to support IE9 and above? Good, it'll work. Only the up to 1% global usage browsers? Fine, it'll work too. ​ No more vendor's prefix tipping anymore. I don't know about you, but it makes me feel free. And if, by habit, you write an old -webkit-border-radius, don't worry, Autoprefixer will delete that line for you. You're welcome. ​ Now for the installation: ​ At Snipcart, we use SASS to help us maintain a proper style base. So first, let's write a classic SASS to CSS task and a watch task (to execute the CSS task when we change a SASS file). ​

# Requirement
sass = require 'gulp-sass'
​
# Paths
srcs =
    scss: 'sass/**/*.scss'
    watch:
        scss: 'sass/**/*.scss'
​
dests =
    css: 'stylesheets'
​
# Tasks
gulp.task 'watch', ->
    gulp.watch srcs.watch.scss, ['css']
​
gulp.task 'css', ->
    gulp.src srcs.scss
        .pipe sass()
        .pipe gulp.dest(dests.css)

Now let's add Autoprefixer to our CSS task. ​ npm install gulp-autoprefixer --save-dev

# Tasks
gulp.task 'css', ->
    gulp.src srcs.scss
        .pipe sass()
        .pipe autoprefixer(cascade: false, browsers: ['> 1%'])
        .pipe gulp.dest(dests.css)

​ Sounds too easy? Remember the node streams advantage Gulp provides? ​ However, there's one little thing that could bother you if you use our Gulp task. Try making a mistake on your SCSS file. Task will stop. So let's improve that part, shall we? ​

Notify

We could allow the previous Autoprefixer task to continue, even if an error happens. But to be more productive, we'll add gulp-notify. ​ Its name is pretty self-explanatory: it adds notifications (for Windows, Mac OS, Linux, everything) to your Gulp tasks. It's easier to get visual notifications than to watch your console for any suspicious logs. ​ Now for the installation: ​ First, as always, install the package: npm install gulp-notify --save-dev, then: ​

# Requirement
notify = require 'gulp-notify'
​
# Tasks
gulp.task 'css', ->
    gulp.src srcs.scss
        .pipe sass().on('error', (err) ->
            notify(title: 'CSS Task').write err.line + ': ' + err.message  
            this.emit('end');
        )
        .pipe autoprefixer(cascade: false, browsers: ['> 1%'])
        .pipe gulp.dest(dests.css)

​ You can also add a notification for success, but I personally remove it. Since we use Browsersync, the browser will just reload if the task succeeds. As we sync only the generated CSS, if you write error-ridden SCSS, the CSS itself won't change. ​

Imagemin

For this last plugin, let's talk a little about optimization. Websites are growing fatter nowadays, mainly because of media files. Gulp can help us improve overall performance by minifying files (CSS, JavaScript, HTML), removing unused code, combining duplicated code, etc. But since I don't want this post to go on forever, I chose to provide you with a way to simply automate images optimization. It's important to note that manual optimization is often better because we can provide lossless renderings. ​ So, for our images, we can use gulp-imagemin and the pngquant plugin. ​ Now for the installation:

# Requirement
imagemin = require 'gulp-imagemin'
pngquant = require 'imagemin-pngquant'
​
# Paths
srcs =
    scss: 'sass/**/*.scss'
    img: 'images/*'
​
dests =
    css: 'stylesheets'
    img: 'images'
​
# Tasks
gulp.task 'media', ->
    gulp.src srcs.img
        .pipe imagemin({
            progressive: true,
            use: [pngquant()]
        }) 
        .pipe gulp.dest dests.img

​ Warning: the 'media' task is not in a watch task. So it only executes when we start it. We can watch every image files, but it can be a major performance issue regardless of your images number/size. ​ All right folks, let's run the commands once more: ​ npm install gulp-imagemin imagemin-pngquant --save-dev ​ And there we have it, a sweet task optimizing our images. ​

Running all the Gulp tasks at once

To end this lengthy post, I will just add to our main gulpfile a default task that executes all our four previous tasks in the proper order: ​

gulp.task 'default', ['media', 'css', 'watch', 'browser-sync']

​ Now you'll just have to enter gulp in your CLI, and: ​

  • Your images will be optimized.
  • Your SASS will be compiled to CSS, with automated vendor's prefixes.
  • Your SASS errors will pop up as notifications on your screen.
  • A local server page will start, synched with your source files modifications. ​ Thanks to Gulp you're ready to kick some serious ass with your development efforts! ​

Conclusion

Yup, Gulp rocks. It helps us improve performance, maintainability, and productivity. And you can add each and every kind of plugins you'd need to do just that. ​ As for us at Snipcart, we're now working on a new frontend version of the cart itself. Creating a proper gulpfile was the first step in making it as rock-solid as we want it to be. I sincerely hope these methods can add value to your frontend development workflow too. :) ​ Friendly reminder: all the code used for this blog post demo is available in our GitHub repo.


If you enjoyed this post and found it valuable, please, take a second to share it on Twitter. As always, your thoughts and questions regarding Gulp, our methods & the upcoming cart v2.0 are welcome in the comments below!

Suggested posts: