--- slideOptions: transition: slide --- # Layering in JS build tools | Modern Web meetup | Alex Eagle | | :---------------- | ---------: | |Angular Tooling team lead|<img src="https://avatars0.githubusercontent.com/u/47395?s=460&v=4" style="border:2px solid grey; border-radius: 200px;" width=200/>| --- <blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">The JavaScript community has gotten into the pattern that every devserver, bundler, or test runner tool has to accept the original program sources as inputs, and that means each tool gradually expands its scope to include a build system.</p>&mdash; Alex 🦅 Eagle (@Jakeherringbone) <a href="https://twitter.com/Jakeherringbone/status/1093618370509852672?ref_src=twsrc%5Etfw">February 7, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> --- <img src="https://farm9.staticflickr.com/8388/8646652808_c44c28e6ca.jpg"/> --- ## A tale of two shapes - The grid - The wheel Slide deck w/o images, so watch me draw! --- # Let's talk tooling | user facing | code processing | | ----------- | --------------- | | you run it in your workflow | it processes specific source files | | e.g. dev server | e.g. language compiler | What are some other examples? --- # The Matrix shape - Rows: code processors - Columns: workflow tools - Cells: plugins Number of plugins needed is O(M×N) --- ![](https://i.imgur.com/WP97BiM.png) Bundler like Webpack needs to transpile your TypeScript code --- ![](https://i.imgur.com/i0lAjwP.png) Test runner like Cypress needs to transpile your TypeScript code --- # What's wrong with this model? Obvious: 1) missing plugins 2) so many chances for bugs 3) plugins call internal APIs in the tools --- *What if you want to write a new CSS preprocessor?* Need to write a plugin for every workflow tool 🤷 --- *What if you want to write a new test runner?* Need to write a plugin for every code transform tool 🤷‍♂️ --- # "Governance" It's hard for an enterprise to depend on - so many **plugins** from - so many **authors** using - so many different **licenses** Who supports the end-to-end? Language team? Bundler team? Plugin author? --- # The Wheel shape - Perimeter: all tools - Hub: generic build orchestration tool - Spokes: plugins Number of plugins needed is O(M+N) *Okay, there might be 2-3 popular "wheels" so O(c(M+N))* --- The wheel model allows good layering - Tools don't need to know about each other - We run the supported CLI of each tool - The "spoke" can be simple, reproducible --- # Remember Gulp? or Grunt? Those followed the wheel model --- What was wrong with Gulp? - Error handling for failed builds - Easy to make "incorrect" build, need to clean - Node streams: probably wrong abstraction --- Wrong abstraction? - When the plugin gives a set of files, user config must connect the files - User configuration can get complicated - Not sufficiently ergonomic for users to compose the plugins --- *What if multiple sets of files are produced?* ```javascript var gulp = require('gulp'); var ts = require('gulp-typescript'); var merge = require('merge2'); gulp.task('scripts', function() { var tsResult = gulp.src('lib/**/*.ts') .pipe(ts({ declaration: true })); return merge([ tsResult.dts.pipe(gulp.dest('release/definitions')), tsResult.js.pipe(gulp.dest('release/js')) ]); }); ``` --- # Best abstraction? Plugins have an API like a message bus Loosely coupled, but richer than file streams ### Example TypeScript plugin could produce different outputs depending whether it's connected to a - type-check plugin - development server plugin - production plugin --- ## Am I selling something? <img src="https://bazel.build/images/bazel-og-image.png"/> Bazel is getting some adoption, starting with Node.js backend systems. Planning a 1.0 release this summer. We are pioneering its use in Angular. --- Thanks! | Alex Eagle | @jakeherringbone | | :---------------- | ---------: | | http://g.co/ng/abc |<img src="https://avatars0.githubusercontent.com/u/47395?s=460&v=4" style="border:2px solid grey; border-radius: 200px;" width=200/>|