Pro Yearly is on sale from $80 to $50! »

Plumbin' Pipelines with Gulp.js - 3hr Workshop

Plumbin' Pipelines with Gulp.js - 3hr Workshop

With JavaScript being no toy language anymore our demands on a high quality development environment have risen tremendously. One part of a good development environment are build tools, and Gulp.js -- being the JavaScript streaming build system -- is but one of the many choices a developer has nowadays. For many however, it's considered to be the best! In this three hour workshop, we will take a good look into Gulp and its possibilities. After our in-depth 3 hour course you will be able to do the following:

- Know how Gulp's API and the ecosystem of its plugins work
- Create parallel and sequential execution chains to be in total control of your build flow
- Know how 3rd party Node modules evolve around Gulp and how they can be integrated
- Create incremental builds to speed up your build time
- Know how streams work in Node.js
- And use stream arrays and merge streams to plumb together sophisticated pipelines doing all the work for you

Join us and become a build plumber!

More information
http://github.com/frontend-tooling
http://bit.ly/gulp-tool-book
http://fettblog.eu

187d92c9284160ad908885ab096f5209?s=128

Stefan Baumgartner

November 10, 2015
Tweet

Transcript

  1. Plumbin' Pipelines with Gulp.js

  2. @Dynatrace @Ruxit

  3. @ddprrt fettblog.eu

  4. HTML CSS JavaScript

  5. 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 B r o w s e r i f y A n g u l a r J S E m b e r C S S M i n J S L i n t ESHint ImageOptim Mocha Jasmine TypeScript
  6. None
  7. None
  8. None
  9. None
  10. 1530 lines of code original Ant tasks used: concat —

    copy — delete — mkdir
  11. None
  12. Let's talk a short bit about the JS build tool

    revolution
  13. Grunt started a boom

  14. Gruntfiles get long

  15. Grunt tasks get slow

  16. lots of reads and writes

  17. And then came Gulp

  18. Disclaimer

  19. I (occasionally) contribute to Gulp

  20. I'm writing a book on Gulp http://bit.ly/gulp-tool-book 39% off with

    39baumgar
 coupon code!
  21. I don't know Java anymore Java is to JavaScript what


    Alf is to Gandalf
  22. Let's go!

  23. The ecosystem

  24. None
  25. Runtime environment JavaScript

  26. Package System for Node Host of all things Gulp plugins

  27. CLI Gulpfile PluginA PluginA

  28. CLI Gulpfile PluginA PluginA starts

  29. CLI Gulpfile PluginA PluginA loads starts

  30. CLI Gulpfile PluginA PluginA loads starts uses

  31. npm install -g gulp-cli npm init npm install --save-dev gulp

    touch gulpfile.js
  32. npm install -g gulpjs/gulp-cli#4.0 npm init npm install --save-dev gulpjs/gulp#4.0

    touch gulpfile.js
  33. The basics: Streams

  34. gulp.src(…) gulp.dest(…) Reads files Writes files

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

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

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

  38. to the command line!

  39. Gulp API • gulp.task creates a new task • It

    requires to return either a Stream, a Promise or an Observable • gulp.src “globs” files and returns a stream of virtual file objects • each file can be piped through a process (jshint, uglify, less, etc.) • gulp.dest saves the file back to the file system
  40. gulp.task('styles', function() { return gulp.src('app/styles/main.less') .pipe(less()) .pipe(minifyCSS()) .pipe(prefix()) .pipe(gulp.dest('dist/styles')); });

  41. gulp.task('styles', function() { return gulp.src('app/styles/main.less') .pipe(less()) .pipe(minifyCSS()) .pipe(prefix()) .pipe(gulp.dest('dist/styles')); });

    defines a new task
  42. gulp.task('styles', function() { return gulp.src('app/styles/main.less') .pipe(less()) .pipe(minifyCSS()) .pipe(prefix()) .pipe(gulp.dest('dist/styles')); });

    with a defined name
  43. gulp.task('styles', function() { return gulp.src('app/styles/main.less') .pipe(less()) .pipe(minifyCSS()) .pipe(prefix()) .pipe(gulp.dest('dist/styles')); });

    we load a certain file (or files) Starting here, we have virtual files in-memory instead of real files we
  44. gulp.task('styles', function() { return gulp.src('app/styles/main.less') .pipe(less()) .pipe(minifyCSS()) .pipe(prefix()) .pipe(gulp.dest('dist/styles')); });

    and pipe it through a series of operations
  45. gulp.task('styles', function() { return gulp.src('app/styles/main.less') .pipe(less()) .pipe(minifyCSS()) .pipe(prefix()) .pipe(gulp.dest('dist/styles')); });

    before we save it again on the "real" file system
  46. Tasks

  47. scripts styles lint

  48. scripts styles lint gulp.parallel

  49. scripts styles lint gulp.parallel gulp.series

  50. to the command line!

  51. Gulp API • The second parameter of gulp.task is always

    a function. • gulp.series is a task function that runs tasks in sequential order. • gulp.parallel is a task function that starts every task concurrently • Both task functions accept task names and other functions as parameters. • They can be combined infinitly
  52. gulp.task('default', gulp.series('clean', gulp.parallel('styles', 'scripts'), ‘server' ) );

  53. gulp.task('default', gulp.series('clean', gulp.parallel('styles', 'scripts'), ‘server' ) ); runs in series

  54. gulp.task('default', gulp.series('clean', gulp.parallel('styles', 'scripts'), ‘server' ) ); runs in parallel

  55. A development environment

  56. gulp.watch scripts *.js

  57. Bowser-Sync! r

  58. to the command line!

  59. Gulp API • gulp.watch creates a file watcher and listens

    to changes • changes include ‘change’, ‘add’, ‘unlink’ and others • BrowserSync is a development tool that can be fully integrated in Gulp. • Watchers trigger a browserSync.reload call
  60. function watcher(done) { gulp.watch('styles/**/*.less', gulp.parallel(‘styles’)); done(); }

  61. function watcher(done) { gulp.watch('styles/**/*.less', gulp.parallel(‘styles’)); done(); } watches this Glob

    pattern
  62. function watcher(done) { gulp.watch('styles/**/*.less', gulp.parallel(‘styles’)); done(); } starts this task

    on change, unlink, add
  63. gulp.task('server', function(done) { bSync({ server: { baseDir: ['dist', 'app'] }

    }) done(); });
  64. gulp.task('server', function(done) { bSync({ server: { baseDir: ['dist', 'app'] }

    }) done(); }); BrowserSync set up to start a dev server, serving dist and app statically
  65. gulp.watch('dist/**/*', bSync.reload); And a watcher that triggers a reload

  66. Incremental builds

  67. Some tasks take long gulp.src(‘scripts/*.js’) .pipe(uglify()) .pipe(gulp.dest()) .pipe(concat())

  68. Some tasks take long gulp.src(‘scripts/*.js’) .pipe(uglify()) .pipe(gulp.dest()) .pipe(concat())

  69. 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?
  70. Some tasks take long gulp.src(‘scripts/*.js’) .pipe(uglify()) .pipe(gulp.dest()) .pipe(concat())

  71. None
  72. filter files that have changed

  73. filter files that have changed do performance heavy operations

  74. filter files that have changed do performance heavy operations remember

    the old files
  75. filter files that have changed do performance heavy operations remember

    the old files and continue with the other ops
  76. to the command line!

  77. Gulp Plugins • gulp-cached and gulp-remember can be used to

    create file caches • The plugin filters non-changed files and ads them back to the stream once we are done with performance-heavy tasks • Additionally to that, we can use gulp.lastRun in Gulp 4 to filter files during globbing • gulp-newer allows us to do incremental copies/builds on a per-file basis
  78. 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')); });
  79. 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
  80. 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
  81. Part II

  82. A short source map interlude

  83. Browserify (for Babel/React)

  84. so similar … yet so different? Gulp Streams Browserify 


    Streams
  85. Why not both??

  86. var b = browserify({ entries: ['_js/main.js'] }); var bundle =

    function() { return b.bundle() .pipe(source(‘main.js’)) .pipe(buffer()) .pipe(uglify()) .pipe(gulp.dest('js')); }
  87. var b = browserify({ entries: ['_js/main.js'] }); var bundle =

    function() { return b.bundle() .pipe(source(‘main.js’)) .pipe(buffer()) .pipe(uglify()) .pipe(gulp.dest('js')); } b.bundle emits a stream. But no vinyl file objects
  88. var b = browserify({ entries: ['_js/main.js'] }); var bundle =

    function() { return b.bundle() .pipe(source(‘main.js’)) .pipe(buffer()) .pipe(uglify()) .pipe(gulp.dest('js')); } vinyl-source-stream wraps the original stream into a vinyl file object
  89. var b = browserify({ entries: ['_js/main.js'] }); var bundle =

    function() { return b.bundle() .pipe(source(‘main.js’)) .pipe(buffer()) .pipe(uglify()) .pipe(gulp.dest('js')); } vinyl-buffer converts the stream contents to a buffer for plugins who need such
  90. Stream arrays and merge Streams

  91. A static site generator

  92. What does it do? • Generates static HTML sites •

    From a templating engine • Can parse Markdown • Can parse HTML • Can create permalinks • For different types (posts, pages)
  93. The stack • We use kramdown to convert Markdown to

    HTML • We use nujucks for our templating engine • We rename posts to feature blog permalink • We rename pages to resemble pretty URLs
  94. In pipes gulp.src(‘posts/*.md') .pipe(kramdown()) .pipe(wrap()) .pipe(nunjucks()) .pipe(rename()) .pipe(gulp.dest())

  95. In pipes gulp.src(‘posts/*.md') .pipe(kramdown()) .pipe(wrap()) .pipe(nunjucks()) .pipe(rename()) .pipe(gulp.dest()) gulp.src(‘posts/*.html') .pipe(wrap())

    .pipe(nunjucks()) .pipe(rename()) .pipe(gulp.dest())
  96. In pipes gulp.src(‘posts/*.md') .pipe(kramdown()) .pipe(wrap()) .pipe(nunjucks()) .pipe(rename()) .pipe(gulp.dest()) gulp.src(‘posts/*.html') .pipe(wrap())

    .pipe(nunjucks()) .pipe(rename()) .pipe(gulp.dest()) the same!
  97. In pipes gulp.src(‘pages/*.md') .pipe(kramdown()) .pipe(wrap()) .pipe(nunjucks()) .pipe(rename()) .pipe(gulp.dest()) gulp.src(‘pages/*.html') .pipe(wrap())

    .pipe(nunjucks()) .pipe(rename()) .pipe(gulp.dest())
  98. In pipes gulp.src(‘pages/*.md') .pipe(kramdown()) .pipe(wrap()) .pipe(nunjucks()) .pipe(rename()) .pipe(gulp.dest()) gulp.src(‘pages/*.html') .pipe(wrap())

    .pipe(nunjucks()) .pipe(rename()) .pipe(gulp.dest()) the same!
  99. What if we could reuse parts of the stream?

  100. to the command line!

  101. to the command line!

  102. gulp.task('default', function(cb) { var streams = elements.map(function(el) { return merge(

    gulp.src(el.dir + '/**.md').pipe(markdown()), gulp.src(el.dir + '/**.html') ).pipe(rename(el.renamefn)); }); return merge(streams).pipe(data(options)) .pipe(wrap(layoutStr)) .pipe(swig()) .pipe(gulp.dest('build')); });
  103. gulp.task('default', function(cb) { var streams = elements.map(function(el) { return merge(

    gulp.src(el.dir + '/**.md').pipe(markdown()), gulp.src(el.dir + '/**.html') ).pipe(rename(el.renamefn)); }); return merge(streams).pipe(data(options)) .pipe(wrap(layoutStr)) .pipe(swig()) .pipe(gulp.dest('build')); }); we combine multiple sources to one stream
  104. gulp.task('default', function(cb) { var streams = elements.map(function(el) { return merge(

    gulp.src(el.dir + '/**.md').pipe(markdown()), gulp.src(el.dir + '/**.html') ).pipe(rename(el.renamefn)); }); return merge(streams).pipe(data(options)) .pipe(wrap(layoutStr)) .pipe(swig()) .pipe(gulp.dest('build')); }); with Array.map and merge we can create stream arrays
  105. Material

  106. 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

  107. Reading Material http://bit.ly/gulp-tool-book 39% off with 39baumgar
 coupon code!

  108. None
  109. @ddprrt