featured5

How does a Command Line fit into Web Design: Automation with Grunt and Gulp (5/5)

By - (Last Modified: July 27, 2015)

So far you’ve learned how to do things like compiling code, autoprefixing, cleaning, compressing and minifying all just by typing a few words. This is great, but what if you have a project that would need you to run several of these commands, one after the other, over and over again until you complete your work? For example:

  1. Compile preprocessor to CSS
  2. Autoprefix CSS
  3. Clean CSS
  4. Compile Jade to HTML
  5. Concatenate and Minify JavaScript

Even with just a few words per command it would quickly become tiresome throughout the course of a typical site creation process.

This is where “Task Runners” step in to save the day. With task runners you can setup a single file inside your project that defines all the tasks you need to run on your project, and the order they need to run in. In this file you can then define custom commands you can use to execute all those tasks once.

You’ll be learning how to setup task runners in this way through this tutorial, and in the process you’ll also see an example of bringing in scripts from Bower packages for efficient deployment in your projects.

Note: This tutorial assumes you’ve completed all the previous tutorials in this series. If you haven’t yet done that, you’ll find it helpful to go through them before you start here.

There are actually several task runners available right now, however for the purposes of this tutorial we’ll be focusing on the two which are currently most popular: Grunt and Gulp.

There are several technical differences between the two projects, but for the purposes of simplification, Gulp is easier to use for beginners while Grunt has more customization for better control of the task. I recommend following the steps for using both below then deciding for yourself which one you prefer.

We’re going to be creating a project that watches and automatically compiles Stylus and Jade, and optimizes CSS and JavaScript. We’ll achieve this first using Grunt, and then using Gulp.

To begin with, we’ll need to setup an example project with some files inside it that our task runner can operate on. Create a folder named “Grunt Project”, then add a subfolder named “build” and a subfolder named “source”.

In the “source” folder add two new subfolders named “stylus”, “jade”. Add a few example files of the appropriate type to each folder.

The files can contain any code you want, just so you have something you can see the compilation process working on.

Tip: If you’re not sure what code to add, try grabbing some sample code from Codepen: pens tagged stylus, pens tagged jade.

Your directory should look like this:

Directory of Example Project

We’re then also going to take advantage of what we learned about Bower in a previous lesson and grab downloads of jQuery and Modernizr, which we’ll combine and minify later.

Run the commands:

[shell]bower install jquery –save[/shell]

[shell]bower install modernizr –save[/shell]

Now, make a duplicate of your entire project folder and rename it “Gulp Project”.

This way you can follow the steps on using Grunt inside your “Grunt Project” folder, and the steps for using Gulp inside your “Gulp Project” folder.


Grunt Banner

In order for Grunt commands to work you’ll need to install its CLI (command line interface). Install it globally with:

[shell][sudo] npm install -g grunt-cli[/shell]

Every project that uses Grunt will need a “package.json” file in the root folder.

We covered setting up a “package.json” file by using the command npm init in the previous Installing Packages tutorial. If you haven’t completed that section yet please go back and follow it now.

Install Grunt into your project and save it as a development dependency with:

[shell]npm install grunt –save-dev[/shell]

You’ll remember that when you wanted to use packages with npm or Bower, you had to search in the right place to get the versions designed to work with each system.

The same thing goes when using packages with Grunt. Through Grunt you can access an ecosystem of plugins, which are essentially wrappers around vanilla npm packages. These plugins are still delivered via npm, but they’re specially equipped to work with Grunt

For example, instead of the npm package UglifyJS, with Grunt you might use the plugin “grunt-contrib-uglify”.

You can search for Grunt plugins at http://gruntjs.com/plugins

Grunt Plugins

For our project we’ll be installing these six Grunt plugins:

Each one will be installed into your project folder’s “node_modules” subfolder, and saved as a development dependency.

Run each of these commands, one at a time, with your terminal pointed at your “Grunt Project” folder:

[shell]npm install grunt-contrib-stylus –save-dev[/shell]

[shell]npm install grunt-autoprefixer –save-dev[/shell]

[shell]npm install grunt-contrib-cssmin –save-dev[/shell]

[shell]npm install grunt-contrib-jade –save-dev[/shell]

[shell]npm install grunt-contrib-uglify –save-dev[/shell]

[shell]npm install grunt-contrib-watch –save-dev[/shell]

When you’re done, you should see these folders inside your project’s “node_modules” folder:

Grunt Plugin Folders

Every Grunt project also needs to have what’s called a Gruntfile in the root folder.

A Gruntfile is a file named “Gruntfile.js”, or “Gruntfile.coffee” if you prefer writing in CoffeeScript. In our case we’ll be working with JavaScript, so add a file named “Gruntfile.js” to your root folder.

Filling in your Gruntfile will allow you to determine which commands will trigger what tasks to be run. You can start by just adding a basic shell into your Gruntfile. Add the following code to your Gruntfile.js:

[javascript]module.exports = function(grunt) {

};[/javascript]

Now we’re going to use the grunt.loadNpmTasks method to enable our plugins.

Inside the curly brackets of your existing Gruntfile, we’ll add six lines, one to enable each grunt plugin, like so:

[javascript]module.exports = function(grunt) {

// Load grunt plugins.
grunt.loadNpmTasks(‘grunt-contrib-stylus’);
grunt.loadNpmTasks(‘grunt-autoprefixer’);
grunt.loadNpmTasks(‘grunt-contrib-cssmin’);
grunt.loadNpmTasks(‘grunt-contrib-jade’);
grunt.loadNpmTasks(‘grunt-contrib-uglify’);
grunt.loadNpmTasks(‘grunt-contrib-watch’);

};[/javascript]

This code registers the name of each plugin as a grunt command, allowing us to use that command to make the plugin run a task. For example, we would use the command grunt stylus to run a stylus task, grunt autoprefixer to run an autoprefixer task and so on.

Our grunt plugins are installed and the commands to use each are operational, however if you were to use them right now you wouldn’t see anything happen. The reason is we have to setup some configuration to determine what each task should actually do.

This is done by adding the grunt.initConfig method to your Gruntfile, and then passing information through it that dictates how you want each task to be run.

First, we’ll add the grunt.initConfig method above the lines you just added to load grunt plugins:
[javascript]grunt.initConfig({

});[/javascript]

Now we can go ahead and add the configuration for each of the plugins we installed.

Every plugin has its own range of settings you can use, and these options are detailed on the pages linked to in the “Install Grunt Plugins” section above.

You can also read full detail on configuring Grunt tasks here:http://gruntjs.com/configuring-tasks

We’re going to start by adding configuration for our stylus task.

In between the curly brackets you just added, on the empty line, add the following code:
[javascript]stylus: {
compile: {
options: {
compress: false,
paths: [‘source/stylus’]
},
files: {
‘build/style.css’: ‘source/stylus/main.styl’
}
}
}[/javascript]

Your Gruntfile should now look like this:
[javascript]module.exports = function(grunt) {

grunt.initConfig({

stylus: {
compile: {
options: {
compress: false,
paths: [‘source/stylus’]
},
files: {
‘build/style.css’: ‘source/stylus/main.styl’
}
}
},
});

// Load grunt plugins.
grunt.loadNpmTasks(‘grunt-contrib-stylus’);
grunt.loadNpmTasks(‘grunt-autoprefixer’);
grunt.loadNpmTasks(‘grunt-contrib-cssmin’);
grunt.loadNpmTasks(‘grunt-contrib-jade’);
grunt.loadNpmTasks(‘grunt-contrib-uglify’);
grunt.loadNpmTasks(‘grunt-contrib-watch’);

};[/javascript]
Let’s go through a breakdown of the code we’ve added here. We won’t break down every task, but looking at this one should give you an idea of the type of syntax used when putting together Grunt task configuration.

As mentioned above, every plugin has different configuration options so when you’re employing a new plugin take a good look at the usage instructions it offers.

The first thing we’ve done is add an entry into our config for our stylus task with the code:
[javascript]stylus: {

},[/javascript]
Inside that we’ve added a compile entry to control what happens during compilation:
[javascript]stylus: {
compile: {

}
},[/javascript]
Inside the compile task we’ve created a options area.

We’ve used that area to set the compress option to false, because we’ll be doing our code optimization later.

We’ve also set the paths option to [’source/stylus’] so if Stylus sees the@import directive while compiling it will look for files to import in the project’s “source/stylus” folder:
[javascript]stylus: {
compile: {
options: {
compress: false,
paths: [‘source/stylus’]
}
}
},[/javascript]
Then after the options area we’ve added a files area to control the output directory and file name, as well as the input directory and file name.

We’ve set the output location of our compiled CSS file to be ’build/style.css’, while the Stylus file to process is ’source/stylus/main.styl’.
[javascript]stylus: {
compile: {
options: {
compress: false,
paths: [‘source/stylus’]
},
files: {
‘build/style.css’: ‘source/stylus/main.styl’
}
}
},[/javascript]
Now, with your terminal pointed at your main root folder run the command:
[javascript]grunt stylus[/javascript]

Look inside your “build” folder and you should see a newly compiled “style.css” file.

We’ll now move fairly quickly through the configuration of each remaining task. Insert each block of config code immediately after the one you previously added.

Add this code:
[javascript]autoprefixer: {
compile: {
files: {
‘build/style.css’: ‘build/style.css’
},
},
},[/javascript]
Run the autoprefixer task with:
[javascript]grunt autoprefixer[/javascript]
If you inspect your “build/style.css” file you should now see prefixes added where required.

Add this code:
[javascript]cssmin: {
clean: {
files: {
‘build/style.css’: ‘build/style.css’
}
}
},[/javascript]
Run the cssmin task with:
[javascript]grunt cssmin[/javascript]
If you look at your “build/style.css” again now, you’ll see it has been nicely cleaned and compressed for you.

Add this code:
[javascript]jade: {
compile: {
files: [{
expand: true,
cwd: “source/jade”,
src: “*.jade”,
dest: “build”,
ext: “.html”
}]
}
},[/javascript]
Run the jade task with:
[javascript]grunt jade[/javascript]
If you look inside your “build” folder, you should now see an HTML file to correspond with every Jade file you had in your “source/jade” folder.

Add this code:
[javascript]uglify: {
bower_js_files: {
files: {
‘build/output.min.js’: [
‘bower_components/jquery/dist/jquery.js’,
‘bower_components/modernizr/modernizr.js’
]
}
}
},[/javascript]
In this example you’ll see we’re referencing the locations of the Bower components we installed earlier.

We’re grabbing the full expanded versions of both jQuery and Modernizr out of our “bower_components” folder, then concatenating and minifying them into a new file named “output.min.js”. This is a great way to deploy scripts you’re managing with Bower.

Run the uglify task with:
[javascript]grunt uglify[/javascript]
You should now see a new “output.min.js” file in your “build” folder.

So far it might seem like we just replaced one command to do a certain task with another command, but what we’ve actually been doing is laying down the groundwork for where Grunt really starts to shine.

The key is Grunt’s ability to have one task run another task. So now we’re going to setup a watch task that will monitor certain files for changes, then run our stylusand jade tasks automatically for us.

Add this code:
[javascript]watch: {
stylus: {
files: [ ‘source/stylus/*.styl’ ],
tasks: [‘stylus’, ‘autoprefixer’, ‘cssmin’]
},
jade: {
files: [ ‘source/jade/*.jade’ ],
tasks: [‘jade’]
}
},[/javascript]
We’ve first added our watch task, and then inside that we’ve setup an area forstylus and for jade.

The files option in each sets which files should be watched for changes. Thetasks option sets which tasks should then be executed when changes happen, and in what order.

For stylus, we’ve set the watch task to monitor all “.styl” files in the “source/stylus” folder, and when it sees changes it will run the stylus, autoprefixer and cssmintasks in that order.

So now when the watch task is running, all you have to do is save any of your Stylus files and you’ll automatically get a compiled, autoprefixed and optimized CSS file written into the “build” folder for you.

Likewise for jade, we’ve set all “.jade” files in the “source/jade” folder to be monitored, and whenever one is saved the jade task will automatically run and compile the corresponding HTML file in the “build” .

Run the watch task with:
[javascript]watch: {
stylus: {
files: [ ‘source/stylus/*.styl’ ],
tasks: [‘stylus’, ‘autoprefixer’, ‘cssmin’]
},
jade: {
files: [ ‘source/jade/*.jade’ ],
tasks: [‘jade’]
}
},[/javascript]
Stop it again by either:

  • Closing the terminal
  • Pressing CTRL + C

At this point you might be wondering, what about the JavaScript uglify task?

The reason we didn’t include it with the watch task is you’re not going to be making changes to the jQuery and Modernizr files the uglify task is processing. So because the watch task only responds to changes it would never be triggered to process your JavaScript.

Instead, we’re going to make use of the default task that can be set in your Gruntfile. This is the task that will be run if you use the command grunt by itself with nothing appended.

After your last grunt.loadNpmTasks line, but before the closing }; of the file, add this line:

[javascript]grunt.registerTask(‘default’, [‘stylus’, ‘autoprefixer’, ‘cssmin’, ‘jade’, ‘uglify’]);[/javascript]

This sets the default task to run stylus, autoprefixer, cssmin, jade and then uglify.

So now if you run the command grunt without anything after it, it will build your entire project, including your JavaScript.


 

Getting started with Gulp

Gulp Banner

Install Gulp globally with:

[shell][sudo] npm install gulp -g[/shell]

As with the Grunt process, add a “package.json” file to your project using the npm init command.

Install Gulp into your project and save it as a development dependency with:

[shell]npm install gulp –save-dev[/shell]

Strictly speaking, Gulp doesn’t actually need to use Gulp plugins because it can actually make use of vanilla npm packages. However, there are several plugins available that are specifically optimized for use with Gulp, and when you’re starting out you’ll find these easier to use.

Search for Gulp plugins at: http://gulpjs.com/plugins/

We’ll be installing these plugins:

These plugins perform essentially the same roles as those we used with Grunt, with two differences.

One, we don’t need to install a “watch” plugin as Gulp has one built in.

Two, we’re installing the “gulp-rename” plugin because Gulp only allows you to specify a folder to compile new files into, without being able to specify the names the files should have. We’ll use this plugin to solve that problem by renaming the files we generate on the fly.

Note: we’re using a plugin named “gulp-minify-css” but it employs the same “clean-css” package you’ve used so far.

With your terminal pointed at your “Gulp Project” folder run each of these commands:

[shell]npm install gulp-stylus –save-dev[/shell]

[shell]npm install gulp-autoprefixer –save-dev[/shell]

…you get the idea by now

When you’re done, you should see these folders inside your project’s “node_modules” folder:

Directory of Gulp Packages

In a parallel to Grunt’s “Gruntfile”, Gulp uses a “Gulpfile”. To the root folder of your “Gulp Project” add a file named “gulpfile.js”.

To get started, we’ll give the file access to the “gulp” package you just installed into your “node_modules” folder, by adding this line to the top of your Gulpfile:

[javascript]var gulp = require(‘gulp’);[/javascript]

Just as we did with Grunt, we need to enable each of the plugins, this time in our Gulpfile. Instead of Grunt’s method grunt.loadNpmTasks, we’ll be using the require function native to NodeJS.

Add these lines to your Gulpfile, below the line you already added.

[javascript]
var stylus = require(‘gulp-stylus’);
var autoprefixer = require(‘gulp-autoprefixer’);
var minifyCSS = require(‘gulp-minify-css’);
var jade = require(‘gulp-jade’);
var uglify = require(‘gulp-uglify’);
var rename = require(“gulp-rename”);[/javascript]

This approach is different to Grunt in that we don’t yet have any commands registered that can be run at this stage. Rather, we’ve just created JavaScript variables, each representing our plugins, that we can employ later in our Gulpfile.

One of the main differences between Grunt and Gulp is that with Gulp you don’t need to individually configure a task for every plugin you’re using in your project. Instead, you only configure tasks for the actual commands you want to run.

In our Gruntfile earlier we setup a separate task each for Stylus, Autoprefixer and clean-css. In our Gulpfile we don’t need to do this. We know that every time we compile our Stylus code we want the resulting CSS to be autoprefixed and minified, so instead we’ll create one single task to do all these things at once.

Add this code to the bottom of your Gulpfile:

[javascript]
gulp.task(‘css’, function () {
gulp.src(‘source/stylus/main.styl’)
.pipe(stylus({compress: false, paths: [‘source/stylus’]}))
.pipe(autoprefixer())
.pipe(minifyCSS())
.pipe(rename(‘style.css’))
.pipe(gulp.dest(‘build’))
});[/javascript]
Let’s break down what we’ve done.

First, we’re using gulp.task() to define a new task named css, and making some space for a JavaScript function that will be run whenever we run the command gulp css. Next, we’re using gulp.src() to set the source file we want to process to “source/stylus/main.styl” file.

Then, we start using Gulp’s pipe() function to call on each of our plugins. The way pipe() works is like physical pipes, where you feed something into the first pipe and it then passes through every connected pipe.

Our first “pipe” adds Stylus compilation, using the same compress and paths options as we did when working with Grunt earlier. We then connect a second pipe, which takes the compiled code and adds autoprefixing, you get the jist.

Now the css task you just created is ready to go. In your project root folder run:

[shell]gulp css[/shell]

…and your Stylus file will be compiled, autoprefixed and cleaned then output to your “build” folder as “style.css”.

We’ll use the same process again to setup our task for Jade compilation. We’ll create a task named html, set it to use all the “.jade” files in the “source/jade” folder as its source, pipe through Jade compilation, then send the resulting HTML file(s) to our “build” folder.

Add this code below the css task you just created:

[javascript]

…and you’ll see each of your Jade files compiled into corresponding HTML files in your “build” folder.

Now we’re going to use the same approach one more time, setting up a task named js to take the jQuery and Modernizr files from our “bower_components” folder, uglify (concatenate and minify) them, then output the code as a file named “output.min.js” to our “build” folder.

[javascript]
gulp.task(‘js’, function() {
gulp.src([
‘bower_components/jquery/dist/jquery.js’,
‘bower_components/modernizr/modernizr.js’
])
.pipe(uglify())
.pipe(rename(‘output.min.js’))
.pipe(gulp.dest(‘build’))
});[/javascript]
Note: in this case we want to specify two source files, so we are passing the two file names as an array, i.e. comma separated values between square brackets.

Run your js task with the command:

[shell]gulp js[/shell]

…and you’ll see a new file named “output.min.js” appear in your “build” folder, containing jQuery and Modernizr in minified form.

Now that we have our custom css and html tasks setup, we can use Gulp’s in built gulp.watch() function so they’ll automatically run for us. Add this code to the bottom of your Gulpfile to create a watch task:

[javascript]
gulp.task(‘watch’, function () {
gulp.watch(‘source/stylus/*.styl’, [‘css’]);
gulp.watch(‘source/jade/*.jade’, [‘html’]);
});[/javascript]
The first use of gulp.watch() sets the css task to be run whenever a “.styl” file inside the “source/stylus” folder is changed.

The second use of gulp.watch() sets the html task to be run whenever a “.jade” file inside the “source/jade” folder is changed.

Run your watch task with the command

[shell]gulp watch[/shell]

…and whenever you save changes to one of your Stylus or Jade files your compilation will be handled automatically.

Just as we did with our Grunt project, we’ll wrap up by creating a default task that will run whenever we use the command gulp by itself. Add this line to the bottom of your Gulpfile:

[javascript]gulp.task(‘default’, [‘css’, ‘html’, ‘js’]);[/javascript]

We’re using this task to build our whole project, including the JavaScript, by having it run the csshtml and js tasks. To build your entire project with the default task use the magic word:

[shell]gulp[/shell]

In the Next Tut…

…nope. That’s all! And there you have it. Just laying a little bit of groundwork and then all you need is one word of code to build the entire project. Now you know how to install package managers, install plugins via them, use the plugins to make your life easy and then get more efficient (lazy 😉 ) by automating that process as well.

There’s a lot more you can do with these “command line toys” but I aimed to provide a beginner crash course at using command line package managers to make the redundant task of preparing your project for deployment a breeze.

Hope you liked it. Have a good one.

Share Your Thoughts

Copyright © 2011, 2016 - BWD MEDIA
Web Design & Digital Marketing Agency
Call Now Enquire