Gulp-Example for SCSS, JS and BrowserSync

The following setup is based on “tristanisfeld” which I found on Github. See https://gist.github.com/tristanisfeld/9deea503260324f5e9b0

The complete setup: DOWNLOAD

In the following setup you will have the ability to:

  • Generate one minifed CSS from SCSS files (incl. Autoprefixer)
  • Concatinate and minify multiple JS Modules into one JS file
  • use “Browsersync” so you don’t need to reload the tab everytime

Also there will be a boolean variable called “production” which activates or deactivates the “minification”, “uglyfication” and generation of sourcemaps.

package.json

{
  "name": "my_custom_gulp_setup",
  "author": "Kevin Pfeifer",
  "license": "WTFPL",
  "version": "2.0.0",
  "description": "Generate minified CSS and JS from source files",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "devDependencies": {
    "browser-sync": "^2.26.7",
    "gulp-autoprefixer": "^7.0.1",
    "gulp-concat": "^2.6.1",
    "gulp-if": "^3.0.0",
    "gulp-load-plugins": "^2.0.1",
    "gulp-minify-css": "^1.2.4",
    "gulp-rename": "^1.4.0",
    "gulp-sass": "^4.0.2",
    "gulp-sourcemaps": "^2.6.5",
    "gulp-uglify-es": "^2.0.0",
    "gulp-watch": "^5.0.1",
    "node-sass": "^4.13.0"
  },
  "dependencies": {
    "gulp": "^4.0.2"
  }
}

Don’t know what the package.json does? See npm vs. yarn – Package Managers for JavaScript

gulpfile.js

const gulp = require('gulp'),
      gulpLoadPlugins = require('gulp-load-plugins'),
      plugins = gulpLoadPlugins(),
      config = require('./gulp/config');

// --------------------function to get tasks from gulp/tasks
function getTask(task) {
  return require('./gulp/tasks/' + task)(gulp, plugins, config);
}

// ---------------------------------------------- Gulp Tasks
gulp.task('sass',             getTask('sass'));
gulp.task('scripts',          getTask('scripts'));
gulp.task('styles',           getTask('styles'));
gulp.task('watch',            getTask('watch'));
gulp.task('browsersync',      getTask('browsersync'));

// --------------------------------------- Default Gulp Task
gulp.task('default', gulp.series('watch'));

Each Gulp setup starts with a “gulpfile.js“.

  • gulp = require(‘gulp’)
    • Load the gulp default functionality into the variable gulp
  • gulpLoadPlugins = require(‘gulp-load-plugins’)
    • Load the additional modul “gulp-load-plugins” which helps us use gulp modules later on
  • plugins = gulpLoadPlugins()
  • config = require(‘./gulp/config’)
    • Load the config file “./gulp/config” into the variable config
function getTask(task) {
  return require('./gulp/tasks/' + task)(gulp, plugins, config);
}

Here we define a rather generic function which helps us load tasks from the folder “./gulp/tasks/“. With this function gulp allows us to have 1 file per task and not cram all the tasks into the gulpfile.js

gulp.task('sass',             getTask('sass'));
gulp.task('scripts',          getTask('scripts'));
gulp.task('styles',           getTask('styles'));
gulp.task('watch',            getTask('watch'));
gulp.task('browsersync',      getTask('browsersync'));

Here we load all the tasks from each JS file in “./gulp/tasks/“.

Gulp Plugin Loader

Since we don’t want to require every module inside every seperate task file we can use the previously loaded module “gulp-load-plugin” to provide us all the modules in one variable.

Basically this module does the following (so we don’t have to do it):

plugins.sourcemaps = require('gulp-sourcemaps');
plugins.concat = require('gulp-concat');
plugins.uglifyEs = require('gulp-uglify-es');

This happens at the start of the gulpfile.js in the following 2 lines:

gulpLoadPlugins = require('gulp-load-plugins'),
plugins = gulpLoadPlugins()

One important thing here is the fact, that the module changes the name of the loaded modules so we can more easily use it inside our tasks.

Node Module NameFunction name
gulp-sourcemapssourcemaps
gulp-concatconcat
gulp-uglify-esuglifyEs

And with that we now have a variable “plugins” from which we can access all modules which are defined in the package.json.

Structure of tasks

// =========================================================
// Gulp Task: sass
// Description: transpiles sass, adds sourcemaps, prefixes
// npm install --save-dev node-sass gulp-sass gulp-sourcemaps gulp-autoprefixer gulp-load-plugins
// =========================================================

module.exports = function(gulp, plugins, config) {
  return function() {
    return gulp.src(config.sass.src)
      .pipe(plugins.if(!config.production, plugins.sourcemaps.init()))
      .pipe(plugins.sass(config.sass.opts).on('error', plugins.sass.logError))
      .pipe(plugins.autoprefixer())
      .pipe(plugins.if(!config.production, plugins.sourcemaps.write('.')))
      .pipe(gulp.dest(config.sass.dest));
  }
};

Now what does each line?

module.exports = function(gulp, plugins, config) {

With the “module.exports” we define, that this function can be included in other JS files. The parameters used inside the function() are the same gulp, plugins and config variables used in our generic getTask(task) function.

return function() {

The actual functionality of the task needs to be wrapped inside a function() so gulp can use it as a “Callback” in the background and therefore allow tasks to be executed in parallel or series.

return gulp.src(config.sass.src)
   ...

Now the “usual” Gulp code is being done where the different functionalites of the tasks are defnied. You just need to be sure that a valid “Gulp stream” is being returned here.

Difference between dev and production build

The above example already has the “if production” logic implemented.

.pipe(plugins.if(!config.production, plugins.sourcemaps.init()))

The base module here is called “gulp-if“. See https://www.npmjs.com/package/gulp-if

This means, if we have “production” set to false in our Config-JSON gulp will also create additional Sourcemaps for the SASS.

In the “scripts” tasks we also have a similar code example:

.pipe(plugins.if(config.production, plugins.uglifyEs.default(), plugins.sourcemaps.init()))

Autoprefixer settings

With the current version of Autoprefixer it is not recommended to define the autoprefixer rules inside the JS-File and use a separate file named “.browserslistrc” instead.

You can see all available rules here: https://github.com/postcss/autoprefixer#options

# Browsers that we support

last 2 version
> 1%
maintained node versions
not dead

config.js

The following JSON describes how the gulp setup should behave and therefore how the different tasks should output their code.

  • opts => Options for the corresponding Gulp task
  • src => Path to the source files
  • dest => Path where the generated files should be placed

There is also inline documentation present for basically every option

module.exports = {
  production: false,
  rename: {
    min: { suffix: '.min' }
  },
  // --------------------------------------------- browsersync
  browsersync: {
    opts: {
      proxy: "http://localhost", // The URL of the website you want to browsersync
      port: 4000, // The port, from which the browsersync tab will be opened
      serveStatic: [{
        route: '/', // The route, from which the "live" website serves CSS and JS files
        dir: './dist' // Your local path coming from the gulpfile.js where the newly local generated files are laying
      }],
    },
    watch: [
      './dist/assets/css',
      './dist/assets/js'
    ]
  },
  // ---------------------------------------------------- sass
  sass: {
    src: [
      "./source/sass/**/*.scss",
    ],
    opts: { }, // add sass options here
    dest: "./dist/assets/css"
  },
  // ------------------------------------------------- scripts
  scripts: {
    src: [
      'source/js/main.js'
    ],
    base: 'source/js', // common base folder of all concatenated JS files so sourcempas are working correctly
    filename: 'main.js', // filename of outputted, concatenated JS file
    dest: "./dist/assets/js" // folder where the JS files should be populated
  },
  // -------------------------------------------------- styles
  styles: {
    src: [
      "./source/css/**/*.css",
    ],
    dest: './dist/assets/css'
  },
};

Share this post

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.