Automated sass and web workflow with gulp

Using scss is a no brainer when you are comfortable working with css. I was relying heavily on a VSCode extension "Live Sass Compiler" until it break and i was getting annoyed with the error.

Btw, if you have question, need some help or feedback, don't hesitate to reach me on twitter.

It bring me out of the comfort zone, and i began my journey looking for a better alternative. I was looking for a tools with these criteria:

  • familiar
  • easy to use
  • easily customizable
  • can be learn in a day or less

Long story short, after long comparison between parceljs, gulpjs and webpack, i choose gulp and i try a few tutorials to make it click. it tooks me a few hours to search and learn it and the video i like the most is this Gulp Crash Course for Beginners by Coder coder.

So basically, gulp is just plain javascript written in your project file that you are familiar with that you call with a sets of gulp modules based on your needs. It's neato ! Here are steps that we need to take to start using it, if you need more details visit the link above or search a video that suits your style if you wish.

Goals

Our goals in this tutorials is automate Web Front End Development to be ready for production as listed below:

  • compile scss into a single css, add browser prefix and then minify it
  • compile javascript file that we put include in script multiple times into one file
  • rename output file into production name
  • move all file into dist folder

Step 1: Installing Gulp

The best practice is to install node dependency per project. Notice that we only install gulp-cli globally. This is to enable us to use gulp in command line from anywhere instead of using npm run build. Also note that gulp still need to be install in the project.

cd my_project_folder
# in project folder
npm init # create package.json
# install the cli so we can use `gulp` command from anywhere
npm install -g gulp-cli
# and install gulp per project basis to use gulp
npm install -D gulp

Step 2: Installing Gulp modules

Note that gulp modules that we use are based on requirement basis, there are lot more gulp modules available and be sure to check them out when you need more.

npm install -D gulp-sass gulp-sourcemaps gulp-postcss autoprefixer cssnano gulp-rename

# if you need the html and jsTask
npm install -D gulp-html-min babelify@8 babel-core babel-preset-env gulp-sourcemaps gulp-terser-js browserify vinyl-buffer vinyl-source-stream babel-plugin-transform-runtime

npm install babel-runtime

Step 3: Write the gulpfile.js

  • autoprefixer
  • cssnano
  • gulp-postcss
  • gulp-sass
  • gulp-sourcemaps
    • help during debug and point to the source code line that contains the error
  • gulp-rename
// Step 1: define gulp import
const { src, dest, watch, series, parallel } = require('gulp');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const postcss = require('gulp-postcss');
const sass = require('gulp-sass');
const sourcemaps = require('gulp-sourcemaps');
const rename = require('gulp-rename');

const htmlmin = require('gulp-htmlmin');

const terser = require('gulp-terser-js');
const browserify = require('browserify');
const source  = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');

// Step 2:  Add Source file
const files = {
  scssPath: 'src/scss/**/*.scss',
  jsPath: 'src/js/**/*.js',
  jsOutput: 'bundle.min.js',
}

// Step 3: Write the sass task
function scssTask() {
  return src(files.scssPath)
    .pipe(sourcemaps.init())
    .pipe(sass({ outputStyle: 'compressed' }))
    .pipe(postcss([autoprefixer(), cssnano()]))
    .pipe(rename({suffix: '.min'}))
    .pipe(sourcemaps.write('.'))
    .pipe(dest('dist/css'));
    // the output is in folder called dist
    // if my sass file is called main.scss
    // my output is dist/main.min.scss
    // the .min is just preferences to mark it as minified file
};

// from previous post
function jsTask() {
  return browserify(files.jsPath, {debug:true})
    .transform('babelify', {
      presets: ['babel-preset-env'],
      plugins: ['babel-plugin-transform-runtime']
    })
    .bundle()
    .pipe(source(files.jsOutput))
    .pipe(buffer())
    .pipe(sourcemaps.init({loadMaps: true}))
    .pipe(terser())
    .pipe(rename({suffix: '.min'}))
    .pipe(sourcemaps.write('.'))
    .pipe(dest('dist'));
};


// mminfy html and move to output folder
function htmlTask() {
  return src('src/*.html')
    .pipe(htmlmin({ collapseWhitespace: true }))
    .pipe(dest('dist'));
};

// copy all image to output folder
function imgTask() {
  return src('img/*.*')
    .pipe(dest('dist/img'));
}

// step 5: Watch task - monitor file for changes (auto update whenever you save)
function watchTask() {
  watch([files.scssPath, files.jsPath], 
    parallel(scssTask, jsTask));
}

// step: 6: export it all as Default task
exports.default = series(
  parallel(scssTask, jsTask, htmlTask, imgTask),
  watchTask);

Step 4: Include your css from the dist folder

<link rel="stylesheet" href="all.min.css">

Folder Structure

.
└── my_project/
    ├── dist/
    │   ├── img
    │   ├── all.min.css
    │   ├── bundle.main.js
    │   └── main.html
    ├── src/
    │   ├── js/
    │   │   ├── loader.js
    │   │   ├── main.js
    │   │   └── sidebar.js
    │   ├── scss/
    │   │   ├── main.scss
    │   │   └── layout/
    │   │       └── grid.scss
    │   └── main.html
    └── gulpfile.js

Next Step

If you need more gulp usage, you can read my previous post on how to use gulp with babel so that you can use the latest javascript feature and transpile it into javascript that old browser can read or even use commonjs import style in your front end code.