Gulp Jekyll Workflow - Part 1 Design Pattern
Always start with the end in mind. So you know what direction to travel
— Ian Teda
Keeping the end in mind, I listed four design criteria (patterns) to target when writting Gulp tasks. I wanted my workflow to be modern, simple, configurable and modulised.
Design Criteria/Patterns
- Use ES2015, ECMAScript 2015 (modern): Why? Get accustom to new JavaScript features before they become mainstream.
- Command Line Interface (simple): Why? KISS. Keep It Simple Stupid. A good design is a simple yet functional design.
- Configuration File (configurable): Why? Make changes in one place, watch them permiate. Easier to read and maintain code.
- Modulised Gulp tasks: Why? Makes for more readable, easier to reuse and maintainable code.
1 - Use ES2015 with Gulp
To paraphrase the Babel tagline. Use next generation JavaScript, today with Babel. Since the release of Gulp (gulp-cli) version +3.9 gulp -v
it is as easy as 1-2-3 to use ES2015 while writting Gulp tasks 1.
To get babel plugged into Gulp I used the following 3 steps:
1 - Install npm packages for Babel and babel presents
npm install babel-core babel-preset-es2015 --save-dev
2 - Create a .babelrc
file to enable 2015 presets
{
"presets": ["es2015"]
}
3 - Rename gulpfile.js
to gulpfile.babel.js
Done. See, as easy as 1-2-3.
2 - Command Line Interface with Yargs
Paraphrasing the Yargs tagline. Build interactive command line tools by parsing arguments and generating an elegant user interface. Keeping with my design criteria, I refractored the Yargs configuration into a seperate config file yargs.config.js
. Which is then required from within the gulpfile.babel.js
. Keeping things neat and tidy.
Require Yargs configuration file within gulpfile.babel.js
.
// Command line (CLI) argument
var argv = require("./gulp/yargs.config");
Setup the user interface and configure the CLI arguments yargs.config.js
2.
/**
* CLI (YARGS) Configuration
* @param {yargs} yargs - Module for handling CLI arguments
* @exports {argv} argv - Argument object
*/
module.exports = require("yargs")
.usage("Usage: Gulp <task> [-p -prod -production]")
.command("script", "Run script tasks", {alias: "scripts"})
.boolean("production")
.alias("production", ["p", "prod"])
.describe("production", "Run Gulp tasks in production mode")
.help("help")
.alias("help", "?")
.argv;
3 - Gulp Configuration File
Make changes in one place, watch them permiate. Which equals easier to read and maintain code.
gulp.babel.js
// Configuration file for gulp tasks
const config = require("./gulp/gulp.config");
gulp.config.js
module.exports = {
xyz: {
src: "src/xyz.xyz",
options: {
a: true,
b: false
},
dest: "src/"
}
}
4 - Modulise Gulp Tasks
Modulisation of Gulp tasks makes for more readable, easier to reuse and maintain code.
Always abstract anything you need to do more than once. With that in mind a requireTask function is used to require task files from within gulp.babel.js
. 3
// Import Gulp module
import gulp from "gulp";
// Command line (CLI) argument
var argv = require("./gulp/yargs.config");
// Configuration file for gulp tasks
const config = require("./gulp/gulp.config");
// Lazy load plugins, makes for neater source code
var plugins = require("gulp-load-plugins")(config.gulpLoadPlugins.options);
/**
* Require Gulp Task
* @param {task} task - What Gulp task do you require
* @return {function} function - Returns task function from module export
*/
function requireTask(task) {
// Require Gulp task module, passing in Gulp, config, argv and plugin object references
return require("./gulp/tasks/" + task + ".task.js")(
gulp,
config,
argv,
plugins
);
}
gulp.task("scripts:build", requireTask("nameOfTask"));
The task ./gulp/tasks/nameOfTask.task.js
is built up using the NodeJS module pattern, returing the task stream. Returning the task stream is important as it allows Gulp to signal async task completion. With task configuration from withing the gulp.config.js
file.
"use strict";
/**
* Gulp Task for doing XYZ
* @param {gulp} gulp - The gulp module passed in
* @param {config} config - The projects Gulp config file
* @param {argv} argv - Arguments flagged at the CLI
* @param {$} $ - Lazy load plugins, save the imports at the start of the file
* @return {stream} Stream - Task stream to manage XYZ in project
*/
module.exports = (gulp, config, argv, $) => {
return function() {
var stream = gulp
// XYZ source files
.src(config.xyz.src)
// Apply special Gulp source
.pipe($.if(
!argv.prod,
$.specialsource(config.specialsource.options
)
// Write stream to destination folder
.pipe(gulp.dest(config.xyz.dest));
return stream;
};
};
5 - Just Show Me the Repository Already
If you would like to see it in action, check out the repositry for this website at https://github.com/IanTeda/IanTeda.github.io