Skip to content
This repository was archived by the owner on Jan 20, 2019. It is now read-only.
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions active/0000-build-fastboot-in-ember-cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
- Start Date: 2016-11-10
- RFC PR: (leave this empty)
- Ember CLI Issue: (leave this empty)

# Summary

This RFC will primarily allow FastBoot assets to be built using `ember build`. FastBoot is a different environment in which your ember apps run and require your app behavior to change a bit in this environment that running your app in the browser. This requires building FastBoot assets that compliment the current browser assets.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/compliment/complement/


This RFC describes the details of how FastBoot will be built inside `ember-cli`. Since we do not know the generic usecases, we would like to build this into `ember-cli` as the first pass. Once we have understood the usecases, we can make it generic per this [RFC](https://github.com/ember-cli/rfcs/pull/75). This RFC aims to expose the minimal public API and work to build FastBoot in `ember-cli`.

# Motivation
[FastBoot](https://ember-FastBoot.com) allows ember apps to be rendered on the server side. It renders the initial content of your app allowing your app to be used in SEO usecases. On a very high level, FastBoot loads your assets in a Node environment and creates the Ember App once the assets are loaded. It does not do any automatic routing but creates `Ember.ApplicationInstance` whenever there is a server side rendering request and runs your route to render the initial render in Node.

In order for your app/addon to be able to run in a Node environment, it needs to be compatible in such an environment. Compatibility includes not doing DOM/window access in Node, making sure you are able to make API requests in Node etc. Therefore an app/addon may need to provide FastBoot specific initializers, instance-initializers, services etc that are only applicable in the Node environment and not in the browser. Including them in the browser has performance implication since you could be sending down more bytes than required to the client at runtime.

Currently FastBoot builds the app twice and generates a different set of assets for FastBoot and browser environments via `ember fastboot` command. Most of the app between the two sets of assets is same except where we want FastBoot to override the browser behavior or need FastBoot specific handling. Currently `ember fastboot` filters these and generates the two sets of assets (each for a different environment). Due to filtering and creating two different sets of assets we end up running the build on the app twice. Building different sets of assets (app and vendor files) for different environments cannot guarantee the app works correctly in both environments always. This RFC helps us not create FastBoot commands (which patches the private API of `ember-cli`, does a double build to generate two sets of assets and does a heavy filtering in the app tree causing large build times) for build and keeps the eco-system unified.

We want to build this FastBoot specific code as an additive asset to the browser that loads in the Node VM in addition to the the other assets. If it overrides any browser behavior, having the same module id will override the definition in the loader. In order to build FastBoot assets in a performant way, we would like to integrate building FastBoot into ember-cli. This issue specifically tracks integrating building FastBoot in ember-cli. When we need to build more such artifacts, we can extend this to be a generic target solution.

# Detailed design

## Directory Structure for FastBoot app/addons
In order to build the FastBoot assets which are an addition to the app and vendor files, we want to define a separate directory structure. This will allow FastBoot specific app code to live in its own namespace and does not touch the browser specific app file.

*Note*: Currently today no FastBoot specific code lives in the addon namespace. Hence we do not need `FastBoot/addon` namespace and building of that namespace as part of this RFC.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a concept of a FatBoot-specific addon? How should this get merged from a child addon which needs to do something different in FastBoot?

I feel like we're missing a concept here that I'm sloppily calling treeForFastboot().

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Seen later in the RFC.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nathanhammond There is no usecase currently that requires a addon inside another addon to do FastBoot work specifically. In general, the goal of this RFC is to only address the current FastBoot usecases and a very limited usecases.

I am open to discussions about how to get this working for addon inside addon but the way I see it should just work how app namespace is built for addon inside addon.


For example an addon containing FastBoot specific functionality will have a directory structure like:
```
my-addon/
|-- addon/
│ |-- utils/
│ │ |-- foo.js
│-- app/
│ │-- instance-initializers/
│ │ |-- error-handler.js
│-- fastboot/
│ │-- app/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach implies strongly that FastBoot is only additive or clobbering. You propose postprocessTree as a way to get out of that, but I'm thinking that we should come up with a better preprocessor/prostprocessor story that allowed for callbacks at the treeFor level instead of at the "giant collection" level.

This makes it far easier to compose with nested dependencies.

│ │ |-- instance-initializers/
| | | |-- error-handler.js
| | | |-- ajax.js
```
Note: The same applies for an app as well.

This allows us to keep FastBoot specific functionality in its own namespace and allows us to build FastBoot artifact by walking only the subset of the tree rather than walking the whole app and doing filtering (as done right now).

After an ember build, the generated assets will be:
1. vendor.js
2. app.js
3. app-fastboot.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm opposed to adding an additional asset and new failure mode here. I'd much rather generate app-fastboot.js which is mergeTrees + overwrite: true here and contains the actual result..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nathanhammond I would like to leave that behavior upto the platform to decide. If we merge the two files, it requires us to fork the app.js such that it works in browser differently and in Node environments differently . In Node environment it will be a merge of the two files while in browser it will just be the original app.js file. In general we want to move away from forking and generating two different assets for the primary purpose that it doesn't really guarantee consistency in both environments correctly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a firm believer that in our future story we're going to be doing more and more arbitrary splitting of assets. This has already begun with our Engines story and is only going to get more complicated. In other words, I don't know that I agree with this as a long term goal.

We need to instead do a better job allowing for this behavior to be tested but since it will hopefully primarily be a framework level concern we can probably feel relatively confident that it "just works" most of the time.


In the Node VM, we will first load the assets and eval them in the above order. Therefore, if you wanted to override a functionality in FastBoot, you can keep the name of the file same in FastBoot namespace and will override it when app-fastboot.js gets loaded and evaluated. This also guarantees that we do not regress existing ember builds that do not contain the FastBoot namespace.

## Public API
With building the additional assets, this RFC would also like to expose some public APIs so that addons that are doing FastBoot specific things can leverage that to build FastBoot assets. The additional public API will be as follows:
1. `preprocessTree(type, tree)`: Currently the type includes only for browser specific assets. We want to invoke this hook for FastBoot asset as well. Therefore, when FastBoot assets are built, this hook will be invoked with type as `app-fastboot`. Addons can use this hook to munge the FastBoot/app tree before it gets processed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newline before.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned about this being the place that we want to insert things. preprocessTree and postprocessTree receive broad categories of file types (test, template, js, css), not segments of built files. Segmentation tends to be more in the treeFor space inside of Ember CLI.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nathanhammond The reason why we need these hooks is we want to patch other things (example dom helper patches based on versions) before we start processing the tree. Currently, ember-cli doesn't really distinguish the segments of built files and file types clearly for this hook. In the long run, I would be happy to address this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I consider this to be a shortcoming in Ember CLI that we should address.

2. `postprocessTree(type, tree)`: This currently is also only invoked for browser specific assets. We want to invoke the same hook with `app-fastboot` as the type when building FastBoot asset.
3. `treeForFastBootApp(tree)`: This is a new hook that this RFC proposes to add which can be used by addons to munge the tree for `fastboot/app` before it is processed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are you expecting this to be invoked at nested addon levels? What order guarantees are you expecting? And since you're expecting a tree as input, what is that tree?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nathanhammond We don't have a usecase currently that requires this to work for nested addon levels. I would assume the order would be same as what ember-cli behavior is for app namespace.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my head I had a different mental model when posting this comment, which we discussed today at the meeting. This is one of the open problems with my proposal which we need to solve for.


# How We Teach This

This is an advanced feature and any app that defines `fastboot/app` and runs `ember build` will end up generating an additional asset as `app-fastboot.js`. We would need to update the `ember-cli` documentation to explain users how this additional asset is generated and how it will be of limited use.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should include guides / docs in ember-fastboot.com

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.


Moreover, `ember-cli-fastboot` will do the work of moving the existing FastBoot specific funtionality in various addons into `fastBoot/app`. As part of building FastBoot assets faster, we will deprecate the `ember fastBoot` command.

We will also be upgrading [FastBoot](https://ember-fastboot.com) website of how this is works with `ember-cli`.

# Drawbacks

Following are the drawbacks of this approach:
- [ ] It builds FastBoot specific code in `ember-cli`. This is only being done since we do not want to come up with a generic solution until we fully know the usecases to make this generic that any additional asset can be built.
- [ ] This approach of loading additive assets after the main asset heavily depends on the loader.js behavior of "last one" wins always. If this behavior changes in future, this approach will break.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Major confirm, I see this as blocking landing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this blocking landing? I am not sure I understand that. Could you please elaborate a bit more?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean that I don't think we should rely on this behavior, and that we should design something (similar to our whiteboarding session) which doesn't rely on this. Both @rwjblue and I had the same feedback without consulting each other.


# Alternatives

An alternative [RFC](https://github.com/ember-cli/rfcs/pull/75) which is a more generic solution and long term goal in `ember-cli`.

# Unresolved questions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FastBoot needs to be aware of the engine route map as well in order to properly inline assets in response to the initial request.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nathanhammond See this issue tracking that already. My current WIP branch of ember-cli-fastboot fixes this somewhat to allow the engine route map to be read and inlined. This is not something specific that needs to be done in ember-cli but in ember-fastboot project.


- [ ] How will this work in long term with module unification?