Gulp 4 Tutorial
Ganesh Shinde
Posted on June 20, 2021
Table of Contents
- What is Gulp?
- Common Tasks
- Prerequisites
- Create package.json
- Install Packages
- Create gulpfile.js
- Import Packages
- Add Paths
- Create Tasks
- Export Tasks
- Run Tasks
- My gulpfile.js
What is Gulp?
- Gulp is an open source Javascript toolkit and task runner
- It was built on Node.js and NPM
- Used for time consuming and repetitive tasks
- Hundreds of plugins available for different tasks
Common Tasks
- Minification of styles and scripts
- Concatenation
- Cache busting
- Testing, linting and optimization
Prerequisites
Install Node.js
Install Gulp globally using following command in command line.
By default latest version will get installed.
npm install -g gulp
Check if Gulp is installed properly, Then we are good to move forward.
npm gulp --version
Create package.json
First create new directory for our project, if you already have one no need to create new.
Open command prompt and change current working directory as our project directory using below command (change path accordingly).
# Absolute path of directory
cd c:/projects/my-project
Now create package.json
file for our project using below command.
npm init -y
Install Packages
Install required packages and save them as development dependencies using below command.
npm install --save-dev gulp gulp-concat gulp-rename gulp-replace gulp-imagemin gulp-sourcemaps gulp-sass postcss gulp-postcss autoprefixer cssnano gulp-terser
Find below, Purpose of installed packages.
gulp gulp-concat gulp-rename gulp-replace
- Basic file operations such as concatenation, file renaming and file content replacement.
gulp-imagemin
- Image optimization.
gulp-sourcemaps
- Sourcemaps creation for styles and scripts.
gulp-sass postcss gulp-postcss autoprefixer cssnano
- sass/scss compilation, Add vendor prefixes and minify styles.
gulp-terser
- Minify scripts.
After this our package.json
file will contain data something like below.
"devDependencies": {
"autoprefixer": "^10.2.5",
"cssnano": "^5.0.2",
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"gulp-imagemin": "^7.1.0",
"gulp-postcss": "^9.0.0",
"gulp-rename": "^2.0.0",
"gulp-replace": "^1.1.3",
"gulp-sass": "^4.1.0",
"gulp-sourcemaps": "^3.0.0",
"gulp-terser": "^2.0.1",
"postcss": "^8.2.15"
}
Create gulpfile.js
Open project in code editor and create gulpfile.js
.
In this file we will define all the tasks that we want to automate.
Import Packages
Write below code inside gilpfile.js
.
It will import all those installed packages, So that we can use them to perform tasks.
const gulp = require('gulp');
const { src, dest, watch, series, parallel } = require('gulp');
const imagemin = require('gulp-imagemin');
const sourcemaps = require('gulp-sourcemaps');
const concat = require('gulp-concat');
const rename = require('gulp-rename');
const replace = require('gulp-replace');
const terser = require('gulp-terser');
const sass = require('gulp-sass');
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
Add Paths
Add below object of paths into gulpfile.js
.
We are using this object because its the most convenient way to handle paths. It adds maintainability to our code.
const paths = {
html: {
src: ['./src/**/*.html'],
dest: './dist/',
},
images: {
src: ['./src/content/images/**/*'],
dest: './dist/content/images/',
},
styles: {
src: ['./src/scss/**/*.scss'],
dest: './dist/css/',
},
scripts: {
src: ['./src/js/**/*.js'],
dest: './dist/js/',
},
cachebust: {
src: ['./dist/**/*.html'],
dest: './dist/',
},
};
Selectors
Pattern | Match |
---|---|
*.scss | Matches any file ending with .scss from current directory |
*/.scss | Matches any file ending with .scss from current directory and any child directory |
*.+(scss|sass) | Matches any file ending with .scss or .sass from current directory |
Folder Structure
We will keep all our files in src
directory and then using Gulp tasks we will create optimized files in dist
directory.
Above paths object is created based on this folder structure.
Create Tasks
Gulp performs actions on files in pipeline. Pipeline / .pipe()
operator is nothing but chained processes running synchronously.
Files are not affected until all processes are completed.
Gulp .src()
and .dest()
operators are used to read and write files.
Below is the basic syntax for creating a Gulp task.
function task_name() {
return src('source-location') // Select files from given location
.pipe(gulpPlugin()) // Send files through a gulp plugin
.pipe(dest('destination-location')); // Write modified files at given location
}
Copy Files
Copy HTML files from src to dest location using below function.
We can add more function like this in case we want to copy some other files such as fonts or media files.
For that, All we need to do is add paths in the paths object.
Then create new function just as below and update src and dest paths.
function copyHtml() {
return src(paths.html.src).pipe(dest(paths.html.dest));
}
Optimize Images
Optimize all types of images(.png, .jpeg, .gif, .svg).
If any error occurs during performing the task, We will be logging that to the console.
function optimizeImages() {
return src(paths.images.src)
.pipe(imagemin().on('error', (error) => console.log(error)))
.pipe(dest(paths.images.dest));
}
Compile Styles
Compile sass/scss and convert them into optimized css.
Keep all the tasks that needs to be done on styles between sourcemaps.init()
and sourcemaps.write('.')
, Otherwise sourcemaps won't be generated properly.
We are using cssnano
to optimize our styles that's why we are renaming files with .min
suffix (Indicating minified).
function compileStyles() {
return src(paths.styles.src)
.pipe(sourcemaps.init())
.pipe(sass().on('error', sass.logError))
.pipe(postcss([autoprefixer(), cssnano()]))
.pipe(rename({ suffix: '.min' }))
.pipe(sourcemaps.write('.'))
.pipe(dest(paths.styles.dest));
}
Minify Scripts
Optimize scripts using below function.
function minifyScripts() {
return src(paths.scripts.src)
.pipe(sourcemaps.init())
.pipe(terser().on('error', (error) => console.log(error)))
.pipe(rename({ suffix: '.min' }))
.pipe(sourcemaps.write('.'))
.pipe(dest(paths.scripts.dest));
}
Cache Busting
Browser cache files which we link in our .html
files and next time use cached files whenever request is made for the same .html
page.
This sometimes creates issue like, Browser still uses old cached files even if we have done changes in the files. This is known as browser caching issue.
Cache busting solves the browser caching issue by using a unique file version identifier to tell the browser that a new version of the file is available. Therefore the browser doesn't retrieve the old file from cache but rather makes a request to the origin server for the new file.
To make this work we will add cache_bust
parameter (with any number) to all style and script urls in our .html
files.
<html>
<head>
<link rel="stylesheet" href="/dist/css/style.min.css?cache_bust=123" />
</head>
<body>
<script src="/dist/js/script.min.js?cache_bust=123"></script>
</body>
</html>
Now using below function we will replace these cache_bust
parameter value with unique number. So that these urls will be unique, Browser will know that url is changed and instead of using already cached file it will request for the file from the server.
function cacheBust() {
return src(paths.cachebust.src)
.pipe(replace(/cache_bust=\d+/g, 'cache_bust=' + new Date().getTime()))
.pipe(dest(paths.cachebust.dest));
}
Watch Files
Watch for file modification at specific paths and run respective tasks accordingly.
watch('path-to-watch',[tasks-to-perform]);
We can perform as many tasks as we want using series()
and parallel()
operators.
series()
will execute tasks synchronously and parallel()
will execute tasks asynchrously.
function watcher() {
watch(paths.html.src, series(copyHtml, cacheBust));
watch(paths.images.src, optimizeImages);
watch(paths.styles.src, parallel(compileStyles, cacheBust));
watch(paths.scripts.src, parallel(minifyScripts, cacheBust));
}
Export Tasks
Export created tasks so that they will be accessible to execute from command line.
exports.copyHtml = copyHtml;
exports.optimizeImages = optimizeImages;
exports.compileStyles = compileStyles;
exports.minifyScripts = minifyScripts;
exports.cacheBust = cacheBust;
exports.watcher = watcher;
Create one default task which will execute all the tasks that we want and later starts watching files for modification.
exports.default = series(
parallel(copyHtml, optimizeImages, compileStyles, minifyScripts),
cacheBust,
watcher
);
Run Tasks
Run any specific task using below command.
gulp task_name
Run default task using below command.
gulp
To stop watcher
task, which continuously watch for file modifications, press ctrl + c
in command line and answer asked question as Y
.
^CTerminate batch job (Y/N)? Y
My gulpfile.js
Check out my gulpfile.js for reference.
Posted on June 20, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.