Gulp for Beginners

Share this:

Gulp is a tool that helps you out with several tasks when it comes to web development. It's often used to do front end tasks like:

Spinning up a web server

Reloading the browser automatically whenever a file is saved

Using preprocessors like Sass or LESS

Optimizing assets like CSS, JavaScript, and images

This is not a comprehensive list of things Gulp can do. If you're crazy enough, you can even build a static site generator with Gulp (I've done it!). So yes, Gulp is extremely powerful, but you'll have to learn how to use Gulp if you want to create your own customized build processes.

So that's what this article is for. It helps you get so good with the basics of Gulp that you can begin exploring everything else for yourself.

Before we dive into working with Gulp, let's talk about why you may want to use Gulp as opposed to other similar tools.

Why Gulp?

Tools like Gulp are often referred to as "build tools" because they are tools for running the tasks for building a website. The two most popular build tools out there right now are Gulp and Grunt. (Chris has a post on getting started with Grunt here). But there are others of course. Broccoli focuses on asset compilation, one of the most common build tool tasks.

There are already multiple articles covering the difference between Grunt and Gulp and why you might use one over another. You can check out this article, this one, or this if you're interested in finding out more. Brunch is similar in its focus on assets, and it bundles in some of the most common other tasks like a server and file watcher.

The main difference is how you configure a workflow with them. Gulp configurations tend to be much shorter and simpler when compared with Grunt. Gulp also tends to run faster.

Let's now move on and find out how to setup a workflow with Gulp.

What we're setting up

By the end of this article, you'll have a workflow that does the tasks we outlined at the beginning of this article:

Spins up a web server

Compiles Sass to CSS

Refreshes the browser automatically whenever you save a file

Optimizes all assets (CSS, JS, fonts, and images) for production

You'll also learn how to chain together different tasks into simple commands that are easy to understand and execute.

Let's begin by installing Gulp onto your computer.

Installing Gulp

You need to have Node.js (Node) installed onto your computer before you can install Gulp.

When you're done with installing Node, you can install Gulp by using the following command in the command line:

$ sudo npm install gulp -g

Note: Only Mac users need the sudo keyword. (See the first comment by Pawel Grzybek if you don't want to use sudo). And remember the "$" in the code above just symbolizes the command prompt. That's not actually part of the command you run.

The -g flag in this command tells npm to install Gulp globally onto your computer, which allows you to use the gulp command anywhere on your system.

Mac users need the extra sudo keyword in the command because they need administrator rights to install Gulp globally.

Now that you have Gulp installed, let's make a project that uses Gulp.

Creating a Gulp Project

First, we'll create a folder called project to server as our project root as we move through this tutorial. Run the npm init command from inside that directory:

# ... from within our project folder
$ npm init

The npm init command creates a package.json file for your project which stores information about the project, like the dependencies used in the project (Gulp is an example of a dependency).

npm init will prompt you:

Once the package.json file is created, we can install Gulp into the project by using the following command:

$ npm install gulp --save-dev

This time, we're installing Gulp into project instead of installing it globally, which is why there are some differences in the command.

You'll see that the sudo keyword isn't required because we're not installing Gulp globally, so -g is also not necessary. We've added --save-dev, which tells the computer to add gulp as a dev dependency in package.json.

If you check the project folder when the command has finished executing, you should see that Gulp has created a node_modules folder. You should also see a gulp folder within node_modules.

We're almost ready to start working with Gulp. Before we do so, we have to be clear on how we're going to use Gulp for the project, and part of that is deciding on a directory structure.

Determining Folder Structure

Gulp is flexible enough to work with any folder structure. You'll just have to understand the inner workings before tweaking it for your project.

We'll need to provide the sass task with source files and a destination for the task to work, so let's create a styles.scss file in the app/scss folder. This file will be added to the sass task in gulp.src.

We want to output the eventual styles.css file to the `app/css` folder, which would be the destination for gulp.dest.

We'll want to test that the sass task is working as we want it to. To do so, we can add a Sass function within styles.scss.

// styles.scss
.testing {
width: percentage(5/7);
}

If you run gulp sass in the command line, you should now be able to see that a styles.css file was created in app/css. In addition, it has the code where percentage(5/7) was evaluted into 71.42857%.

/* styles.css */
.testing {
width: 71.42857%;
}

That's how we know that the sass task works!

Sometimes we need the ability to compile more than one .scss file into CSS at the same. We can do so with the help of Node globs.

FYI: Gulp-sass uses LibSass to convert Sass into CSS. It's much quicker than Ruby-based methods. If you want, you can still use Ruby methods with Gulp by using gulp-ruby-sass or gulp-compass instead.

Globbing in Node

Globs are matching patterns for files that allow you to add more than one file into gulp.src. It's like regular expressions, but specifically for file paths.

When you use a glob, the computer checks file names and paths for the specified pattern. If the pattern exists, then a file is matched.

Most workflows with Gulp tend to only require 4 different globbing patterns:

*.scss: The * pattern is a wildcard that matches any pattern in the current directory. In this case, we’re matching any files ending with .scss in the root folder (project).

**/*.scss: This is a more extreme version of the * pattern that matches any file ending with .scss in the root folder and any child directories.

!not-me.scss: The ! indicates that Gulp should exclude the pattern from its matches, which is useful if you had to exclude a file from a matched pattern. In this case, not-me.scss would be excluded from the match.

*.+(scss|sass): The plus + and parentheses () allows Gulp to match multiple patterns, with different patterns separated by the pipe | character. In this case, Gulp will match any file ending with .scss or .sass in the root folder.

Since we know about globbing now, we can replace app/scss/styles.scss with a scss/**/*.scss pattern, which matches any file with a .scss extension in app/scss or a child directory.

Any other Sass file that's found within app/scss would automatically be included into the sass task with this change. If you add a print.scss file into the project, you'll see that print.css will be generated in app/css.

We've now managed to compile all Sass files into CSS files with a single command. The question is, what good does it do if we have to run gulp sass manually every time we want to compile Sass into CSS?

Luckily, we can tell Gulp to automatically run the sass task whenever a file is saved through a process called "watching".

Watching Sass files for changes

Gulp provides us with a watch method that checks to see if a file was saved. The syntax for the watch method is:

You may have noticed that there isn't a gulp- prefix when we install Browser Sync. This is because Browser Sync works with Gulp, so we don't have to use a plugin.

To use Browser Sync, we'll have to require Browser Sync.

var browserSync = require('browser-sync').create();

We need to create a browserSync task to enable Gulp to spin up a server using Browser Sync. Since we're running a server, we need to let Browser Sync know where the root of the server should be. In our case, it's the `app` folder:

We're done with configuring Browser Sync. Now, we have to run both the watch and browserSync tasks at the same time for live-reloading to occur.

It'll be cumbersome to open up two command line windows and run gulp browserSync and gulp watch separately, so let's get Gulp to run them together by telling the watch task that browserSync must be completed before watch is allowed to run.

We can do so by adding a second argument to the watch task. The syntax is:

Now, if you run gulp watch in the command line, Gulp should start both the sass and browserSync tasks concurrently. When both tasks are completed, watch will run.

At the same time, a browser window that points to app/index.html would also pop up. If you change the styles.scss file, you'll see that the browser reloads automatically.

There's one more thing before we end this live-reloading section. Since we're already watching for .scss files to reload, why not go a step further and reload the browser if any HTML or JavaScript file gets saved?

We can do so by adding two more watch processes, and calling the browserSync.reload function when a file gets saved:

<type> can either be js, css, or remove. It's best to set type to the type of file that you're trying to concatenate. If you set type to remove, Gulp will remove the entire build block without generating a file.

<path> here refers to the target path of the generated file.

We'll want the final JavaScript file to be generated in the js folder, as main.min.js. Hence, the markup would be:

Now if you run this useref task, Gulp will take run through the 3 script tags and concatenate them into dist/js/main.min.js.

The file however, isn't minified right now. We'll have to use the gulp-uglify plugin to help with minifying JavaScript files. We also need a second plugin called gulp-if to ensure that we only attempt to minify JavaScript files.

Gulp should now automatically minify the `main.min.js` file whenever you run the useref task.

One neat thing I've yet to reveal with Gulp-useref is that it automatically changes all the scripts within "<!--build:" and "<!--endbuild-->" into one single JavaScript file that points to `js/main.min.js`.

Wonderful, isn't it?

We can use the same method to concatenate any CSS files (if you decided to add more than one) as well. We'll follow the same process and add a build comment.

Combining Gulp tasks

Let's summarise what we've done. So far, we have created two distinct sets of Gulp tasks.

The first set is for a development process, where we compiled Sass to CSS, watched for changes, and reloaded the browser accordingly.

The second set is for an optimization process, where we ready all files for the production website. We optimized assets like CSS, JavaScript, and images in this process and copied fonts over from app to dist.

We've already grouped the first set of tasks together into a simple workflow with the gulp watch command:

In this case, Gulp first runs task-one. When task-one is completed, Gulp runs every task in the second argument simultaneously. All tasks in this second argument must be completed before task-three is run.

So we can now create a task that ensures that clean:dist runs first, followed by all the other tasks:

Wrapping it up

We've gone through the absolute basics of Gulp and created a workflow that's able to compile Sass into CSS while watching HTML and JS files for changes at the same time. We can run this task with the gulp command in the command line.

We've also built a second task, build, that creates a dist folder for the production website. We compiled Sass into CSS, optimized all our assets, and copied the necessary folders into the dist folder. To run this task, we just have to type gulp build into the command line.

Lastly, we have a clean task that clears away from the generated dist folder any image caches that are created, allowing us to remove any old files that were inadvertently kept in dist.

We've created a robust workflow so far that's capable enough for most web developers. There's a lot more to Gulp and workflows that we can explore to make this process even better. Here are some ideas for you:

In addition to development or optimization processes, you can also add write JavaScript unit tests with gulp-jasmine and even deploy your dist folder onto your production server automatically with gulp-rync.

As you can see, even though the workflow we've created does quite a few things, there's a lot more that can be done. Creating a workflow that suits your needs can be extremely exciting and fulfilling, but it can be a lot to take in if you're new to this.

There's so much more to Gulp that it's impossible to cover within this blog post, or even a series of posts. That's why I wrote a book on automating your workflow, and I invite you to grab ten chapters for free if you're interested in finding out more :)

Let me know what you felt about this article in the comments below! Oh yes, feel free to contact me if you have any questions on workflow. I'll be happy to reply!

Hey! I love this tutorial and i plan on creating my own gulp workflow soon. I have a quick question on the browsersync watch feature. If Im working on a WordPress project I would need it to watch for changes in my .php files correct? So would I change this:
gulp.watch(‘app/.html’, browserSync.reload);
to this?:
gulp.watch(‘app/.php’, browserSync.reload);
Cant wait to get started with Gulp :)

There’s one more thing. If you’re on WordPress you’ll probably be using MAMP as your server, so you need to you point browserSync to your server with the proxy key. Check out the free sample chapters of my book for more info :)

Great article – a lot of useful information presented in a way that should make sense to beginners and experienced developers alike.

I noticed that in the first couple of examples (i.e. the Sass stuff) you’re not returning anything from the gulp task, and you’re not calling the callback argument. By not doing either of those two things, gulp will not know when the task has truly completed, which is no good if it’s used as a dependency of another task.

I also noticed that you’re using runSequence, which usually isn’t necessary (in fact, as per the author, the whole thing is a temporary hack). It’s especially important for a beginner to understand that gulp tasks are just regular JavaScript functions. You can compose them as you would any other JavaScript function:

The key thing to remember, as pointed out previously, is to handle asynchronous tasks correctly.

Another thing to think about is organizing your gulpfile.js, especially across different projects. It’s possible to create your own npm package so that you can manage your gulpfile.js in a central place, rather than copy-pasting it each time. This is what we’ve done with our asset pipeline, which may serve as a good example if you’re interested in setting up your own. Another great example is Laravel’s Elixir.

Missed out on the returns. Contacting Chris to correct it now
Yeah I understand it’s a hack, but it’s so much simpler compared to writing async example you’ve just written. Besides, when Gulp 4 comes out, they’re gonna use a similar syntax. IMO, doesn’t hurt too much :)
Great idea about publishing NPM package for synchronised Gulpfiles. Wonderful stuff that I didn’t think about! Thanks! :)

Thanks for the article. Which clearly expalins the gulp without comparing its peer grunt. I have doubt Here why callback is used in some task function and how to use task:varianttask i am new to this gulp.

The callback is used to tell gulp.js that the task is done. This is important for asynchronous tasks which may past the duration of the task functions itself. See the gulp.js docs on asynchronous tasks.task and task:subTaskare both just task identifiers (the colon doesn’t mean anything to gulp.js). Some people like to use a colon to group tasks with related tasks.

Great article. I just built my first gulpfile yesterday and this covered a lot of things I learned by googling around. Haha. Thanks for writing it. It gave me some good ideas for further optimization. I already knew Grunt but I’m liking gulp better.

Maybe a repeat comment but yeah, with Homebrew installed, no need to sudo for npm -g installs. I’m a full-time Grunt user but I appreciate you covering Gulp in depth in case I end up on a project that uses it in the build process. Good job!

Can you confirm whether what Mitranim said is true? I haven’t played with gulp 4.0 yet myself, and I’m not sure how much it affects the workflow I’ve spelled out here. (Probably only the run-sequence part though)

I can’t have ‘clean:dist’ task to work. I’ve installed del@1.2.1, as Zell points out, but the task isn’t working. When I type ‘gulp clean:dist’, it deletes everything inside the ‘dist’ directory, also the images folder.

You should be using gulp 4.0 (alpha) and the third party gulp-watch library instead of gulp 3.x and gulp.watch recommended by this post. gulp 4.0 has built-in methods to explicitly run tasks in sequence or parallel, and gulp-watch notices files added while the build system is running.

This is awesome! One question, how can I compress the compiled css with gulp sass? I looked at the documentation and tried it myself but the compiled css doesn’t result compressed. This is how I tried it:

“First, we’ll create a folder called project to server as our project root as we move through this tutorial. Run the npm init command from inside that directory:”

How does that bash command know where the folder is? Do you need a pathname? As Zell points out, Mac users are often using MAMP, but I can’t find any info about how to run that actual command in your tutorial…

How’s going plugin’s updating, once package.json is aging? I’ve tried $npm i and $npm i –save-dev. All plugins of my package.json remain the same outdated version comparing to your, a bit fresher ones…

Two more Qs, please:
1) What’s ‘sass’ function doing in ‘build’ task? By that time everything is supposed to be compiled, as for me.
2) Should I have all .html files at the root folder “app” to run ‘useref’ correctly? Can I put all .html but not index.html to html folder?

There may be times where changes are made, but are not compiled yet. Placing sass in the build task ensures that it’s definitely compiled.
Yes you can, just use the node globs to get it. You’ll have to be careful about the paths to your CSS and JavaScript files though

Hey thanks for this tutorial, it’s been really useful!
I could setup everything successfully and created a task ‘gulp’ for doing everything. The only thing I see on the console is that when the build process is running i cannot stop it via Ctrl+C like I do with other gulp processes I used for other projects. The process is stopped but the console only show this: (^C^C^C^C)

There are a few plugins, like ‘uncss’ to delete idle css. Grate idea! Is there any confidence about preserving ‘idle css’ for html but, at the same time, active for .js? Does ‘uncss’ and alike take into account link to .js to inspect usefulness of styles?

OK,ok, Zell, grate job! Seems there is a whole bunch of reasons to write even more advanced blog.
Could I be perfectly sure, after scss to css compilation, of pure valid css outcome from w3c point of view? Sounds logical…
But html validation may come to play.

Great article. I’ve been avoiding task-runners in node for the longest time because I’ve disliked the cognitive load, so I’ve been doing everything task related in ruby… but I am much happier to be moving over to gulp, and this article was a fantastic tool for doing that.

One minor nitpick.. when setting up my app structure I just did $touch index.html, leading to a disconnect as there was no HTML in the file. It may be worth adding a little to the preamble around creating the initial HTML.

Never mind, I read over the bit where you use gulp-useref to do that, sorry about that.

I do have another question however. When developing, do you test unminified and unconcatenated files from the app or the dist directory? In some cases I’ve run into scenarios where both minified and unminified files were written to the dist directory and I assume that files are tested from there and only the minified files are used in production. What is best practice?

I test from the app directory as much as possible since that’s the source code. There’s no real “best practice” at all. It all depends on what you believe in, and from that believe, you’ll adjust your own workflow accordingly.

This is probably a little too much to talk about in a comment though. I’ve covered it extensively in the book I’ve written and I thought I’d just refer you there. Just get the sample chapters and you’ll have a feel of what I believe in.

It puts the index.html in the dist folder, but there isn’t any ‘main.min.js’ generated, like the post says. Where could I have gone wrong, I’ve been over the code several times and I believe it’s identical.

The gulp-useref plugin doesn’t log anything to the command line so that’s normal. doesn’t It’s likely that you’ve made a small mistake somewhere. Please put a a github repo and send me a link via email. I’ll take a look at it.

Hey Zell, thanks for great article, I’m starting using gulp thanks to you.
I’m used to have “assets” folder for css, js, images and fonts. I have a problem with useref. I want my css and js to go to dist/assets and html to dist folder but I’m not sure if I can add two destinations. I don’t like hacky ways where I can create task for copying css and js to dist, and then task for deleting them from dist. Is there some simple solution for this?

1) You didn’t use –save-dev when installing gulp-minify-css. Did you do that on purpose or was it just a mistake?

2) When I use the build command, gulp creates a dist folder and copies all files where they’re supposed to be. So far so good. But when I run the build command a second time, Gulp just deletes the dist folder (as its supposed to do) and that’s it. It does not create a new one.

My clean task looks like this (I don’t manipulate the images and therefor went without the cache stuff):

👋

CSS-Tricks* is created, written by, and maintained by Chris Coyier and a team of swell people. It is built on WordPress and powered up by Jetpack. It is made possible through sponsorships from products and services we like.