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"
}
}