Web and Native Technologies

Gulp.js

Today is an awesome day because I stumbled across something super awesome. To be honest, I didn’t even know how useful it was until now. Now that I started going over it and tried to understand it, I saw how it resembled the asset pipeline in rails. The asset pipeline can concatenate, minify and rename your files. But guess what? Yup, so can gulp. Okay, let’s dive in!

The first thing you have to do is install node.js and it’s package manager (npm).

You will also need a server of some sort to run your app. Python comes with a simple server. If you don’t want to use that, there is one you can install with npm called http-server.

npm init (initializes folder as a node package using a package.json file)

This will then have a little section in your terminal where you will have to fill in some info like the name, version, description and git repo.

Now that we have that set up, it’s time to install gulp.

npm install gulp --save-dev (only available in the current project)
adds gulp to projects development dependencies

npm install -g gulp (also so it can be available system wide)

Now, that we have gulp, we have to create the main file (gulpfile.js) in the root directory. This is where all of our code will go.

Below is a sample gulp task:


// gulpfile.js

'use strict'

var gulp = require('gulp')

gulp.task('flatiron', function() {

console.log("Hello from The Flatiron School!");

})

The syntax is not that crazy. Just type gulp flatiron in terminal to run the task. You can also create a custom task called Default which is a special task that runs when gulp is invoked with no task names in the terminal. Then we add all of the dependencies – like in rake. It will load and run all those dependencies first before running the default code, which in this case will run flatiron.

gulp.task('default', console.log()["flatiron"], function(){

console.log("Inside default");

})

This is all pretty cool, but there is not need to re-invent the wheel when creating our own tasks. Gulp plugins to the rescue! Gulp plugins are basically third party libraries to make your life easier (just like ruby gems.)

The first plugin we will look at is gulp-concat:

npm install gulp-concat --save-dev

This plugin concatenates all your files into only one file file, which in my opinion is pretty awesome.

After installing the plugin, we have to require it:

concat = require("gulp-concat")

After requiring the plugin, we can finally start coding our task:

gulp.task("concatScripts", function() {

gulp.src(['js/jquery.js', 'js/folder/file.js', 'js/main.js']) //can take an array of filenames or a string for a filename (src puts the results in memory. WIll have to pipe it to places we want) BTW ORDER MATTERS

}).pipe(concat('app.js')) //sends the data from the src to the concat task. The concat task takes a parameter for the name of the file it will create

.pipe(gulp.dest('js')) //pipes the data to the dest task which writes it to disk in a folder to which it should write it to
})

Here, we gave gulp a list of files that we would want to concatenate. App.js will be the file that has all the concatenated files.

Step one is complete! Now onto step two, where we will minify our concatenated file!

First, install the uglifier node package:

npm install gulp-uglify --save-dev

then require it

uglify = require("gulp-uglify")

After installing and requiring the plugin, just like we did with the first plugin, we can now begin our task:

gulp.task("minifyScripts", function() {

gulp.src("app.js") // the result of the concat task

.pipe(uglify()) // pass it to the uglify method

.pipe(gulp.dest("js")) // save it to the js folder

})

This will minify the files you pass gulp in the src() method and save it in a folder, which we have to specify in the dest() method.

We are almost there! Now, that we can finally concatenate and minify our files, we will have to rename it so we can have exampleFile.js and exampleFile.min.js. There is a cool plugin we can use to achieve this called rename`. Installing it is the same as before:

npm install gulp-rename --save-dev

We can now require it:

rename = require("gulp-rename")

After all that is done, we can then add `pipe(rename("app.min.js"))` right after the uglify method. So, now the minify task should look like this:


gulp.task("minifyScripts", function() {

gulp.src("app.js") // the result of the concat task

.pipe(uglify()) // pass it to the uglify method

pipe(rename("app.min.js"))

.pipe(gulp.dest("js")) // save it to the js folder

})

Now, looking at these tasks shouldn't be so difficult. The syntax is pretty straightforward, and you really don't need to create your own tasks because chances are what you are trying to build has already been made by someone else.

Let's do a little more with gulp, since we all know how fun it can be now.

It's time for compiling sass with gulp!!

Sass (syntactically awesome style sheets) is growing in popularity and it's actually easier to learn as well as more efficient to use since it keeps our code dry.

We already know the pattern now. Yup, that's right. Time to install the sass plugin:

npm install gulp-sass --save-dev

Then we require it as usual:

sass = require("gulp-sass")

Now, we can create a new sass task:


gulp.task("compileSass", function(){

gulp.src("scss/application.scss") //Its good practice to import sass files into one another so that way you only have to specify one sass file to gulp

.pipe(sass())

.pipe(gulp.dest('css'))

 

})

To run the task, simply type:

gulp compileSass

Now time to add source maps. It basically adds a way for you debug your code easier by knowing what is happening on what line in the developer tools. When you open the elements tab on the developer console (I'm using chrome), you can see all the styles related to any DOM element selected. You should then be able to see the exact file name name and line number for each style on the right hand pane. If you did not have source maps, then debugging would become a nightmare because it will only point to one gigantic file if you have concatenated them, and there will be no way to quickly and efficiently go and add changes to that file.

First, let's install it:

npm install gulp-sourcemaps --save-dev

Then, require it in your gulp file:

maps = require("gulp-sourcemaps")

Now, we can call the maps.init() method to start the magic:

Let's go back to the sass task and add this:


gulp.task("compileSass", function(){

gulp.src("scss/application.scss")

.pipe(maps.init())

.pipe(sass())

.pipe(gulp.dest('css'))

})

Next we need to add the write() method, which takes one parameter of the path to where it should write the source map to, relative to the dest() gulp method.


gulp.task("compileSass", function(){

gulp.src("scss/application.scss")

.pipe(maps.init())

.pipe(sass())

.pipe(maps.write("./")) // Tells gulp to write this source map in the same directory as the css

.pipe(gulp.dest('css'))

})

Source maps are not only limited to css source maps, we can also have javascript source maps.

Lets revisit the concat scripts task and adds maps just like we did for the css:


gulp.task("concatScripts", function() {

gulp.src(['js/jquery.js', 'js/folder/file.js', 'js/main.js'])

.pipe(maps.init())

.pipe(concat('app.js'))

.pipe(maps.write("./")) //

.pipe(gulp.dest('js'))

})

Now time for gulp to do it's magic and run all the scripts at once for us!

gulp.task("build", ["concatScripts, "uglifyScripts", "compileSass"]);

Gulp will run all the dependencies in parallel, which is not really what we want, because we have tasks that depend on other tasks, so that will obviously be bad. In order to stop the gulp engine from doing this, we will need to make it run the tasks serially.

We already know what the order in which the tasks need to be run in, so the process is fairly simple. If concatScripts needs to run before minifyScripts, then all we need to do is add concatScripts as a dependency to the minifyScripts. That way, minify will run concat first, before it runs itself the same way we did with the default task.

The minify scripts task should now look like this:


gulp.task("minifyScripts", ["concatScripts"], function() {

gulp.src("app.js")

.pipe(uglify())

pipe(rename("app.min.js"))

.pipe(gulp.dest("js"))

})

Now, you would normally think we're done right? But WRONG! There is a super important part to truly make this task depend on another task. And that is to explicitly return the dependent task or all the other tasks will still start right away instead of waiting for the concat scripts to finish.

gulp.task("concatScripts", function() {

<strong>return</strong> gulp.src(['js/jquery.js', 'js/folder/file.js', 'js/main.js'])

.pipe(maps.init())

.pipe(concat('app.js'))

.pipe(maps.write("./")) //

.pipe(gulp.dest('js'))

})

Now, we can safely remove concatScripts from the build task, since it is a dependent of the minifyScripts task. So now our build task should look like this:

gulp.task("build", ["minifyScripts", "compileSass"]);

But, wait. There's more. If concatScripts was a dependent of minifyScripts, then that means minifyScripts and compileSass are also dependents of the build task, so we will have to add a return statement to them as well. Now all of our code should look like this:

gulp.task("concatScripts", function() {

return gulp.src(['js/jquery.js', 'js/folder/file.js', 'js/main.js'])

.pipe(maps.init())

.pipe(concat('app.js'))

.pipe(maps.write("./")) //

.pipe(gulp.dest('js'))

})

gulp.task("minifyScripts", ["concatScripts"], function() {

return gulp.src("app.js") // check if it's 'js/app.js instead'

.pipe(uglify())

pipe(rename("app.min.js"))

.pipe(gulp.dest("js"))

})

gulp.task("compileSass", function(){

gulp.src("scss/application.scss")

.pipe(maps.init())

.pipe(sass())

.pipe(maps.write("./"))

.pipe(gulp.dest('css'))

})


gulp.task("build", ["minifyScripts", "compileSass"]);

Now, you may ask what was the default task for? Well, it was useless, haha. But, if you don't want to type 'gulp build' to the console every time, you can simply add build as a dependent to the default task, and then all you would need to do is run 'gulp' on your terminal.

gulp.task('default', console.log()["build"], function(){

// Do some other cool stuff here

})

It's recommended to make everything production ready with the default task, so that other developers just need to run one line of code to get everything working.

And now we are done!

BONUS:

A really cool thing you can do with gulp, is make it literally do whatever you want, without you having to explicitly tell it to. What I mean by this is, if you want to, you don't even have to write gulp in the terminal. You can make gulp automatically run your tasks just by making a small change in any of your files that are being 'watched'. In order to illustrate this. Let's see how this would look:

gulp.task("watchFiles", function(){

gulp.watch(["filename1", "filename2", "..."], [taskToRunAfterChange])

})

So let's say I wanted to run a task called automateScripts which would watch a scripts directory with multiple directories inside that which also had multiple javascript files. This can be achieved by using glob patterns, which is basically like a regex to match all cases.

gulp.task("watchFiles", function(){

gulp.watch(["scripts/**/*.js"], [automateScripts])

})

You can easily see how you can apply this to automate all of your tasks within a project. If you are using rails, you probably don't need this since it uses the asset-pipeline, but if you are building your own web-app from scratch or anything that involves tasks without a robust framework like rails, then this would be a perfect solution to many of your problems!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s