From 7c5cff73720384147e2349066ec96114afa66831 Mon Sep 17 00:00:00 2001 From: Mehul Kar Date: Fri, 10 Jan 2020 14:08:13 -0800 Subject: [PATCH 1/6] Ember CLI build pipeline --- text/0000-ember-cli-build-pipeline.md | 69 +++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 text/0000-ember-cli-build-pipeline.md diff --git a/text/0000-ember-cli-build-pipeline.md b/text/0000-ember-cli-build-pipeline.md new file mode 100644 index 0000000000..e18d143809 --- /dev/null +++ b/text/0000-ember-cli-build-pipeline.md @@ -0,0 +1,69 @@ +- Start Date: 2020-01-10 +- Relevant Team(s): Ember CLI +- RFC PR: (after opening the RFC PR, update this with a link to it and update the file name) +- Tracking: + +# Ability to hook into build process without addons + +## Summary + +This RFC proposes adding the `treeFor` and `treeFor*` hooks to the options passed to the `EmberApp` class. +These hooks would run during the build process and allow developers to affect the build +pipelines for each of the trees (app, vendor, public, etc). + +## Motivation + +Currently, the only supported way to affect the Broccoli tree during build time is by hooking into +the `treeFor*` APIs provided by addons. Developers that want to use these APIs are forced to develop +an addon or in-repo addon. This is problematic for a few reasons: + +- An addon is a full npm package. Even if it’s an in-repo addon, it comes with its own name and +dependency tree. The burden of maintaining another package to write a few lines +of code perpetuates the perception that Ember is "bloated" and has a steep learning curve. +- Writing code in an addon (or `lib/`) requires relying Ember CLI to invoke the code. There is no +guarantee of when or how the code will be called, so it keeps developers locked into the Ember +ecosystem. This feeling of being trapped in a build system means under-investment, +or worse: moving away. +- The entry point of the Ember build is the `ember-cli-build.js` file. The full power of a good +program should always be available in the entry point of the program. Being able to add modules +into the program should be treated as a progressive enhancement rather than a requirement. +- Although any number of addons can be added into the build process and any number of them could +affect the build process, there is no good way to guarantee the order of these addons. With hooks +exposed in a single place, it would be simple to execute code in the desired order. +- Any framework-agnostic business logic, configuration, or data needed by the build pipeline +must first be deployed independently as a module and then wrapped again in an ember-specific addon. This is a maintenance nightmare. + +## Detailed design + +The high level of Ember application build looks like this: + +```js +const app new EmberApp(defaults, {}); +return app.toTree(); +``` + +The `toTree()` method on the Application is responsible for gathering modules from the app +and addons and outputing the `vendor.js` and an `app.js` file. In addition to creating the final bundle, +it also runs the `treeFor` hooks from addons. It would be possible to add functionality to refactor +this into also running `treeFor` hooks on the `EmberApp` instance itself. + +## How we teach this + +The Ember CLI documentation currently does not introduce Ember CLI as a build pipeline. Rather, +it explains Ember CLI as an ecosystem of addons, and covers common use cases such as asset compilation +and minification. This can make it challenging to dive into the build pipeline, when it is necessary. + +Teaching these `treeFor` hooks would require first making the decision to expose the build pipeline +as a first-class citizen of the Ember CLI ecysostem. + +## Drawbacks + +None. + +## Alternatives + +Wait for Embroider and see what it offers? + +## Unresolved questions + +- Would these hooks be run before or after the addon hooks and will that cause any complications? From 96c72248127b5e1ddb93665ffc42f8ff2ba52ef9 Mon Sep 17 00:00:00 2001 From: Mehul Kar Date: Fri, 10 Jan 2020 14:11:32 -0800 Subject: [PATCH 2/6] Add PR link --- text/0000-ember-cli-build-pipeline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-ember-cli-build-pipeline.md b/text/0000-ember-cli-build-pipeline.md index e18d143809..12a545a66b 100644 --- a/text/0000-ember-cli-build-pipeline.md +++ b/text/0000-ember-cli-build-pipeline.md @@ -1,6 +1,6 @@ - Start Date: 2020-01-10 - Relevant Team(s): Ember CLI -- RFC PR: (after opening the RFC PR, update this with a link to it and update the file name) +- RFC PR: https://github.com/emberjs/rfcs/pull/578 - Tracking: # Ability to hook into build process without addons From 1693ff416dc564dbecbeb43c68b07d6e8aa0925f Mon Sep 17 00:00:00 2001 From: Mehul Kar Date: Sun, 12 Jan 2020 12:38:58 -0800 Subject: [PATCH 3/6] improve reasoning for why ember-cli-build is not enough --- text/0000-ember-cli-build-pipeline.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/text/0000-ember-cli-build-pipeline.md b/text/0000-ember-cli-build-pipeline.md index 12a545a66b..0aea65bcc0 100644 --- a/text/0000-ember-cli-build-pipeline.md +++ b/text/0000-ember-cli-build-pipeline.md @@ -13,9 +13,15 @@ pipelines for each of the trees (app, vendor, public, etc). ## Motivation -Currently, the only supported way to affect the Broccoli tree during build time is by hooking into -the `treeFor*` APIs provided by addons. Developers that want to use these APIs are forced to develop -an addon or in-repo addon. This is problematic for a few reasons: +Currently, the recommended way to affect the Broccoli tree during build time is by hooking into +the `treeFor*` APIs provided by addons. Although it is technically possible to [merge additional +trees by passing in more trees into the `toTree()` method][1] of `EmberApp`in `ember-cli-build.js`, +this feature is not documented well and it's not clear if the core team would like to see it used. + +[1]: https://github.com/ember-cli/ember-cli/blob/v3.15.1/lib/broccoli/ember-app.js#L1791-L1799 + +Developers that want to use the `treeFor` APIs have to develope an addon or in-repo addon. +This is problematic for a few reasons: - An addon is a full npm package. Even if it’s an in-repo addon, it comes with its own name and dependency tree. The burden of maintaining another package to write a few lines From b712a10f9256b9fa8074e626b3f862ec6fc37b9e Mon Sep 17 00:00:00 2001 From: Mehul Kar Date: Wed, 20 May 2020 13:16:38 -0700 Subject: [PATCH 4/6] Add more details to design --- text/0000-ember-cli-build-pipeline.md | 76 +++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/text/0000-ember-cli-build-pipeline.md b/text/0000-ember-cli-build-pipeline.md index 0aea65bcc0..3d5240afb3 100644 --- a/text/0000-ember-cli-build-pipeline.md +++ b/text/0000-ember-cli-build-pipeline.md @@ -15,11 +15,9 @@ pipelines for each of the trees (app, vendor, public, etc). Currently, the recommended way to affect the Broccoli tree during build time is by hooking into the `treeFor*` APIs provided by addons. Although it is technically possible to [merge additional -trees by passing in more trees into the `toTree()` method][1] of `EmberApp`in `ember-cli-build.js`, +trees by passing in more trees into the `toTree()` method][1] of `EmberApp` in `ember-cli-build.js`, this feature is not documented well and it's not clear if the core team would like to see it used. -[1]: https://github.com/ember-cli/ember-cli/blob/v3.15.1/lib/broccoli/ember-app.js#L1791-L1799 - Developers that want to use the `treeFor` APIs have to develope an addon or in-repo addon. This is problematic for a few reasons: @@ -44,14 +42,69 @@ must first be deployed independently as a module and then wrapped again in an em The high level of Ember application build looks like this: ```js -const app new EmberApp(defaults, {}); +const app = new EmberApp(defaults, {}); return app.toTree(); ``` -The `toTree()` method on the Application is responsible for gathering modules from the app -and addons and outputing the `vendor.js` and an `app.js` file. In addition to creating the final bundle, -it also runs the `treeFor` hooks from addons. It would be possible to add functionality to refactor -this into also running `treeFor` hooks on the `EmberApp` instance itself. +The `toTree()` method gathers the trees of each type from each addon and merges them together [like this][3]: + +```js +const trees = [ + this.getAddonTemplates(), + this.getStyles(), + this.getTests(), + this.getExternalTree(), + this.getPublic(), + this.getAppJavascript(this._isPackageHookSupplied), +].filter(Boolean); + +mergeTrees(trees, { + overwrite: true, + annotation: 'Full Application', +}); +``` + +Each of the individual `trees` (template, style, etc) gathers both explicit and implicit trees +from each addon. Explicit trees are the return value of the `treeFor()` and `treeFor` hooks +in the index.js file, whereas implicit trees are the contents of the correlated directories in the +addon (e.g. the `public/` directory for the public tree. Currently, the [order that these three sets +of trees][4] are gathered is this: + +1. Explicit tree from `treeFor` hook +1. Implicit tree from directory +1. Explicit tree from `treeFor` hook + +The `treeFor` hook receives the implicit tree as an argument. + +This RFC proposes that after Ember CLI has merged all addon and app trees for each type (but before +it calls `postProcessTree` hooks from addons), it call `treeFor` on the `app` instance and +pass the merged tree of that type as an argument. + +The end user experience would look roughly like this: + +```js +const writeFile = require('broccoli-file-creator'); +const path = require('path') +const fs = require('fs'); + +const app = new EmberApp(defaults, { + /** + * @param tree The merged tree from the app and all addons + */ + treeForPublic(tree) { + const dataPath = path.join(tree.outputPath, 'data.json'); + if (fs.existsSync(dataPath)) { + return writeFile('data.json', JSON.stringify({ foo: 'bar' })); + } + }, + + treeForApp(/* tree */) {}, + treeFor(/* tree */) {}, + // ...etc +}); + +return app.toTree(); +``` ## How we teach this @@ -60,7 +113,7 @@ it explains Ember CLI as an ecosystem of addons, and covers common use cases suc and minification. This can make it challenging to dive into the build pipeline, when it is necessary. Teaching these `treeFor` hooks would require first making the decision to expose the build pipeline -as a first-class citizen of the Ember CLI ecysostem. +as a first-class citizen of the Ember CLI ecosystem. ## Drawbacks @@ -73,3 +126,8 @@ Wait for Embroider and see what it offers? ## Unresolved questions - Would these hooks be run before or after the addon hooks and will that cause any complications? + +[1]: https://github.com/ember-cli/ember-cli/blob/v3.15.1/lib/broccoli/ember-app.js#L1791-L1799 +[2]: https://github.com/ember-cli/ember-cli/blob/v3.18.0/lib/broccoli/ember-app.js#L697-L711 +[3]: https://github.com/ember-cli/ember-cli/blob/v3.18.0/lib/broccoli/ember-app.js#L1646-L1649 +[4]: https://github.com/ember-cli/ember-cli/blob/v3.18.0/lib/models/addon.js#L627-L632 From 0ed96e422af5c654ffe00e33b5d860f889f3eb6a Mon Sep 17 00:00:00 2001 From: Mehul Kar Date: Wed, 20 May 2020 13:19:47 -0700 Subject: [PATCH 5/6] Some more udpates --- text/0000-ember-cli-build-pipeline.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-ember-cli-build-pipeline.md b/text/0000-ember-cli-build-pipeline.md index 3d5240afb3..31688885e3 100644 --- a/text/0000-ember-cli-build-pipeline.md +++ b/text/0000-ember-cli-build-pipeline.md @@ -7,7 +7,7 @@ ## Summary -This RFC proposes adding the `treeFor` and `treeFor*` hooks to the options passed to the `EmberApp` class. +This RFC proposes adding the `treeFor` hooks to the options passed to the `EmberApp` class. These hooks would run during the build process and allow developers to affect the build pipelines for each of the trees (app, vendor, public, etc). @@ -67,7 +67,7 @@ mergeTrees(trees, { Each of the individual `trees` (template, style, etc) gathers both explicit and implicit trees from each addon. Explicit trees are the return value of the `treeFor()` and `treeFor` hooks in the index.js file, whereas implicit trees are the contents of the correlated directories in the -addon (e.g. the `public/` directory for the public tree. Currently, the [order that these three sets +addon (e.g. the `public/` directory for the public tree). Currently, the [order that these three sets of trees][4] are gathered is this: 1. Explicit tree from `treeFor` hook @@ -78,7 +78,7 @@ The `treeFor` hook receives the implicit tree as an argument. This RFC proposes that after Ember CLI has merged all addon and app trees for each type (but before it calls `postProcessTree` hooks from addons), it call `treeFor` on the `app` instance and -pass the merged tree of that type as an argument. +passes the merged tree of that type as an argument. The end user experience would look roughly like this: From 3f6aa980bad9a70efd1b014d314f0c9912859ee2 Mon Sep 17 00:00:00 2001 From: Mehul Kar Date: Wed, 20 May 2020 13:20:24 -0700 Subject: [PATCH 6/6] remove unresolved qs --- text/0000-ember-cli-build-pipeline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-ember-cli-build-pipeline.md b/text/0000-ember-cli-build-pipeline.md index 31688885e3..bba8642e6c 100644 --- a/text/0000-ember-cli-build-pipeline.md +++ b/text/0000-ember-cli-build-pipeline.md @@ -125,7 +125,7 @@ Wait for Embroider and see what it offers? ## Unresolved questions -- Would these hooks be run before or after the addon hooks and will that cause any complications? +None [1]: https://github.com/ember-cli/ember-cli/blob/v3.15.1/lib/broccoli/ember-app.js#L1791-L1799 [2]: https://github.com/ember-cli/ember-cli/blob/v3.18.0/lib/broccoli/ember-app.js#L697-L711