Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dissecting an Ember CLI Build

Dissecting an Ember CLI Build

Talk from EmberConf 2016

As the tooling ecosystem continues to evolve, developers nowadays can easily scaffold out a new Ember app and start being productive right away, without ever thinking of all the intricacies that go on behind a typical build command. But there comes a time when manipulating trees or nodes in Broccoli may be required to support a custom project architecture, or you may find yourself having to extend the build for specialized environments through addons.

Whether you face any one of those scenarios, or you simply want to know more of what goes on behind the curtain, this talk is for you.

Estelle DeBlois

March 29, 2016
Tweet

More Decks by Estelle DeBlois

Other Decks in Technology

Transcript

  1. You use Ember CLI You are familiar with the project

    structure You know what addons are
  2. var EmberApp = require(‘ember-cli/lib/broccoli/ember-app’); module.exports = function(defaults) { var app

    = new EmberApp(defaults, { // Add options here }); return app.toTree(); }; ember-cli-build.js
  3. var EmberApp = require(‘ember-cli/lib/broccoli/ember-app’); module.exports = function(defaults) { var app

    = new EmberApp(defaults, { // Add options here }); return app.toTree(); }; ember-cli-build.js
  4. ember-conf !"" app !"" bower_components !"" config !"" dist !""

    node_modules !"" public !"" tests !"" vendor #"" workers #"" worker.js
  5. ember-conf !"" app !"" bower_components !"" config !"" dist !""

    node_modules !"" public !"" tests !"" vendor #"" workers #"" worker.js minify
  6. WHAT IS A TREE? A directory of files A string

    representing a directory path
  7. WHAT IS A TREE? A directory of files A string

    representing a directory path An object that implements the Plugin API
  8. WHAT IS A PLUGIN? Takes one or more input trees

    Performs some transformation Returns an output tree
  9. ember-conf !"" app $ !"" components $ !"" controllers $

    !"" helpers $ !"" models $ !"" routes $ !"" styles $ #"" templates !"" bower_components !"" config !"" node_modules !"" public !"" tests #"" vendor source directories SOURCE NODE
  10. ember-conf !"" app $ !"" components $ !"" controllers $

    !"" helpers $ !"" models $ !"" routes $ !"" styles $ #"" templates !"" bower_components !"" config !"" node_modules !"" public !"" tests #"" vendor source directories / SOURCE NODE
  11. var WatchedDir = require(‘broccoli-source’).WatchedDir; var Transpiler = require(‘broccoli-babel-transpiler’); var Concat

    = require(‘broccoli-concat’); var TreeMerger = require(‘broccoli-merge-trees’); module.exports = function(defaults) { };
  12. var WatchedDir = require(‘broccoli-source’).WatchedDir; var Transpiler = require(‘broccoli-babel-transpiler’); var Concat

    = require(‘broccoli-concat’); var TreeMerger = require(‘broccoli-merge-trees’); module.exports = function(defaults) { var appNode = new WatchedDir(‘app’); var publicNode = new WatchedDir(‘public’); };
  13. var WatchedDir = require(‘broccoli-source’).WatchedDir; var Transpiler = require(‘broccoli-babel-transpiler’); var Concat

    = require(‘broccoli-concat’); var TreeMerger = require(‘broccoli-merge-trees’); module.exports = function(defaults) { var appNode = new WatchedDir(‘app’); var publicNode = new WatchedDir(‘public’); var transpiledNode = new Transpiler(appNode); var concatNode = new Concat(transpiledNode, { /* … */ }); return new TreeMerger([concatNode, publicNode]); };
  14. var buildFile = load(‘ember-cli-build.js’); var outputNode = buildFile(); var Builder

    = require(‘broccoli’).Builder; var builder = new Builder(outputNode, options); builder.build();
  15. var EmberApp = require(‘ember-cli/lib/broccoli/ember-app’); module.exports = function(defaults) { var app

    = new EmberApp(defaults, { // Add options here }); return app.toTree(); }; ember-cli-build.js
  16. ember-conf !"" app $ !"" components $ !"" controllers $

    !"" helpers $ !"" models $ !"" routes $ !"" styles $ #"" templates !"" bower_components !"" config !"" node_modules !"" public !"" tests #"" vendor app styles templates bower public tests vendor SOURCE NODES EMBER APP
  17. var EmberApp = require(‘ember-cli/lib/broccoli/ember-app’); module.exports = function(defaults) { var app

    = new EmberApp(defaults, { // Add options here }); app.import(app.bowerDirectory + ‘/moment/moment.js’); return app.toTree(); }; ember-cli-build.js
  18. module.exports = { name: ‘my-addon’, treeForApp: function() { return new

    UnwatchedDir(path.join(__dirname, ‘custom’)); } }; my-addon/index.js
  19. treeForApp treeForStyles treeForTemplates treeForPublic treeForTestSupport treeForVendor app styles templates public

    tests vendor ADDON HOOKS CONSUMING APP ADDON my-addon !"" custom $ !"" components $ !"" controllers $ !"" helpers $ !"" models $ !"" routes $ !"" styles $ #"" templates !"" public !"" test-support #"" vendor app
  20. treeForAddon ADDON HOOKS CONSUMING APP ADDON my-addon #"" addon !""

    components !"" controllers !"" helpers !"" models !"" routes !"" styles #"" templates vendor.js vendor.css
  21. treeForAddon: function(addonNode) { var node = this._super.treeForAddon(addonNode); var filteredNode =

    new Funnel(node, { exclude: [ // exclusion logic ] }); return debug(filteredNode, { name: ‘filtered-metrics’ }); } my-addon/index.js
  22. ember-conf !"" app !"" bower_components !"" config !"" DEBUG-filtered-metrics $

    #"" modules $ #"" ember-metrics $ #"" metrics-adapters $ !"" base.js $ #"" google-analytics.js !"" dist !"" node_modules !"" public !"" tests #"" vendor
  23. postprocessTree: function(type, node) { if (type === ‘all’) { //

    add fingerprinting node = assetRev(node, this.options); } return node; } my-addon/index.js