Jesse Harlin PRO
I am a developer, musician and usergroup leader living and working in Oklahoma, US.
with Gulp and Slush
Why streams?
What is a task runner?
What is a scaffold?
Why Gulp?
Why Slush?
Gulp.js
Whats a task runner?
On in a word...
Much task.
Very Choice.
(mostly) Objectively speaking
But also...
and in my opinion...
POWER-TOOL
POWER-TOOL
I know what some of you might be thinking...
Hey Wait!
We're a C# Shop!
..we have NUGET
..and VISUAL STUDIO!
and like. microsofty..stuff...
(Your home-slice Scott 'Rocket Punch', H, just chillin wearin' a gulp shirt.)
So if you are in a c# environment..
(as many of you may be)
Trust your boy, Scott...Get the full scoop here:
www.hanselman.com
Or you can do what the rest of us do...
npm install -g gulp
"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 Mcllroy, 1964
a.pipe(b).pipe(c).pipe(d)
Read the FANTASTIC Manual
https://github.com/substack/stream-handbook
Substack wrote this, and its good read even out of the context of gulp, honestly.
npm install -g stream-handbook
Big Whoop.
What can I
REALLY
do?
More like
what
CAN'T
you do.
This is how you REALLY get it DONE
0. require gulp
1. require plugins
2. declare tasks (more on that later)
3. task order/separate from tasks (queue)
4. call tasks.
var gulp = require('gulp'),
concat = require('gulp-concat'),
minify = require('gulp-minify');
var scriptFiles = './src/**/*.js';
function build(){
gulp
.src(scriptFiles)
.pipe(concat({fileName: "funky-town.js"})
.pipe(minify())
.pipe(gulp.dest('./dist/'));
}
gulp.task('build', build);
A simple, yet comon scenario.
A BUILD
gulp build
gulp.task('build', build);
If this is your JS file:
This is what you type on the command line:
And then?...
A simple, yet comon scenario.
A BUILD
var gulp = require('gulp'),
concat = require('gulp-concat'),
minify = require('gulp-minify');
var scriptFiles = './src/**/*.js';
function build(){
gulp
.src(scriptFiles)
.pipe(concat({fileName: "funky-town.js"})
.pipe(minify())
.pipe(gulp.dest('./dist/'));
}
gulp.task('build', build);
1. Glob goes in
2. pipe, pipe,pipe,
3. ...files go out.
"you can't explain that"
This is only the surface.
USE YOUR IMAGINATION
"I got 5 on it"
The 5
Noble Tasks
.run(tasks)
.watch(glob, taskFn)
.src(glob)
.dest(folder)
How To
How To
Stream
Returning nothing is probably not what you want, because you might introduce
Race Conditions
POWER TIP
Return a stream
Return a callback
var gulp = require('gulp');
var coveralls = require('gulp-coveralls');
function lcov() {
return gulp
.src('coverage/**/lcov.info')
.pipe(coveralls());
}
gulp.task('coveralls', lcov)
var gulp = require('gulp');
var istanbul = require('gulp-istanbul');
var mocha = require('gulp-mocha');
var gutil = require('gulp-util');
function test(cb) {
function runner() {
return gulp
.src(testGlob)
.pipe(mocha(mochaOpts))
.pipe(istanbul.writeReports())
.on('end', cb);
}
gulp
.src('./test-files')
.pipe(istanbul())
.pipe(istanbul.hookRequire())
.on('finish', runner)
.on('error', gutil.log);
}
gulp.task('test', test);
You can sequence these larger gestures into task chains!
They naturally run async, but you can use plugins to handle things further.
Basic Gulp task chain :
parallel
gulp.task('lots-of-stuff', ['task-1', 'task-2', 'task-3']);
run-sequence
var gulp = require('gulp'),
runSequence = require('run-sequence');
function runAllTasks(cb) {
runSequence('pretasks', 'posttask', cb);
}
gulp.task('pretasks', ['clean']);
gulp.task('posttask', ['build', 'lint', 'test']);
gulp.task('default', runAllTasks);
// npm install --save-dev gulp merge-stream
var gulp = require('gulp');
var merge = require('merge-stream');
gulp.task('test', function() {
var bootstrap = gulp.src('bootstrap/js/*.js')
.pipe(gulp.dest('public/bootstrap'));
var jquery = gulp.src('jquery.cookie/jquery.cookie.js')
.pipe(gulp.dest('public/jquery'));
return merge(bootstrap, jquery);
});
Combining Streams
gulp merge-stream
Scaffolding made simple.
+
=
Ask questions
Do stuff
And that's Slush.
Did I mention?
Hey, hold up!
What about that other scaffolding system?
I used that a few times and my scaffolding needs already taken care of
why do I even need this???
npm install -g slush
npm install -g gulp
npm install -g slush-generator
slush generator
Easy to use
Easy to make
1. think of questions
2. make a slushfile
3. call your generator
A basic slush task
// your callback
function callback(answers){
gulp
.src(__dirname + '/templates/**')
.pipe(template(answers))
.pipe(conflict('./'))
.pipe(gulp.dest('./'))
.pipe(install())
.on('end', function () {
done();
});
}
//every inquirer statement is made like this.
inquirer.prompt( questions, callback )
Ask questions
Do stuff
What do questions look like?
var prompts = [{
name: 'appName',
message: 'What is the name of your project?',
default: defaults.appName
}, {
name: 'appDescription',
message: 'What is the description?'
}, {
name: 'appVersion',
message: 'What is the version of your project?',
default: '0.1.0'
}, {
name: 'authorName',
message: 'What is the author name?',
default: defaults.authorName
}, {
name: 'authorEmail',
message: 'What is the author email?',
default: defaults.authorEmail
}, {
name: 'userName',
message: 'What is the github username?',
default: defaults.userName
}, {
type: 'confirm',
name: 'moveon',
message: 'Continue?'
}];
? What is the name of your project? ballz
? What is the description? Some description
? What is the version of your project? 6.6.6
? What is the author name? Jesse Harlin
? What is the author email? harlinjesse@gmail.com
? What is the github username? Jesse_Harlin
? Continue? Yes
{
appName: 'ballz',
appDescription: 'Some description',
appVersion: '6.6.6',
authorName: 'Jesse Harlin',
authorEmail: 'harlinjesse@gmail.com',
userName: 'Jesse_Harlin',
moveon: true
}
BUT WILL IT TEST?
TEST
You're darn tootin it will!
Test every little bit.
'use strict';
var inquirer = require('inquirer');
function mockPrompt(answers) {
function assignAnswer(prompt) {
if (!(prompt.name in answers)) {
answers[prompt.name] = prompt.default;
}
}
function inquirerPrompt(prompts, done) {
[].concat(prompts).forEach(assignAnswer);
done(answers);
}
inquirer.prompt = inquirerPrompt;
}
module.exports = mockPrompt;
Inquirer Fixture
var mockPrompt = require('./inquirer-prompt-fixture');
require('../slushfile');
var chai = require('chai'), //chai for assertion
gulp = require('gulp'),
mockGulpDest = require('mock-gulp-dest')(gulp), //here is our dest stub
expect = chai.expect; //I use expect, but I dont expect(you).to.also()
var mockPrompt = require('./inquirer-prompt-fixture'); //this is to mock inquirer
require('../slushfile'); //and the thing we are testing
describe('your awesome module!!!', function () {
describe('taskname', function () {
beforeEach(function () {
mockPrompt({
appName: 'test-app',
userName: 'the-simian',
authorName: 'Fancypants Harlin',
authorEmail: 'derp@derp.derp',
appDescription: 'some description',
moveon: true
});
});
it('should make a readme', function (done) {
function assertDirectories() {
mockGulpDest.assertDestContains('README.md');
done();
}
gulp
.start('default')
.once('task_stop', assertDirectories); //here's the tricky part....
});
});
});
simiansblog.com
jesseharlin.net
@5imian
By Jesse Harlin
I am a developer, musician and usergroup leader living and working in Oklahoma, US.