advanced javascript build pipelines using gulp.js

67
Advanced JavaScript Build Pipelines with Gulp.js

Upload: stefan-baumgartner

Post on 16-Jan-2017

499 views

Category:

Software


1 download

TRANSCRIPT

Advanced JavaScript

Build Pipelines

with Gulp.js

Let's talk a

short bit about

the JS build tool

revolution

HTML

CSS

JavaScript

Sass CoffeeScript LESS

P o s t C S S H A M L J a d e

U g l i f y E S 6 R e a c t J S

Browserify AngularJS

Ember CSSMin JSLint

ESHint ImageOptim Mocha

Jasmine TypeScript

1530 lines of code

original Ant tasks used:

concat — copy — delete — mkdir

Maybe Java isn't the right

tool?

Java is to JavaScript whatAlf is to Gandalf

Grunt started a boom

Gruntfiles get long

Grunt tasks get slow:

lots of reads

and writes

One unmanageable horde

of (sometimes)

low quality plug-ins

And then came Gulp

React is in love with

Webpack

Ember.js digs Broccoli.js

Ember.js digs Broccoli.js

So… every community seems

to have its preference

Stick with your communities

preference!

For all the rest?

Gulp might be a good,

very good option

Disclaimer

I (occasionally) contribute to

Gulp

I'm writing a book on Gulp

http://bit.ly/gulp-tool-book

39% off with 39baumgarcoupon code!

gulp.src(…) gulp.dest(…)

Reads files Writes files

gulp.src(…) .pipe(uglify()) gulp.dest(…)

gulp.src(…) .pipe(uglify()) gulp.dest(…).pipe(concat())

task

manager

streaming

file

system

file watcher

gulp.task('scripts', function() { !

return gulp.src(‘src/**/*.js') !

.pipe(uglify()) !

.pipe(concat('main.min.js')) !

.pipe(gulp.dest('dist')); !

}); !

!

gulp.task('default', function(done) { !

gulp.watch(‘src/**/*.js', gulp.parallel(‘scripts')); !

done(); !

}); !

undertaker.task('scripts', function() { !

return vinyl.src(‘src/**/*.js') !

.pipe(uglify()) !

.pipe(concat('main.min.js')) !

.pipe(vinyl.dest('dist')); !

}); !

!

undertaker.task('default', function(done) { !

chokidar.watch(‘src/**/*.js', undertaker.parallel(‘scripts')); !

done(); !

}); !

so similar … yet so

different?

Gulp

Streams

Browserify

Streams

var source = require(‘vinyl-source-stream’); !

!

var b = browserify({ !

entries: ['_js/main.js'] !

}); !

!

var bundle = function() { !

return b.bundle() !

.pipe(source(‘main.js’)) !

.pipe(gulp.dest('js')); !

} !

!

gulp.task(‘bundle’, bundle); !

This also goes the

other way around…

var app = express(); !

var router = express.Router(); !

!

router.get('/*', function(req, res) { !

var stream = request('http://host.to.forward.to' + req.originalUrl); !

stream.pipe(res); !

stream !

.pipe(source('.' + req.originalUrl)) !

.pipe(gulp.dest('./cachedir')); !

}); !

!

app.use(express.static('_site')); !

app.use(express.static('cachedir')); !

app.use(router); !

var app = express(); !

var router = express.Router(); !

!

router.get('/*', function(req, res) { !

var stream = request('http://host.to.forward.to' + req.originalUrl); !

stream.pipe(res); !

stream !

.pipe(source('.' + req.originalUrl)) !

.pipe(gulp.dest('./cachedir'));!

}); !

!

app.use(express.static('_site')); !

app.use(express.static('cachedir')); !

app.use(router); !

So start thinking

streams …

Multiple input formats

return gulp.src(‘src/**/*.coffee) !

.pipe(coffee()) !

.pipe(uglify()) !

.pipe(concat(‘main.js’)) !

.pipe(gulp.dest(‘build’)) !

Multiple input formats

return gulp.src(‘src/**/*.js) !

.pipe(uglify()) !

.pipe(concat(‘main.js’)) !

.pipe(gulp.dest(‘build’)) !

Multiple input formats

return gulp.src(‘src/**/*.js) !

.pipe(uglify()) !

.pipe(concat(‘main.js’)) !

.pipe(gulp.dest(‘build’)) !

the same!

Multiple input formats

And actually, you just want

one bundle in the end

What if we could

reuse parts of the

stream?

return gulp.src(‘app1/src/**/*.coffee’) !

.pipe(coffee()) !

.pipe(uglify() !

.pipe(concat(‘main.js’)) !

.pipe(gulp.dest('build')); !

var merge = require(‘merge2’); !

!

return merge(gulp.src(‘app1/src/**/*.coffee’) !

.pipe(coffee()), !

gulp.src(‘app1/src/**/*.js’)) !

.pipe(uglify() !

.pipe(concat(‘main.js’)) !

.pipe(gulp.dest('build')); !

var merge = require(‘merge2’); !

!

return gulp.src(‘app1/src/**/*.coffee’) !

.pipe(markdown()), !

.pipe(gulp.src(‘app1/src/**/*.js’), {passthrough: true}) !

.pipe(rename(blogFn)) !

.pipe(wrap(layoutStr)) !

.pipe(swig()) !

.pipe(gulp.dest('build')); !

Multiple bundles

And now we need this

over and over again

for all our applications…

var elems = [ !

{ dir: ‘app1’, bundleName: ‘app1.min.js’ }, !

{ dir: ‘app2’, bundleName: ‘app2.min.js’ } !

]; !

!

var streams = elems.map(function(el) { !

return gulp.src(el.dir + ‘src/**/*.coffee’) !

.pipe(coffee()), !

.pipe(gulp.src(el.dir + ‘src/**/*.js’), {passthrough: true}) !

.pipe(uglify()) !

.pipe(concat(el.bundleName)) !

}); !

return merge(streams) !

.pipe(gulp.dest('build')); !

Incremental

builds

Some tasks take long

gulp.src(‘scripts/*.js’) !

.pipe(uglify()) !

.pipe(gulp.dest()) !

.pipe(concat()) !

Too much is going on!

Each change: Uglify all

the files?

filter files

that have changed

do performance

heavy operations

remember the

old files

and continue

with the other ops

gulp.task('scripts', function () { !

return gulp.src('app/scripts/**/*.js') !

.pipe(cached('ugly')) !

.pipe(uglify()) !

.pipe(remember('ugly')) !

.pipe(concat('main.min.js')) !

.pipe(gulp.dest('dist/scripts')); !

}); !

gulp.task('scripts', function () { !

return gulp.src('app/scripts/**/*.js') !

.pipe(cached('ugly')) !

.pipe(uglify()) !

.pipe(remember('ugly')) !

.pipe(concat('main.min.js')) !

.pipe(gulp.dest('dist/scripts')); !

}); !

we use the cache to

check if files have

changed

gulp.task('scripts', function () { !

return gulp.src('app/scripts/**/*.js') !

.pipe(cached('ugly')) !

.pipe(uglify()) !

.pipe(remember('ugly')) !

.pipe(concat('main.min.js')) !

.pipe(gulp.dest('dist/scripts')); !

}); !

once we are done,

we remember all

the other files

we stored in

the cache

gulp.task('lint', function () { !

return gulp.src(‘src/**/*.js’) !

.pipe(jshint()) !

.pipe(jshint.reporter(‘default’)) !

.pipe(jshint.reporter(‘fail’)); !

}); !

gulp.task('lint', function () { !

return gulp.src(‘src/**/*.js’, { since: gulp.lastRun(‘lint’) }) !

.pipe(jshint()) !

.pipe(jshint.reporter(‘default’)) !

.pipe(jshint.reporter(‘fail’)); !

}); !

gulp.task('images', function () { !

return gulp.src(‘src/images/**/*.*’) !

!

.pipe(imagemin()) !

.pipe(gulp.dest(‘dist’)); !

}); !

gulp.task('images', function () { !

return gulp.src(‘src/images/**/*.*’) !

.pipe(newer(‘dist’)) !

.pipe(imagemin()) !

.pipe(gulp.dest(‘dist’)); !

}); !

When architecting

Gulp build pipelines…

Separate the process

from the content

Think about how the

basic pipeline would

look like

Think about how

your data looks like

And then posh your pipes up

with stream tools that

change your data accordingly

Thank you … !

@ddprrt

Material

Workshop files

https://github.com/frontend-tooling

https://github.com/frontend-tooling/sample-project-gulp

https://github.com/frontend-tooling/static-site-generator

http://fettblog.eu

http://speakerdeck.com/ddprrt

Reading Material

http://bit.ly/gulp-tool-book

39% off with 39baumgarcoupon code!