
In a world where Webpack, Parcel and Rollup are the prevalent ways of bundling JavaScript and carrying out all manner of other front end build tasks, it doesn't feel very on-trend to still be using, or talking about, Gulp.
But... I don't care! If I'm working on something like an SPA with React then sure, I'll be fully in Webpack world - but for most other applications (small to medium vanilla JS projects, or PHP-based CMS projects where I just want to import, transpile and uglify some assets and and point at them from my templates) I still absolutely love Gulp for its simplicity, speed and flexibility.
I also just can't get away from my strong distaste for how Webpack handles non-JS assets. Importing SCSS into a JavaScript file and then having it spit out CSS in a monolithic <style>
block at the top of my page just feels nasty. I know there are different ways of handling this, but Gulp just feels a little closer to where I want to be out of the box.
So with all of that said, here's my current go-to gulpfile.js. This still uses Webpack to bundle JS, but I can handle the rest of the pipeline and any other assets in a way that makes more sense to my brain. During development, the only task I ever need to run is the default gulp
which watches all of my SCSS and JS files, and does the following:
Compiles Sass, and then sourcemaps, minifies and autoprefixes the resulting CSS
Bundles and transpiles modern (i.e. ES6 and above) JavaScript, and then sourcemaps and uglifies the output
Writes all of the above to the /dist/ directory, which I can then point to from my templates
The only other addition worth mentioning is gulp-mode, which allows me to pass in a "mode" flag (i.e. --development
or --production
) which I then use to modify a few tasks. Development mode is set by default, but when I'm ready to deploy to staging or live I can simply run gulp --production
to create an optimised build (no sourcemaps, and webpack runs in "production" mode).
One common use for Gulp which I personally don't bother with is copying over arbitrary asset folders (fonts, images etc) from /src/ to /dist/. This has just never been a priority for me as I handle the optimisation of these kinds of assets manually and then just save the files straight into /dist/. This one just depends on your workflow, if you want to use an automated image optimiser, or simply prefer to work exclusively in your /src/ directory then this is something you may want to add.
gulpfile.js
const gulp = require('gulp');
const uglify = require('gulp-uglify');
const cssnano = require('gulp-cssnano');
const autoprefixer = require('gulp-autoprefixer');
const sass = require('gulp-sass');
const sourcemaps = require('gulp-sourcemaps');
const webpack = require('webpack-stream');
const babel = require('gulp-babel');
const mode = require('gulp-mode')();
gulp.task('process-sass', () => {
return gulp.src('src/scss/index.scss')
.pipe(mode.development(sourcemaps.init()))
.pipe(sass().on('error', sass.logError))
.pipe(autoprefixer({
overrideBrowserslist: ['> 1%']
}))
.pipe(cssnano())
.pipe(mode.development(sourcemaps.write()))
.pipe(gulp.dest('dist/css'));
});
gulp.task('process-js', () => {
return gulp.src('src/js/index.js')
.pipe(webpack({
mode: mode.development() ? 'development' : 'production',
watch: true,
output: {
filename: 'bundle.js'
}
}))
.pipe(babel({ presets: ['@babel/env'] }))
.pipe(mode.development(sourcemaps.init()))
.pipe(uglify().on('error', (uglify) => {
console.error(uglify.message);
this.emit('end');
}))
.pipe(mode.development(sourcemaps.write()))
.pipe(gulp.dest('dist/js'));
});
gulp.task('default', () => {
gulp.watch(
['src/scss/*.scss','src/scss/*/*.scss'],
{ ignoreInitial: false },
gulp.series('process-sass')
);
gulp.watch(
['src/js/*.js','src/js/*/*.js'],
{ ignoreInitial: false },
gulp.series('process-js')
);
});
And just for completeness, here's a package.json containing all of the required dev dependencies for the above gulpfile:
package.json
{
"name": "projectName",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"gulp": "^4.0.2",
"gulp-autoprefixer": "^7.0.1",
"gulp-babel": "^8.0.0",
"gulp-cssnano": "^2.1.3",
"gulp-mode": "^1.0.2",
"gulp-sass": "^4.1.0",
"gulp-sourcemaps": "^3.0.0",
"gulp-uglify": "^3.0.2",
"webpack-stream": "^6.1.1"
}
}