Black Friday sale is now on! 50% off Laravel: The Modular Way. Learn more

A Brief Introduction to Gulp

Dan Sherwood

Javascript Tutorials

  • All together
  • What is it?

    Gulp is a frontend task manager. In the simplest of terms, it is a tool which saves you from performing mundane tasks, such as minifying, concatenating and linting your files. The time it saves you will be invaluable.

    Gulp can be as complex or as simple as you need (or want) it to be. In this article we will cover installing gulp and the gulp command line interface so you can get up an running with a simple, but powerful gulp file in your local projects. 
     

    Installing

    Install Gulp globally

    This is how we use gulp.

    npm install --global gulp-cli

    Initialise your project

    npm init

    Add Gulp to your dependencies

    npm install --save-dev gulp

    Create a new file called gulpfile.js

    var gulp = require('gulp');
    
    gulp.task('default', function() {
        // place code for your default task here
    });
    

    And that's it! You're ready to use gulp! 

    What's Next?

    Now we can start building up our gulpfile.js . We will be performing several tasks.

    SCSS/CSS

    • Converting SCSS files to CSS
    • Concatenating all of our newly converted CSS files
    • Minifying our CSS

    JS

    • Concatenating our JS files
    • Minifying our JS

    Watching

    • Listen for any changes to the SCSS + JS files

    File Structure

    Before we get underway, let's make our file structure should look something like this:
    |- - dist
    |    |- - js
    |    |- - css
    |- - build
    |    |- - css
    |    |- - js
    |    |- - scss
    |- - index.html
    |- - gulpfile.js

    Plugins

    Next, we will install some third party gulp plugins to help us out. 
    The --save-dev option will add the gulp plugin to your dependency file for you.

    npm install --save-dev gulp-util
    npm install --save-dev gulp-concat
    npm install --save-dev gulp-sass
    npm install --save-dev gulp-cssnano
    npm install --save-dev gulp-rename
    npm install --save-dev gulp-notify 
    npm install --save-dev gulp-uglify
    npm install --save-dev del

    Require

    Add the require statements for the installed plugins in your gulpfile.js.

    // Require gulp + plugins
    var gulp    = require('gulp'),
        gutil   = require('gulp-util'),
        concat  = require('gulp-concat'),
        sass    = require('gulp-sass'),
        cssnano = require('gulp-cssnano'),
        rename  = require('gulp-rename'),
        notify  = require('gulp-notify'),
        uglify  = require('gulp-uglify'),
        del     = require('del');
    

    Paths

    In my gulpfile.js I have added my paths to an object for convenience, this will make it much easier to update the file if you ever decide to change folder names etc.

    var paths = {
        dist:  './dist/',
        build: './build/'
    }

    Keeping It Clean

    One thing to remember is, we will be updating the master CSS + JS in the dist folder. Every time we make a change to the files in the build folder we will need to empty the respective dist CSS or JS folder. These tasks will be executed before any other tasks.

    // CLEAN ALL
    // We call this function when we run the default gulp task, after only the `clean:js` or `clean:css` tasks are run
    gulp.task('clean:all', function() {
        return del([
            paths.dist + 'js/**/*.
            paths.dist + 'css/**/*.css',
        ]);
    });
    
    // CLEAN JS
    gulp.task('clean:js', function() {
        return del([
            paths.dist + 'js/**/*.js',
        ]);
    });
    
    // CLEAN CSS
    gulp.task('clean:css', function() {
        return del([
            paths.dist + 'css/**/*.css',
        ]);
    });

    We can use del to empty a folder of its contents. This will allow us to have an empty folder to add the updated files with gulp.

    SCCS/CSS

    Next, we will write our SCSS and CSS tasks to modify and manipulate our source files to create a new file called dist.min.css

    CSS
    Every time we run this task we tell gulp to run `dev:scss` to make sure we pick up any scss files if there are any

    gulp.task('dev:css', gulp.series('dev:scss', function() {
        return gulp.src([paths.build + 'css/**/*.css')   // Tell gulp what folder we want to look inside
            .pipe(concat('build.css'))                   // Tell gulp to concatenate every file into a new one called `build.css`
          .pipe(cssnano())                               // Minify our `build.css` file
          .pipe(rename({suffix: '.min'}))                // Rename the file to signify it is minified
          .pipe(gulp.dest(paths.dist + 'css'))           // Tell gulp we are saving this new file in dist/css
          .pipe(notify({message: 'CSS task complete'})); // Send a notification when we are done
    }));
    

    Let's look at that dev:scss task we mentioned earlier. This task does what is essentially the same as the dev:css task, but with a couple of differences. Firstly it compiles the SCSS into valid CSS. Secondly, it will place these new CSS files in the build/css folder for the dev:css task to perform its functions on. 

    // SCSS
    gulp.task('dev:scss', function() {
        return gulp.src(paths.build + 'scss/**/*.scss')      // Tell gulp what folder we want to look inside
            .pipe(concat('build.scss'))                       // Tell gulp to concatenate every file into a new one called `build.scss`
          .pipe(sass())                                   // Compile SCSS into CSS
          .pipe(gulp.dest(paths.build + 'css'))           // Tell gulp we are saving this new file in build/css
          .pipe(notify({message: 'SCSS task complete'})); // Send a notification when we are done
    });


    This completes our core SCSS/CSS functionality. 

    JS

    Now we can move on the JS part of the gulpfile.js. Again, we will be doing largely the same thing as before. 
     

    // JS
    gulp.task('dev:js', function() {
        return gulp.src(paths.build + 'js/**/*.js')     // Tell gulp what folder we want to look inside
            .pipe(concat('build.js'))                       // Tell gulp to concatenate every file into a new one called `build.js`
          .pipe(uglify())                               // Minify our `build.js` file
          .pipe(rename({suffix: '.min'}))               // Rename the file to signify it is minified
          .pipe(gulp.dest(paths.dest + 'js')            // Tell gulp we are saving this new file in dist/js
          .pipe(notify({message: 'JS task complete'})); // Send a notification when we are done
    });


    Watching

    Now, for this to be even more useful is to update the dist files overtime the build files are updated. We can do this by creating watch tasks. These watch task will essentially listen for any changes in the folders we specify and will execute a function when these conditions are met. 

    // WATCH
    gulp.task('watch:scss', function(done) {
        gulp.watch( 
            paths.src + 'scss/**/*.scss',
          gulp.series('clean:css', 'dev:css')
      );
      done();
    });
    
    gulp.task('watch:css', function(done) {
      gulp.watch([
          '!' + paths.src + 'css/**/build.css',
          paths.src + 'css/**/*.css'
      ],
          gulp.series('clean:css', 'dev:css')
      );
      done();
    });
    
    gulp.task('watch:js', function(done) {
      gulp.watch(
          paths.src + 'js/**/*.js',
          gulp.series('clean:js', 'dev:js')
      );
      done();
    });

    So, the first argument for the watch function is the path to the folder we want to watch, and secondly, we call gulp.series() to execute our chosen tasks. 

    A quick note about the gulp.series() and gulp.parallel functions. gulp.series() will execute the tasks/functions you pass to it sequentially, while gulp.parallel will execute its functions in parallel. These functions allow you to apply fine control to how your gulpfile.js behaves in any situation.

    Default Task

    Now we can update our default task.

    // We want to run all of the watch tasks in parallel
    var all = gulp.parallel('watch:scss', 'watch:css', 'watch:js');
    
    // The clean and dev tasks need to ordered sequentially to work
    // Finally we pass in our parallel tasks at the end
    gulp.task('default', gulp.series('clean:all', 'dev:css', 'dev:js', all));

    Running

    Now we can use gulp and test our gulpfile.js, everything has been attached to to the default task which means all we need to do is write gulp.

    gulp

    Voila! As simple as that.

    Of course, you can rename the default task if you want. For example:

    gulp.task('awesome', gulp.series('clean:all', 'dev:css', 'dev:js', all));

    And then we write

    gulp awesome

     

    All together

    Stitching everything together we end up with a gulpfile.js looking something like this.

    var gulp    = require('gulp'),
        gutil   = require('gulp-util'),
        concat  = require('gulp-concat'),
        sass    = require('gulp-sass'),
        cssnano = require('gulp-cssnano'),
        rename  = require('gulp-rename'),
        notify  = require('gulp-notify'),
        uglify  = require('gulp-uglify'),
        del     = require('del');
    
    var paths = {
      dist: './dist/',
      build: './build/'
    }
    
    // CLEAN
    gulp.task('clean:all', function() {
      return del([
        paths.dist + 'js/**/*.js',
        paths.dist + 'css/**/*.css',
      ]);
    });
    
    gulp.task('clean:js', function() {
      return del([
        paths.dist + 'js/**/*.js',
      ]);
    });
    
    gulp.task('clean:css', function() {
      return del([
        paths.dist + 'css/**/*.css',
      ]);
    });
    
    // SCSS
    gulp.task('dev:scss', function() {
      return gulp.src(paths.build + 'scss/**/*.scss')
        .pipe(concat('build.scss'))
        .pipe(sass())
        .pipe(gulp.dest(paths.dist + 'css'))
        .pipe(notify({message: 'SCSS task complete'}));
    });
    
    // CSS
    gulp.task('dev:css', gulp.series('dev:scss', function() {
      return gulp.src(paths.build + 'css/**/*.css')
        .pipe(concat('build.css'))
        .pipe(cssnano())
        .pipe(rename({suffix: '.min'}))
        .pipe(gulp.dest(paths.dist + 'css'))
        .pipe(notify({message: 'CSS task complete'}));
    }));
    
    // JS
    gulp.task('dev:js', function() {
      return gulp.src(paths.build + 'js/**/*.js')
        .pipe(concat('build.js'))
        .pipe(uglify())
        .pipe(rename({suffix: '.min'}))
        .pipe(gulp.dest(paths.dist + 'js'))
        .pipe(notify({message: 'JS task complete'}));
    });
    
    // WATCH
    gulp.task('watch:scss', function(done) {
      gulp.watch(
        paths.build + 'scss/**/*.scss',
        gulp.series('clean:css', 'dev:css')
      );
      done();
    });
    
    gulp.task('watch:css', function(done) {
      gulp.watch([
        '!' + paths.build + 'css/**/build.css',
        paths.build + 'css/**/*.css'
      ],
        gulp.series('clean:css', 'dev:css')
      );
      done();
    });
    
    gulp.task('watch:js', function(done) {
      gulp.watch(
        paths.build + 'js/**/*.js',
        gulp.series('clean:js', 'dev:js')
      );
      done();
    });
    
    //DEFAULT
    var all = gulp.parallel('watch:scss', 'watch:css', 'watch:js');
    gulp.task('default', gulp.series('clean:all', 'dev:css', 'dev:js', all));
    

    Example

    This is an example of what our final project might look like after we have executed the default gulp task.

    |- - build
    |    |- - js
    |    |    `- - build.min.js
    |    |- - css
    |    |    `- - build.min.css
    |- - dist
    |    |- - css
    |    |- - js
    |    |    |- - scripts.js
    |    |    `- - animate.js
    |    |- - scss
    |    |    |- - colors.scss
    |    |    `- - styles.scss
    |- - index.html
    |- - gulpfile.js

    Final thoughts
     

    Gulp can feel daunting at first, but once it is broken down it is much easier to digest. Play around with this file and experiment with different plugins.

    For more information on gulp visit the docs
     

    Laravel Modules Book by David Carr

    Help support the blog so that I can continue creating new content!

    Subscribe to my newsletter

    Subscribe and get my books and product announcements.

    © 2009 - 2022 DC Blog. All code MIT license. All rights reserved.