Gulp

The streaming build system



@wearefractal













Streams























Your application is not a big truck - it's a series of tubes











We should have some ways of connecting programs like garden hose--screw in another segment when it becomes necessary to massage data in another way. This is the way of IO also. - Doug McIlroy - Doug McIlroy





Streams come to us from the earliest days of unix and have proven themselves over the decades as a dependable way to compose large systems out of small components that do one thing well.

You can then plug the output of one stream to the input of another and use libraries that operate abstractly on streams to institute higher-level flow control. - substack

- substack

Understanding flow control is what makes you a programmer



Read a comprehensive overview of streams by substack

https://github.com/substack/stream-handbook



Learning new flow control techniques will make you more efficient













Why streams?































Picture a build system in your head.

(It should take in files, modify them, and output the new ones)

You pictured this

You didn't picture this













Grunt





















What's so bad?

Plugins do multiple things

Want a banner? Use the javascript minifier

Plugins do things that don't need to be plugins

Need to run your tests? Use a plugin

Grunt config format is a mess that tries to do everything

Not idiomatic with "the node way"

Headache of temp files/folders due to bad flow control



Your build system should empower not impede It should only manipulate files - let other libraries handle the rest.

Sample Gruntfile module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), concat: { options: { separator: ';' }, dist: { src: ['src/**/*.js'], dest: 'dist/<%= pkg.name %>.js' } }, uglify: { options: { banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */

' }, dist: { files: { 'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>'] } } }, qunit: { files: ['test/**/*.html'] }, jshint: { files: ['gruntfile.js', 'src/**/*.js', 'test/**/*.js'], options: { // options here to override JSHint defaults globals: { jQuery: true, console: true, module: true, document: true } } }, watch: { files: ['<%= jshint.files %>'], tasks: ['jshint', 'qunit'] } }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-qunit'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.registerTask('test', ['jshint', 'qunit']); grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']); }; Runs tests

Lints code

Concats javascript

Minifies it

Runs again if files are changed



Switching





Sample Gulpfile var gulp = require('gulp'); var pkg = require('./package.json'); var concat = require('gulp-concat'); var minify = require('gulp-minify'); var jshint = require('gulp-jshint'); var spawn = require('child_process').spawn; var scriptFiles = './src/**/*.js'; gulp.task('compile', function(){ // concat all scripts, minify, and output gulp.src(scriptFiles) .pipe(concat({fileName: pkg.name+".js"}) .pipe(minify()) .pipe(gulp.dest('./dist/')); }); gulp.task('test', function(){ // lint our scripts gulp.src(scriptFiles).pipe(jshint()); // run our tests spawn('npm', ['test'], {stdio: 'inherit'}); }); gulp.task('default', function(){ gulp.run('test', 'compile'); gulp.watch(scriptFiles, function(){ gulp.run('test', 'compile'); }); }); Runs tests

Lints code

Concats javascript

Minifies it

Runs again if files are changed



What's the difference?

With Gulp your build file is code, not config

You use standard libraries to do things

Plugins are simple and do one thing - most are a ~20 line function

Tasks are executed with maximum concurrency

I/O works the way you picture it







Gulp does nothing but provide some streams and a basic task system





Gulp has only 5 functions you need to learn











gulp.task(name, fn)



It registers the function with a name.

You can optionally specify some dependencies if other tasks need to run first.





gulp.run(tasks...)







Runs all tasks with maximum concurrency



gulp.watch(glob, fn)





Runs a function when a file that matches the glob changes





Included in core for simplicity

gulp.src(glob)

This returns a readable stream.

Takes a file system glob (like grunt) and starts emitting files that match.



This is piped to other streams

gulp.dest(folder)

This returns a writable stream

File objects piped to this are saved to the file system











Congratulations



You are now a Gulp expert









For guides on how to make your own plugins check the README

Links

https://github.com/wearefractal/gulp Gulp -

