DigitalOcean provides cloud products for every stage of your journey. Get started with$200 in free credit!
Gulpis 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
Important Note!This article was written for Gulp 3.x, but now Gulp 4.x is out and recommended. Like any major version change, APIs have breaking changes. If you install Gulp 4 and try to do some of the things in this article, they won’t work. We’ll make some notes of that sprinkled through here to remind you.This looks like a pretty good Gulp 4 starter.
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 touseGulp 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 aboutwhyyou 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 andGrunt. (Chris has apost on getting started with Grunt here). But there are others of course.Broccolifocuses 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 outthis article,this one, orthisif you’re interested in finding out more.Brunchis 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 tochain togetherdifferent 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 commentby 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.
Thenpm installcommand we’ve used here is a command that uses Node Package Manager (npm) to install Gulp onto your computer.
The-gflag in this command tells npm to install Gulp globally onto your computer, which allows you to use thegulpcommand anywhere on your system.
Mac users need the extrasudokeyword 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 calledprojectto server as our project root as we move through this tutorial. Run thenpm initcommand from inside that directory:
# ... from within our project folder$ npm init
Thenpm initcommand creates apackage.jsonfile for your project which stores information about the project, like thedependenciesused in the project (Gulp is an example of a dependency).
npm initwill prompt you:
Once thepackage.jsonfile 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 intoprojectinstead of installing it globally, which is why there are some differences in the command.
You’ll see that thesudokeyword isn’t required because we’re not installing Gulp globally, so-gis also not necessary. We’ve added--save-dev, which tells the computer to addgulpas a dev dependency inpackage.json.
If you check the project folder when the command has finished executing, you should see that Gulp has created anode_modulesfolder. You should also see agulpfolder withinnode_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.
For this article, we will use the structure of a generic webapp:
In this structure, we’ll use theappfolder for development purposes, while thedist(as in “distribution”) folder is used to contain optimized files for the production site.
Sinceappis used for development purposes, all our code will be placed inapp.
We’ll have to keep this folder structure in mind when we work on our Gulp configurations. Now, let’s begin by creating your first Gulp task ingulpfile.js, which stores all Gulp configurations.
Writing Your First Gulp Task
The first step to using Gulp is torequireit in the gulpfile.
var gulp = require('gulp');
The require statement tells Node to look into thenode_modulesfolder for a package namedgulp. Once the package is found, we assign its contents to the variablegulp.
We can now begin to write a gulp task with thisgulpvariable. The basic syntax of a gulp task is:
task-namerefers to the name of the task, which would be used whenever you want to run a task in Gulp. You can also run the same task in the command line by writinggulp task-name.
To test it out, let’s create ahellotask that saysHello Zell!.
We can run this task withgulp helloin the command line.
$ gulp hello
The command line will return a log that saysHello Zell!.
Gulp tasks are usually a bit more complex than this. It usually contains two additional Gulp methods, plus a variety of Gulp plugins.
Here’s what a real task may look like:
gulp.task('task-name', async function () {return gulp.src('source-files') // Get source files with gulp.src.pipe(aGulpPlugin()) // Sends it through a gulp plugin.pipe(gulp.dest('destination')) // Outputs the file in the destination folder})
As you can see, a real task takes in two additional gulp methods —gulp.srcandgulp.dest.
gulp.srctells the Gulp task what files to use for the task, whilegulp.desttells Gulp where to output the files once the task is completed.
Let’s try building a real task where we compile Sass files into CSS files.
Preprocessing with Gulp
We can compile Sass to CSS in Gulp with the help of a plugin calledgulp-sass. You can install gulp-sass into your project by using thenpm installcommand like we did forgulp.
We’d also want to use the--save-devflag to ensure that gulp-sass gets added todevDependenciesinpackage.json.
$ npm install gulp-sass --save-dev
We have torequiregulp-sass from thenode_modulesfolder just like we did withgulpbefore we can use the plugin.
var gulp = require('gulp');// Requires the gulp-sass pluginvar sass = require('gulp-sass');
We can use gulp-sass by replacingaGulpPlugin()withsass(). Since the task is meant to compile Sass into CSS, let’s name itsass.
gulp.task('sass', async function(){return gulp.src('source-files').pipe(sass()) // Using gulp-sass.pipe(gulp.dest('destination'))});
We’ll need to provide thesasstask with source files and a destination for the task to work, so let’s create astyles.scssfile in theapp/scssfolder. This file will be added to thesasstask ingulp.src.
We want to output the eventualstyles.cssfile to theapp/cssfolder, which would be thedestinationforgulp.dest.
gulp.task('sass', async function(){return gulp.src('app/scss/styles.scss').pipe(sass()) // Converts Sass to CSS with gulp-sass.pipe(gulp.dest('app/css'))});
We’ll want to test that thesasstask is working as we want it to. To do so, we can add a Sass function withinstyles.scss.
// styles.scss.testing {width: percentage(5/7);}
If you rungulp sassin the command line, you should now be able to see that astyles.cssfile was created inapp/css. In addition, it has the code wherepercentage(5/7)was evaluted into71.42857%.
/* styles.css */.testing {width: 71.42857%; }
That’s how we know that thesasstask works!
Sometimes we need the ability to compile more than one.scssfile 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 usinggulp-ruby-sassorgulp-compassinstead.
Globbing in Node
Globs are matching patterns for files that allow you to add more than one file intogulp.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.scssin the root folder (project).
**/*.scss: This is a more extreme version of the*pattern that matches any file ending with.scssin 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.scsswould 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.scssor.sassin the root folder.
Since we know about globbing now, we can replaceapp/scss/styles.scsswith ascss/**/*.scsspattern, which matches any file with a.scssextension inapp/scssor a child directory.
gulp.task('sass', async function() {return gulp.src('app/scss/**/*.scss') // Gets all files ending with .scss in app/scss and children dirs.pipe(sass()).pipe(gulp.dest('app/css'))})
Any other Sass file that’s found withinapp/scsswould automatically be included into thesasstask with this change. If you add aprint.scssfile into the project, you’ll see thatprint.csswill be generated inapp/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 rungulp sassmanually every time we want to compile Sass into CSS?
Luckily, we can tell Gulp to automatically run thesasstask whenever a file is saved through a process called “watching”.
Watching Sass files for changes
Note! Gulp Watch was one of the things that changed a lot from 3.x to 4.x.See the docs.
Gulp provides us with awatchmethod that checks to see if a file was saved. The syntax for thewatchmethod is:
// Gulp 3.x watch syntaxgulp.watch('files-to-watch', ['tasks', 'to', 'run']);// NOTE! Gulp 4.x watch syntax (all the rest of the examples would need to be like this for Gulp 4gulp.watch('files-to-watch', gulp.series(['tasks', 'to', 'run']));
If we want to watch all Sass files and run thesasstask whenever a Sass file is saved, we just have to replacefiles-to-watchwith theapp/scss/**/*.scss, and['tasks', 'to', 'run']with['sass']:
More often though, we’ll want to watch more than one type of file at once. To do so, we can group together multiple watch processes into awatchtask:
gulp.task('watch', async function(){gulp.watch('app/scss/**/*.scss', ['sass']); // Other watchers})
If you ran thegulp watchcommand right now, you’ll see that Gulp starts watching immediately.
And that it automatically runs thesasstask whenever you save a.scssfile.
Let’s take it a step further and make Gulp reload the browser whenever we save a.scssfile with the help ofBrowser Sync.
Live-reloading with Browser Sync
Browser Sync helps make web development easier by spinning up a web server that helps us do live-reloading easily. It has other features, likesynchronizing actions across multiple devices, as well.
We’ll first have to install Browser Sync:
$ npm install browser-sync --save-dev
You may have noticed that there isn’t agulp-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 torequireBrowser Sync.
var browserSync = require('browser-sync').create();
We need to create abrowserSynctask 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 theappfolder:
We also have to change oursasstask slightly so Browser Sync can inject new CSS styles (update the CSS) into the browser whenever thesasstask is ran.
gulp.task('sass', async function() {return gulp.src('app/scss/**/*.scss') // Gets all files ending with .scss in app/scss.pipe(sass()).pipe(gulp.dest('app/css')).pipe(browserSync.reload({stream: true}))});
We’re done with configuring Browser Sync. Now, we have to run both thewatchandbrowserSynctasks at the same time for live-reloading to occur.
It’ll be cumbersome to open up two command line windows and rungulp browserSyncandgulp watchseparately, so let’s get Gulp to run them together by telling thewatchtask thatbrowserSyncmust be completed beforewatchis allowed to run.
We can do so by adding a second argument to thewatchtask. The syntax is:
And in this case we’re adding the browserSync task.
gulp.task('watch', ['browserSync'], async function (){gulp.watch('app/scss/**/*.scss', ['sass']); // Other watchers})
We’ll also want to make suresassruns beforewatchso the CSS will already be the latest whenever we run a Gulp command.
gulp.task('watch', ['browserSync', 'sass'], async function (){gulp.watch('app/scss/**/*.scss', ['sass']); // Other watchers});
Now, if you rungulp watchin the command line, Gulp should start both thesassandbrowserSynctasks concurrently. When both tasks are completed,watchwill run.
At the same time, a browser window that points toapp/index.htmlwould also pop up. If you change thestyles.scssfile, 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.scssfiles 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 thebrowserSync.reloadfunction when a file gets saved:
gulp.task('watch', ['browserSync', 'sass'], async function (){gulp.watch('app/scss/**/*.scss', ['sass']); // Reloads the browser whenever HTML or JS files changegulp.watch('app/*.html', browserSync.reload); gulp.watch('app/js/**/*.js', browserSync.reload); });
So far in this tutorial we’ve taken care of three things:
Spinning up a web server for development
Using the Sass preprocessor
Reloading the browser whenever a file is saved
Let’s cover the part on optimizing assets in the next section. We’ll start with optimizing CSS and JavaScript files.
Optimizing CSS and JavaScript files
Developers have two tasks to perform when we try to optimize CSS and JavaScript files for production: minification and concatenation.
One problem developers face when automating this process is that it’s difficult to concatenate your scripts in the correct order.
These scripts are located in two different directories. It’ll be difficult to concatenate them with traditional plugins likegulp-concatenate.
Thankfully, there’s a useful Gulp plugin,gulp-userefthat solves this problem.
Gulp-useref concatenates any number of CSS and JavaScript files into a single file by looking for a comment that starts with “<!–build:” and ends with “<!–endbuild–>”. Its syntax is:
... HTML Markup, list of script / link tags.
can either bejs,css, orremove. It’s best to settypeto the type of file that you’re trying to concatenate. If you settypetoremove, Gulp will remove the entire build block without generating a file.
here refers to the target path of the generated file.
We’ll want the final JavaScript file to be generated in thejsfolder, asmain.min.js. Hence, the markup would be:
Now if you run thisusereftask, Gulp will take run through the 3 script tags and concatenate them intodist/js/main.min.js.
The file however, isn’t minified right now. We’ll have to use thegulp-uglifyplugin to help with minifying JavaScript files. We also need a second plugin calledgulp-ifto ensure that we only attempt to minify JavaScript files.
$ npm install gulp-uglify --save-dev
// Other requires...var uglify = require('gulp-uglify');var gulpIf = require('gulp-if');gulp.task('useref', function(){return gulp.src('app/*.html').pipe(useref())// Minifies only if it's a JavaScript file.pipe(gulpIf('*.js', uglify())).pipe(gulp.dest('dist'))});
Gulp should now automatically minify themain.min.jsfile whenever you run theusereftask.
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 tojs/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 abuildcomment.
We can also minify the concatenated CSS file as well. We need to use a package calledgulp-cssnanoplugin to help us with minification.
$ npm install gulp-cssnano
var cssnano = require('gulp-cssnano');gulp.task('useref', async function(){return gulp.src('app/*.html').pipe(useref()).pipe(gulpIf('*.js', uglify()))// Minifies only if it's a CSS file.pipe(gulpIf('*.css', cssnano())).pipe(gulp.dest('dist'))});
Now you’d get one optimized CSS file and one optimized JavaScript file whenever you run theusereftask.
Let’s move on and optimize images next.
Optimizing Images
You’ve probably guessed it by now; we need to usegulp-imageminto help us with optimizing images.
$ npm install gulp-imagemin --save-dev
var imagemin = require('gulp-imagemin');
We can minifypng,jpg,gifand evensvgwith the help of gulp-imagemin. Let’s create animagestask for this optimization process.
Since different file types can be optimized differently, you might want to add options toimageminto customize how each file is optimized.
For example, you can createinterlacedGIFs by setting theinterlacedoption key totrue.
gulp.task('images', async function(){return gulp.src('app/images/**/*.+(png|jpg|jpeg|gif|svg)').pipe(imagemin({// Setting interlaced to trueinterlaced: true})).pipe(gulp.dest('dist/images'))});
You can play around with other options if you want to as well.
Optimizing images, however, is an extremely slow process that you’d not want to repeat unless necessary. To do so, we can use thegulp-cacheplugin.
$ npm install gulp-cache --save-dev
var cache = require('gulp-cache');gulp.task('images', async function(){return gulp.src('app/images/**/*.+(png|jpg|jpeg|gif|svg)')// Caching images that ran through imagemin.pipe(cache(imagemin({interlaced: true}))).pipe(gulp.dest('dist/images'))});
We’re almost done with the optimization process. There’s one more folder that we need to transfer from theappdirectory intodist, the fonts directory. Let’s do that now.
Copying Fonts to Dist
Since font files are already optimized, there’s nothing more we need to do. All we have to do is to copy the fonts intodist.
We can copy files with Gulp simply by specifying thegulp.srcandgulp.destwithout any plugins.
Now Gulp will copyfontsfromapptodistwhenever you rungulp fonts.
We have 6 different tasks in the Gulpfile now, and each of them has to be called individually with the command line, which is kinda cumbersome so we want to tie everything together into one command.
Before we do that though, let’s look at how to clean up generated files automatically.
Cleaning up generated files automatically
Since we’re generating files automatically, we’ll want to make sure that files that are no longer used don’t remain anywhere without us knowing.
This process is called cleaning (or in simpler terms, deleting files).
Now Gulp will delete thedistfolder for you whenevergulp clean:distis run.
Note: We don’t have to worry about deleting thedist/imagesfolder because gulp-cache has already stored the caches of the images on your local system.
To clear the caches off your local system, you can create a separate task that’s namedcache:clear
gulp.task(‘cache:clear’, async function (callback) { return cache.clearAll(callback) })
Phew, that’s a mouthful. Let’s combine all our tasks together now!
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 fromapptodist.
We’ve already grouped the first set of tasks together into a simple workflow with thegulp watchcommand:
gulp.task('watch', ['browserSync', 'sass'], function (){// ... watchers})
The second set consists of tasks that we need to run to create the production website. This includesclean:dist,sass,useref,imagesandfonts.
If we went by the same train of thought, we could create abuildtask to combine everything together.
gulp.task('build', [`clean`, `sass`, `useref`, `images`, `fonts`], async function (){console.log('Building files');})
Unfortunately, we wouldn’t be able to write thebuildtask this way because Gulp activates all tasks in the second argument simultaneously.
There’s a possibility thatuseref,images, or evenfontsgets completed beforecleandoes, which means the entiredistfolder gets deleted.
So, to ensure that cleans get completed before the rest of the tasks, we need to use an extra plugin calledRun Sequence.
$ npm install run-sequence --save-dev
Here’s the syntax of a task sequence with run sequence:
var runSequence = require('run-sequence');gulp.task('task-name', async function(callback) {runSequence('task-one', 'task-two', 'task-three', callback);});
Whentask-nameis called, Gulp will runtask-onefirst. Whentask-onefinishes, Gulp will automatically starttask-two. Finally, whentask-twois complete, Gulp will runtask-three.
Run Sequence also allows you to run tasks simultaneously if you place them in an array:
In this case, Gulp first runstask-one. Whentask-oneis completed, Gulp runs every task in the second argument simultaneously. All tasks in this second argument must be completed beforetask-threeis run.
So we can now create a task that ensures thatclean:distruns first, followed by all the other tasks:
gulp.task('build', async function (callback) {runSequence('clean:dist', ['sass', 'useref', 'images', 'fonts'],callback)})
To make things consistent, we can also build the same sequence with the first group. Let’s usedefaultas the task name this time:
gulp.task('default', async function (callback) {runSequence(['sass','browserSync', 'watch'],callback)})
Whydefault? Because when you have a task nameddefault, you can run it simply by typing thegulpcommand, which saves some keystrokes.
Finally, here’s aGitHub repofor all the work we’ve done!
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 thegulpcommand in the command line.
We’ve also built a second task,build, that creates adistfolder for the production website. We compiled Sass into CSS, optimized all our assets, and copied the necessary folders into thedistfolder. To run this task, we just have to typegulp buildinto the command line.
Lastly, we have acleantask that clears away from the generateddistfolder any image caches that are created, allowing us to remove any old files that were inadvertently kept indist.
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:
Generating inline CSS for performance withCritical
In addition to development or optimization processes, you can also add write JavaScript unit tests withgulp-jasmineand even deploy yourdistfolder onto your production server automatically withgulp-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 onautomating your workflow, and I invite you tograb ten chapters for freeif you’re interested in finding out more :)
Let me know what you felt about this article in the comments below! Oh yes, feel free tocontact meif you have any questions on workflow. I’ll be happy to reply!
Psst!Create a DigitalOcean account and get$200 in free creditfor cloud-based hosting and services.
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 theproxykey. 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 thegulptask, and you’re not calling the callback argument. By not doing either of those two things,gulpwill not know when the task has truly completed, which is no good if it’s used as a dependency of another task.
Generally speaking, always return a stream (or promise), or call the callback argument.See notes on thegulpdocs.
I also noticed that you’re usingrunSequence, 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 thatgulptasks are just regular JavaScript functions. You can compose them as you would any other JavaScript function:
function jsTask(done){gulp.src('js/*.js').pipe(foo())// run the callback when we're actually done, as this might be asynchronous.on('end', done);}// define a gulp task that runs jsTask()gulp.task('js', jsTask);function otherTask(done){// do something immediately, then be donebar();done();}// define a gulp task that runs otherTask()gulp.task('other', otherTask);function complexNestedTask(done){// run jsTask firstjsTask(function() {// then run otherTask, and let it run our done callback when it's doneotherTask(done);});// note that we're not using gulp tasks here, just regular functions}gulp.task('complex-nested', complexNestedTask);
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 withour asset pipeline, which may serve as a good example if you’re interested in setting up your own. Another great example isLaravel’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. taskandtask: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.
NO SUDO!! You shouldn’t need to use root privledges to install user software. Here’s a script to uninstall node and reinstall it. It’s very easy and makes it so you don’t need to use sudo:
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!
It looks like there is a typo. The structure of a webapp is “app/scss”. But task is “gulp.src(‘app/sass/styles.scss’)”. Anyway, you did a great job. Many thx!
Hey, I found out thatdelgot a breaking change (v2.0) after I wrote this article. What you have to do is to install v1.2.1 instead of the latest version of del with this command:
Weird, everything worked up until the ‘clean:dist’ task. When running ‘gulp clean:dist’, it always starts the task but never finishes it. Consequence: the ‘build’ task doesn’t work either.
When I clone your version from github and run the task, it works. When I copy your gulpfile.js to my solution, it has the same issue as I have. What am I missing?
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)
Hey, I found out thatdelgot a breaking change (v2.0) after I wrote this article. What you have to do is to install v1.2.1 instead of the latest version ofdelwith this command:
I can’t have ‘clean:dist’ task to work. I’ve installed[email protected], 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 partygulp-watchlibrary instead of gulp 3.x andgulp.watchrecommended by this post. gulp 4.0 has built-in methods to explicitly run tasks in sequence or parallel, andgulp-watchnotices files added while the build system is running.
That’s great Zell ! As a lucky proofreader of your book on automating workflow, i find this article is a good reflect of your book’s content. Clear, precise and neat :-)
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…
Grab the 10 free chapters I put up at the end of the post. One of them deals with learning the command line so you know how, and where to use these bash commands.
Let me know if you still have problems after reading through it.
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. Placingsassin 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)
[BS] Serving files from: app [14:23:39] Finished ‘sass’ after 150 ms [14:23:39] Starting ‘watch’… [14:23:39] Finished ‘watch’ after 12 ms [14:23:39] Finished ‘default’ after 165 ms
^C^C^C^C
The thing is that if I do this I cannot compile again unless I close the terminal and open it again. Thought it had to do with the runSequesnce task. Any ideas? Thanks!
I’m using codekit for most of these features, but I’m willing to try it out! If I ‘finally’ get everything working, is it easy to reuse it for next new projects?
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?
None of the authors has defined that, as I can see.
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 theappdirectory 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.
Sounds good! Thanks for the advice. I’m currently trying to develop my own and my team’s workflow for some time now so the book could sure come in handy!
Any ideas why the ‘gulp useref’ command doesn’t work as intended? The command runs with the console outputting:
[17:19:29] Using gulpfile ~/Projects/project/gulpfile.js[17:19:29] Starting 'useref'...[17:19:30] Finished 'useref' after 174 ms
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.
After ‘gulp useref’, my js files get combined to one file and the index.html file gets updated… But when I make changes in one of the js files, nothing happens anymore… I’m confused how to get going…
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?
Wow, thanks for such a fast reply. I’ve tried that and it didn’t work because of another bug. I’ve fixed that in the meantime and now it all works. Thanks man.
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):