It's Easy to Use: Gulp

Hey there, This is my first post on my blog, so I'm excited about it. 😇 Also, It took me the right amount of time to self-host this blog using Ghost. But overall, I'm happy with how I set it up, and it is speedy and smooth.

Recently, I came across Gulp, and I was amazed by its features. I came to know how useful a task runner can be for web developers. So, I just wanted to write about it. So without further adieu, let's get started.

Introduction

What is gulp BTW? Gulp is a task runner or builds runner. We provide some instructions in a file called gulpfile.js, and it will execute those instructions to get our work done.

We as developers waste too much of our time doing repetitive tasks, so Gulp is a great simple way to automate our repetitive tasks, thus, making us more productive.

Let's say we built a simple static website, and now it's ready to be deployed to production for the world to see. But before that, we'll need to make some optimization(s) like compressing CSS and JS files, so end users don't have to download huge files and thus leading to bad UX.

So now, you compress your HTML, CSS, JS, and Image files from websites like https://minify-html.com/, https://cssminifier.com/, https://jscompress.com/, and https://tinypng.com respectively. You then deploy your code to production. It works, Yay. But wait, you've made a simple spelling mistake. Now, you go back to your editor. Then you'll have to beautify(or prettify) your whole codebase using websites like https://codebeautify.org. You'll then correct your spelling mistake. Again you'll need to compress your files. Now, you push to production. It works, Yay. But wait Still, there's some other spelling mistake...

But isn't there a better way to automate this stuff? The good news is, there is. And that's what we're going to learn today, and it's effortless to use. We'll write all of our code in src/ folder, write a gulp script gulpfile.js that will compress all of our files, and put it in dist/ folder. You always work with src/ folder and always deploy dist/ folder only(If you deploy src/ folder, then my whole time writing this article will be a waste). With this approach, you don't always have manually to minify(or compress) files or beautify them, you can do it with just one command.

Getting Started

Image from Pixabay

Prerequisites: NodeJS, Yarn(or NPM), and obviously, your codebase of the static website.

  1. From the root of your project, run:

    $ npm init -y
    
    • This will create a package.json file with defaults.
  2. Our initial folder structure must be something like this:

    .
    ├── dist
    ├── package.json
    └── src
        ├── assets
        │   ├── img1.jpg
        │   └── img2.jpg
        ├── css
        │   ├── 01-style1.css
        │   ├── 02-style2.css
        │   └── 03-style3.css
        ├── fonts
        │   ├── font1.woff
        │   └── font2.woff
        ├── index.html
        └── js
            ├── 01-app1.js
            ├── 02-app2.js
            └── 03-app3.js
    
    • You can see that our CSS/JS files have a numeric prefix. We do this because gulp processes file alphabetically.
    • So, for example, If you have 2 CSS files named custom.css and library.css, then gulp will process custom.css and then library.css, thus all the custom code that you write in custom.css will be overridden by library.css.
    • But we don't want this. So we change their names to 01-library.css and 02-custom.css. Sweet and simple.
  3. Let's add some dependencies, run:

    yarn add gulp gulp-autoprefixer gulp-clean gulp-clean-css gulp-concat gulp-htmlmin gulp-imagemin gulp-replace gulp-uglify-es merge-stream
    
    # or
    # npm i --save gulp gulp-autoprefixer gulp-clean gulp-clean-css gulp-concat gulp-htmlmin gulp-imagemin gulp-replace gulp-uglify-es merge-stream
    
  4. Let's understand what each of these packages does:

    • gulp: The main toolbox.
    • gulp-autoprefixer: It will prefix the CSS with Autoprefixer.
    • gulp-clean: It helps to remove files and folders.
    • gulp-clean-css: Minify the CSS with cleancss
    • gulp-concat: Concatenate files, so all of our CSS/JS files will be produced in just one CSS/JS file. Thus, it helps in reducing the requests count.
    • gulp-htmlmin: Minify HTML
    • gulp-imagemin: Compress images
    • gulp-replace: Replace some text in the files with custom texts.
    • gulp-uglify-es: Minify JS
    • merge-stream: We'll use this to copy other static parts.
  5. Finally, create gulpfile.js file in the root of your project, run:

    $ touch gulpfile.js
    

Enough of the theory, let's dive into code.

Codebase:

Let's start writing our automation script:

  1. Let's include all of our packages in gulpfile.js:

    // gulpfile/js
    let gulp = require('gulp');
    let clean = require('gulp-clean');
    let concat = require('gulp-concat');
    let replace = require('gulp-replace');
    let minifyCSS = require('gulp-clean-css');
    let uglify = require('gulp-uglify-es').default;
    let htmlmin = require('gulp-htmlmin');
    let autoprefixer = require('gulp-autoprefixer');
    let merge = require('merge-stream');
    
  2. Next, let's defile the location of our files in the codebase in globs variable:

    // Location to our files
    let globs = {
      dist: './dist',
      css: './src/css/*.css',
      js: './src/js/*.js',
      html: './src/*.html',
      images: './src/assets/**',
      fonts: './src/fonts/**'
    };
    
  3. Now, the first step is to clean the dist/ folder for any old files, and we'll do that by:

    // Step: 1 - This will delete the folder and re-create it
    gulp.task('clean', gulp.series(function() {
      return gulp.src(globs.dist, {read: false})
        .pipe(clean());
    }));
    
  4. The second step is to place our fonts/ directory to the dist/ folder, and we'll not do any compression or optimization to it. Just copy it to the dist/ folder:

    // Step: 2 - Just copy fonts/ folder
    gulp.task('fonts', gulp.series('clean', function() {
      return gulp.src(globs.fonts)
          .pipe(gulp.dest(globs.dist + '/fonts'));
    }));
    
  5. Now let's work on our CSS files. We'll take all of our CSS files, concatenate them into one CSS file called main.min.css, Apply autoprefixer to it, then minify it and then finally place this CSS file to dist/css folder:

    // Step: 3 - CSS processing
    gulp.task('styles', gulp.series('clean', function() {
      return gulp.src(globs.css)
        .pipe(concat('main.min.css'))
        .pipe(autoprefixer())
        .pipe(minifyCSS())
        .pipe(gulp.dest(globs.dist + '/css'));
    }));
    
  6. Now let's work on our JS files. We'll take all of our JS files, concatenate them into one JS file called app.min.js, minify them, then export them to dist/js folder:

    // Step: 4 - JS processing
    gulp.task('js', gulp.series('clean', function() {
      return gulp.src(globs.js)
        .pipe(concat('app.min.js'))
        .pipe(uglify())
        .pipe(gulp.dest(globs.dist + '/js'));
    }));
    
  7. Now let's work on our image files. We'll take all of our Images, compress them, then export them to dist/assets/ folder:

    // Step: 5 - Image processing
    gulp.task('assets', gulp.series('clean', function() {
      return gulp.src(globs.js)
        .pipe(imagemin())
        .pipe(gulp.dest(globs.dist + '/assets'));
    }));
    
  8. Finally, let's work on our HTML file:

    • In our HTML file, we'll have our <link> tags something like this:
      <link rel="stylesheet" href="css/01-style1.css">
      <link rel="stylesheet" href="css/02-style2.css">
      <link rel="stylesheet" href="css/03-style3.css">
      
    • So, we'll need to replace these lines with our one CSS file main.min.css.
    • Also, we need to do the same for our JS files to one JS file app.min.js.
    • We'll now minify our HTML file and remove comments also.
    • We can do this by these lines:
      // Step: 6 - HTML processing
      gulp.task('html', gulp.series('clean', function() {
        return gulp.src(globs.html)
          .pipe(replace(`<link rel="stylesheet" href="css/01-style1.css">`, ''))
          .pipe(replace(`<link rel="stylesheet" href="css/02-style2.css">`, ''))
          // Replace this with our one `main.min.css` file
          .pipe(replace(`<link rel="stylesheet" href="css/03-style3.css">`, '<link rel="stylesheet" href="css/main.min.css">'))
          
          .pipe(replace(`<script src="js/01-app1.js"></script>`, ''))
          .pipe(replace(`<script src="js/02-app2.js"></script>`, ''))
          .pipe(replace(`<script src="js/03-app3.js"></script>`, '<script src="js/app.min.js"></script>'))
          .pipe(htmlmin({
            collapseWhitespace: true,
            removeComments: true
          }))
          .pipe(gulp.dest('./dist'));
      }));
      
  9. The final step is to build the task, and we can tell gulp with this:

    // Step: 7 - Build the task
    gulp.task('build', gulp.parallel('fonts', 'styles', 'js', 'assets', 'html'));
    gulp.task('default', gulp.series('build'));
    
  10. That's it; your complete gulp file must look like this: https://gist.github.com/cdadityang/18cd022ab9a8268032f5b5b44641603f

Testing it

We're done with the coding part, let's test it out:

  1. We need to add gulp to our scripts in our package.json file. So in package.json file, add:

    "scripts": {
      "build": "gulp"
    }
    
  2. Now from the root directory of your project, run this command:

    $ yarn build
    
    # or
    # npm run build
    
  3. Now, go to the dist/ folder and run your server:

    $ cd dist/
    $ python -m SimpleHTTPServer 3000
    # Or any other web server
    

Summary and conclusion

Let's take a quick look at what we learned today:

  1. First of all, I introduced myself, so don't forget to connect with me at Twitter or elsewhere.
  2. We saw a quick introduction to gulp, and we discussed a scenario of how we'll use gulp to solve our problem
  3. Then we saw what the prerequisites are and we also set up our environment
  4. Then we wrote our automation script in gulpfile.js.
  5. Then we tested our script by adding gulp command to package.json file and running yarn build, which will export our app to dist/ folder.
  6. Finally, we took a quick look at this very summary...

That's it and Let there be the end. 🙏