@rob_rich

Welcome to gulp

by Rob Richardson

@rob_rich

http://robrich.org/

June 18, 2014

About Me

Rob Richardson is a local software craftsman building web properties in ASP.NET and Node. He's a frequent speaker at conferences, user groups, and community events, and a diligent teacher and student of high quality software development. You can find this and other talks on his blog at http://robrich.org/presentations and follow him on twitter at @rob_rich.

The streaming build system

FAQ

Is it "gulp" or "Gulp"?

gulp is always lowercase.

source: https://github.com/gulpjs/gulp/blob/master/docs/FAQ.md

Why is gulp better?

  • streams: avoid writing temporary states to disk is faster
  • code over configuration: easier to reason about
  • easy to learn: it's just a javascript file
  • easy to use: debug with your normal node tools

General Methodology

  • Files stream in
  • Through a series of transforms
  • Result is written to disk

Example

  • Read all JavaScript files
  • Lint using JSHint
  • Minify using uglify
  • Concatenate together
  • Add header content
    (e.g. copyright and build date)
  • Write to disk

Example

						
gulp.src('./**/*.js')
  .pipe(jshint())
  .pipe(jshint.reporter())
  .pipe(uglify())
  .pipe(concat('all.min.js'))
  .pipe(header('/** Copyright '+new Date().getFullYear()+' **/'))
  .pipe(gulp.dest('build/js'));
						
					

gulp Methodology

Traditional build systems:

  • A series of steps
  • Disk read, do something, disk write
  • Tasks are build steps:
    • clean
    • build
    • test
    • deploy

gulp:

  • Files stream through transforms
  • Tasks are workflows or processes:
    • scripts
    • styles
    • html
    • live reload

Streams

Streams

						
gulp.src('./**/*.js')
  .pipe(jshint())
  .pipe(jshint.reporter())
  .pipe(uglify())
  .pipe(concat('all.min.js'))
  .pipe(header('/** Copyright '+new Date().getFullYear()+' **/'))
  .pipe(gulp.dest('build/js'));
						
					

Node Streams

						
	src.pipe(dest)
						
					

from stream handbook

Node Streams

Node:
						a.pipe(b).pipe(c).pipe(d)
					
Bash:
						a | b | c | d
					

from stream handbook

Node Streams

						
var through2 = require('through2');
a.pipe(through2.obj(function (data, enc, cb) {
  // do something with data object
  this.push(data);
  cb();
}))
.pipe(b)
						
					

Stream Resources

gulp API

Walkthrough:
Sample gulpfile.js

gulp piping tools API

  • gulp.src(glob): pipe in files
  • gulp.dest(path): write out files
  • gulp.watch(glob, [tasks]): do tasks when file changes

gulp tasks API

  • gulp.task(name, [dependencies], function(cb)): define a task

gulp CLI

gulp task1 task2

Can install it globally

npm install -g gulp

Or rig it through npm run commands in package.json:

npm install --save-dev gulp

	...
},
"scripts": {
  "test": "gulp test",
  "watch": "gulp watch"
},
"devDependencies": {
  "gulp": "^3.8.0",
  ...
					

DEMO:
building a gulpfile

Find gulp Plugins

gulpjs.com/plugins

Build gulp Plugins

						
var through2 = require('through2');

module.exports = function (opts) {
  return through2.obj(function (file, enc, cb) {

    // do something with vinyl fs file
    file.contents = Buffer.concat([opts.text, file.contents]);

    this.push(file);
    cb();
  };
};
						
					

gulp plugin guidelines

Publish gulp Plugins

add keyword "gulpplugin" (if it works with vinyl-fs files)
or "gulpfriendly" (if it doesn't)


	...
},
"keywords": [
  "gulpplugin"
],
"dependencies": {
  "through2": "^0.4.2",
  ...
					

gulp plugin guidelines

Don't Build gulp Plugins

Your gulpfile is just a JavaScript file

Don't build a plugin to do normal Node tasks


function startExpress() {
  var express = require('express');
  var app = express();
  app.use(require('connect-livereload')());
  app.use(express.static(__dirname));
  app.listen(4000);
}
					

Don't Build gulp Plugins

Your gulpfile is just a JavaScript file

Don't build a plugin to do normal Node tasks

(it's a great way to get your plugin blacklisted)

You're locked into plugin's library version

gulp Best Practices

  • Tasks aren't workflow steps, they're CLI-named functions
  • It doesn't have to be a plugin
  • Tell gulp how your task will end
  • If you're struggling with a task workflow, imagine how you'd do it without gulp (hint: async)

gulp Resources