-
-
Notifications
You must be signed in to change notification settings - Fork 54
Conversation
Some history are mentioned in the following issues: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Notes:
- Various references to fastboot should be "FastBoot".
- Is there a specific reason to rely on the "last module registered wins" clobbering behavior as opposed to relying on broccoli-merge-trees (with
{ overwrite: true }
) to allow only the final concat to differ? - I would have thought that we would want a
browser/app
andbrowser/addon
. This way the main generic app bundles live inaddon
orapp
and the "platform specific" parts live in eitherbrowser/
orfastboot/
. The resulting build would haveapp.js
,browser-app.js
,fastboot-app.js
, and possibly acombined-app.js
(which would be the main app bundle along with the main browser bundle).
|
||
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. | ||
|
||
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 `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`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would like to build this
ember-cli
as the first pass
Sounds a bit odd, maybe you mean:
would like to build this into
ember-cli
as the first pass
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
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 `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 application instance whenever there is a server side rendering request and runs your route to render the initial render in Node. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does not do any automatic routing but creates Ember application instance whenever there is a server side rendering request and runs your route to render the initial render in Node.
Slight tweak for correctness:
It does not do any automatic routing but creates an
Ember.ApplicationInstance
instance whenever there is a server side rendering request and runs your applications initial render in Node.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
# 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 application instance 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 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 will send down more bytes to the client. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Including them in the browser has performance implication since you will send down more bytes to the client.
Might read better as:
Including them in the browser has performance implications since you would be sending down more bytes than required to the client at runtime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
|
||
In order for your app/addon to be able to run in a Node environment, it needs to be compatible in such 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 will send down more bytes to the client. | ||
|
||
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. Building different sets of assets (app and vendor files) for different environments cannot guarantee the app works correctly in both environments always. Moreover, ember-fastboot --serve-assets command also spins up a node server and serves your assets. This is very similar to what ember serve does today. However, we end up forking and creating two parallel worlds with problems such as serving stale assets, creating race conditions during serving and building etc. We want to be able converge the two worlds such that fastboot should be able to specify the last middleware that will be used to serve the assets in fastboot. This helps us not create fastboot commands and keeps the eco-system unified. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ember-fastboot --serve-assets command
Should be:
ember fastboot --serve-assets
command
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
|
||
In order for your app/addon to be able to run in a Node environment, it needs to be compatible in such 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 will send down more bytes to the client. | ||
|
||
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. Building different sets of assets (app and vendor files) for different environments cannot guarantee the app works correctly in both environments always. Moreover, ember-fastboot --serve-assets command also spins up a node server and serves your assets. This is very similar to what ember serve does today. However, we end up forking and creating two parallel worlds with problems such as serving stale assets, creating race conditions during serving and building etc. We want to be able converge the two worlds such that fastboot should be able to specify the last middleware that will be used to serve the assets in fastboot. This helps us not create fastboot commands and keeps the eco-system unified. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, we end up forking and creating two parallel worlds with problems such as serving stale assets, creating race conditions during serving and building etc.
Should also mention 2X build speed issues
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to be able converge the two worlds such that fastboot should be able to specify the last middleware that will be used to serve the assets in fastboot.
This is slightly confusing to me (from the RFC's perspective "what are middlewares?", "why do I care about the last middleware?", etc), can you tweak a bit to make it clearer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This helps us not create fastboot commands and keeps the eco-system unified.
We should explain why we care about not duplicating commands and whatnot...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed explaining the double builds. Apologies the middleware shouldn't have been part of this RFC. That will likely be a different RFC (hopefully coming next week...)
|
||
## 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 `fastboot`. Addons can use this hook to munge the fastboot/app tree before it gets processed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this hook will be invoked with type as
fastboot
This should be fastboot-app
and fastboot-addon
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed to use app-fastboot
and dropped the fastboot-addon
per the scope of this RFC.
## 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 `fastboot`. Addons can use this hook to munge the fastboot/app tree before it gets processed. | ||
2. `postprocessTree(type, tree)`: This currently is also only invoked for browser specific assets. We want to invoke the same hook with `fastboot` as the type when building fastboot asset. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, should be app-fastboot
and addon-fastboot
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fastboot-app
(as stated above), or app-fastboot
? It seems that fastboot-app
is more appropriate given how the mapping currently looks:
{
app: 'treeForApp',
styles: 'treeForStyles',
templates: 'treeForTemplates',
'addon-templates': 'treeForAddonTemplates',
'fastboot-app': 'treeForFastbootApp' // ...?
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ryanone I think the confusion is from two aspects:
- The generated fastboot asset is called
app-fastboot.js
- The hook is call
fastboot
.
The reason Rob is suggesting to keep the names same across both the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We discussed this. fastboot/addon
will not be built as part of this RFC.
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 `fastboot`. Addons can use this hook to munge the fastboot/app tree before it gets processed. | ||
2. `postprocessTree(type, tree)`: This currently is also only invoked for browser specific assets. We want to invoke the same hook with `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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should also include a treeForFastbootAddon
hook
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rwjblue I do not want to add building fastboot/addon
since there is no usecase today. In future, if we have a usecase I would agree we want to expose that hook. To satisfy the long term needs (which are undetermined right now), I can add this and about building fastboot/addon
but we will not be addressing it in the corresponding PR. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me. We can make a more focused RFC for specifically adding this at a later date.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. I am going to drop this then.
|
||
# 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. |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
|
||
# Drawbacks | ||
|
||
The only drawback this has is that 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relies on loader.js
behavior of "last wins", which is not guaranteed to be true for:
- a world where we don't use
loader.js
(i.e. if we move to rollup built assets) - lazy engines?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rwjblue lazy-engines
are loaded upfront in FastBoot environment. A world where loader.js
does not live as well, the eval and ordering of loading the assets in the sandbox will still do the override I believe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, the vendor asset that we load in fastboot should still have loader.js
, and it is used (AFAIK we do not transpile with other things like rollup in ember-cli-fastboot today so we have to still be relying on loader.js there...).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there is nothing special done in fastboot. The loader definition and API is exposed in the sandbox.
I was answering the question about the rollup. I honestly don't know what is the plan for that.
I agree about this as a "long term" goal (see this RFC). If we want to do this with this RFC, it then it means this is a backward incompatible change in
If everyone agrees to the above scope of the problem, this this is what this RFC is supposed to address. |
No specific reason, that is how loader.js works today. We can do the final merge of |
@rwjblue updated per your feedback. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting this up as early as I can for visibility. As a result not perfectly wordsmithed, not entirely constructive. But I intend these to be things for which we can work toward solutions.
|
||
# 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/compliment/complement/
## 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. |
There was a problem hiding this comment.
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()
.
There was a problem hiding this comment.
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.)
There was a problem hiding this comment.
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.
|
||
## 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Newline before.
After an ember build, the generated assets will be: | ||
1. vendor.js | ||
2. app.js | ||
3. app-fastboot.js |
There was a problem hiding this comment.
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..
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
|
||
## 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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
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. | ||
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. |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
|
||
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
|
||
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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
│ │-- instance-initializers/ | ||
│ │ |-- error-handler.js | ||
│-- fastboot/ | ||
│ │-- app/ |
There was a problem hiding this comment.
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.
I read through the spike in ember-cli/ember-cli#6395, and it seems like it is so close to being independent of fastboot, all it needs is a supplied "platform".
An app or addon could then supply an array of platforms, via ember-cli-build.js or package.json, and ember-cli would look for folders with those names. Then the rest of this RFC would take effect. |
We are working on closing the ember-cli/rfcs repo in favor of using a single central RFC's repo for everything. This was laid out in https://emberjs.github.io/rfcs/0300-rfc-process-update.html. Sorry for the troubles, but would you mind reviewing to see if this is still something we need, and if so migrating this over to emberjs/rfcs? Thank you! |
rendered
Corresponding PR which does the work described in this RFC is here.
Long term RFC which should allow this to become a generic feature is described in this RFC
cc: @stefanpenner @tomdale @rwjblue @ryanone @masonwan @kristoferbaxter @arjansingh