That Sounds Complicated!
- automate the most irritating tasks first
- try not to over-complicate your build process; an hour or two is more than enough for the initial set-up
- choose task runner software and stick with it for a while.
Task Runners: Gulp
- Features such as file watching were built-in.
- Gulp plug-ins were (mostly) designed to do a single job.
- Gulp used JavaScript configuration code which was less verbose, easier to read, simpler to modify, and provided better flexibility.
- Gulp was faster because it uses Node.js streams to pass data through a series of piped plug-ins. Files were only written at the end of the task.
Step 1: Node.js
node -v
npm
– the Node.js package manager which is used to install modules. Examine its version number:npm -v
npm
commands are prefixed with sudo
. There are a number of options to fix npm permissions and tools such as nvm can help but I often change the default directory, e.g. on Ubuntu/Debian-based platforms:cd ~
mkdir .node_modules_global
npm config set prefix=$HOME/.node_modules_global
npm install npm -g
~/.bashrc
:export PATH="$HOME/.node_modules_global/bin:$PATH"
source ~/.bashrc
Step 2: Install Gulp Globally
gulp
command can be run from any project folder:npm install gulp-cli -g
gulp -v
Step 3: Configure Your Bulid
package.json
configuration file.project1
. Navigate to this folder and initialize it with npm:cd project1
npm init
package.json
file will be created on completion which stores your npm
configuration settings.
src
folder: pre-processed source files
html
– HTML source filesimages
— the original uncompressed imagesjs
— multiple pre-processed script filesscss
— multiple pre-processed Sass.scss
files
build
folder: compiled/processed files
html
– compiled static HTML filesimages
— compressed imagesjs
— a single concatenated and minified JavaScript filecss
— a single compiled and minified CSS file
mkdir -p src/{html,images,js,scss} build/{html,images,js,css}
Step 3a: Install Gulp
npm install gulp --save-dev
"devDependencies"
section of package.json
is updated accordingly.Step 4: Create a Gulpfile.js
gulpfile.js
configuration file in the root of your project folder. Add some basic code to get begined:// Gulp.js configuration
var
// modules
gulp = require('gulp'),
// development mode?
devBuild = (process.env.NODE_ENV !== 'production'),
// folders
folder = {
src: 'src/',
build: 'build/'
}
;
devBuild
variable to true
when running in development (or non-production mode) and defines the source and build folder locations.Step 5: Create new Gulp Tasks
- install Gulp plug-ins, and
- write tasks which utilize those plug-ins to do something useful.
gulp.task
– defines a new task with a name, optional array of dependencies and a function.gulp.src
– sets the folder where source files are located.gulp.dest
– sets the destination folder where build files will be placed.
pipe
between the .src
and .dest
.Image Task
build
folder. Since this process could take time, we’ll only compress new and modified files. Two plug-ins can help us: gulp-newer and gulp-imagemin. Install them from the command-line:npm install gulp-newer gulp-imagemin --save-dev
gulpfile.js
:// Gulp.js configuration
var
// modules
gulp = require('gulp'),
newer = require('gulp-newer'),
imagemin = require('gulp-imagemin'),
gulpfile.js
:// image processing
gulp.task('images', function() {
var out = folder.build + 'images/';
return gulp.src(folder.src + 'images/**/*')
.pipe(newer(out))
.pipe(imagemin({ optimizationLevel: 5 }))
.pipe(gulp.dest(out));
});
- Creates a new task named
images
. - Defines a function with a return value which…
- Defines an
out
folder where build files will be located. - Sets the Gulp
src
source folder. The/**/*
ensures that images in sub-folders are also processed. - Pipes all files to the
gulp-newer
module. Source files that are newer than corresponding destination files are passed through. Everything else is removed. - The remaining new or changed files are piped through
gulp-imagemin
which sets an optionaloptimizationLevel
argument. - The compressed images are output to the Gulp
dest
folder set byout
.
gulpfile.js
and place a few images in your project’s src/images
folder before running the task from the command line:gulp images
Using file gulpfile.js
Running 'imagemin'...
Finished 'imagemin' in 5.71 ms
gulp-imagemin: image1.png (saved 48.7 kB)
gulp-imagemin: image2.jpg (saved 36.2 kB)
gulp-imagemin: image3.svg (saved 12.8 kB)
gulpimages
again and nothing should happen because no newer images exist.HTML Task
npm install gulp-htmlclean --save-dev
gulpfile.js
:var
// modules
gulp = require('gulp'),
newer = require('gulp-newer'),
imagemin = require('gulp-imagemin'),
htmlclean = require('gulp-htmlclean'),
html
task at the end of gulpfile.js
:// HTML processing
gulp.task('html', ['images'], function() {
var
out = folder.build + 'html/',
page = gulp.src(folder.src + 'html/**/*')
.pipe(newer(out));
// minify production code
if (!devBuild) {
page = page.pipe(htmlclean());
}
return page.pipe(gulp.dest(out));
});
gulp-newer
and introduces a couple of concepts:- The
[images]
argument states that ourimages
task must be run before processing the HTML (the HTML is likely to reference images). Any number of dependent tasks can be listed in this array and all will complete before the task function runs. - We only pipe the HTML through
gulp-htmlclean
ifNODE_ENV
is set toproduction
. Therefore, the HTML remains uncompressed during development which may be useful for debugging.
gulpfile.js
and run gulp html
from the command line. Both the html
and images
tasks will run.JavaScript Task
- ensure dependencies are loaded first using the gulp-deporder plug-in. This analyses comments at the top of each script to ensure correct ordering e.g.
// needs: defaults.js lib.js
. - concatenate all script files into a single
main.js
file using gulp-concat, and - remove all
console
anddebugging
statements with gulp-strip-debug and minimize code with gulp-uglify. This step will only occur when running in production mode.
npm install gulp-deporder gulp-concat gulp-strip-debug gulp-uglify --save-dev
gulpfile.js
:var
...
concat = require('gulp-concat'),
deporder = require('gulp-deporder'),
stripdebug = require('gulp-strip-debug'),
uglify = require('gulp-uglify'),
js
task:// JavaScript processing
gulp.task('js', function() {
var jsbuild = gulp.src(folder.src + 'js/**/*')
.pipe(deporder())
.pipe(concat('main.js'));
if (!devBuild) {
jsbuild = jsbuild
.pipe(stripdebug())
.pipe(uglify());
}
return jsbuild.pipe(gulp.dest(folder.build + 'js/'));
});
gulp js
to watch the magic happen!CSS Task
.scss
files to a single .css
file using gulp-sass. This is a Gulp plug-in for node-sass which binds to the super-fast LibSass C/C++ port of the Sass engine (you won’t need to install Ruby). We’ll presume your primary Sass file scss/main.scss
is responsible for loading all partials.- postcss-assets to manage assets. This allows us to use properties such as
background: resolve('image.png');
to resolve file paths orbackground: inline('image.png');
to inline data-encoded images. - autoprefixer to automatically add vendor prefixes to CSS properties.
- css-mqpacker to pack multiple references to the same CSS media query into a single rule.
- cssnano to minify the CSS code when running in production mode.
npm install gulp-sass gulp-postcss postcss-assets autoprefixer css-mqpacker cssnano --save-dev
gulpfile.js
:var
...
sass = require('gulp-sass'),
postcss = require('gulp-postcss'),
assets = require('postcss-assets'),
autoprefixer = require('autoprefixer'),
mqpacker = require('css-mqpacker'),
cssnano = require('cssnano'),
css
task at the end of gulpfile.js
. Note the images
task is set as a dependency because the postcss-assets
plug-in can reference images during the build process. In addition, most plug-ins can be passed arguments – refer to their documentation for more information:// CSS processing
gulp.task('css', ['images'], function() {
var postCssOpts = [
assets({ loadPaths: ['images/'] }),
autoprefixer({ browsers: ['last 2 versions', '> 2%'] }),
mqpacker
];
if (!devBuild) {
postCssOpts.push(cssnano);
}
return gulp.src(folder.src + 'scss/main.scss')
.pipe(sass({
outputStyle: 'nested',
imagePath: 'images/',
precision: 3,
errLogToConsole: true
}))
.pipe(postcss(postCssOpts))
.pipe(gulp.dest(folder.build + 'css/'));
});
gulp css
Step 6: Automate You Gulp Tasks
run
task to gulpfile.js
:// run all tasks
gulp.task('run', ['html', 'css', 'js']);
gulp run
at the command line to execute all tasks. Note I omitted the images
task because it’s already set as a dependency for the html
and css
tasks.gulp.watch
– which can monitor your source files and run an appropriate task whenever a file is changed. The method is passed a folder and a list of tasks to execute when a change occurs. Let’s create a new watch
task at the end of gulpfile.js
:// watch for changes
gulp.task('watch', function() {
// image changes
gulp.watch(folder.src + 'images/**/*', ['images']);
// html changes
gulp.watch(folder.src + 'html/**/*', ['html']);
// javascript changes
gulp.watch(folder.src + 'js/**/*', ['js']);
// css changes
gulp.watch(folder.src + 'scss/**/*', ['css']);
});
gulp watch
immediately, let’s add a default task:// default task
gulp.task('default', ['run', 'watch']);
gulpfile.js
and enter gulp
at the command line. Your images, HTML, CSS and JavaScript will all be processed then Gulp will remain active watching for updates and re-running tasks as necessary. Hit Ctrl/Cmd + C to abort monitoring and return to the command line.Step 7: Yupi!
- gulp-load-plugins – load all Gulp plug-in modules without
require
declarations - gulp-preprocess – a simple HTML and JavaScript preprocessor
- gulp-less – the Less CSS pre-processor plug-in
- gulp-stylus – the Stylus CSS pre-processor plug-in
- gulp-sequence – run a series of gulp tasks in a specific order
- gulp-plumber – error handling which prevents Gulp stopping on failures
- gulp-size – displays file sizes and savings
- gulp-nodemon – uses nodemon to automatically rebegin Node.js applications when changes occur.
- gulp-util – utility functions including logging and color-coding
gulp-util
is .noop()
which passes data straight through without performing any action. This could be used for cleaner development/production processing code, e.g.var gutil = require('gulp-util');
// HTML processing
gulp.task('html', ['images'], function() {
var out = folder.src + 'html/**/*';
return gulp.src(folder.src + 'html/**/*')
.pipe(newer(out))
.pipe(devBuild ? gutil.noop() : htmlclean())
.pipe(gulp.dest(out));
});
- browser-sync – automatically reload assets or refresh your browser when changes occur
- del – delete files and folders (perhaps clean your
build
folder at the begin of every run).
- plug-ins are plentiful
- configuration using pipes is readable and easy to follow
gulpfile.js
can be adapted and reused in other projects- your total page weight can be reduced to improve performance
- you can simplify your deployment.
Read More »