-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Allow visit to specify Rehydration/Serialization or default ClientBuilder #16227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow visit to specify Rehydration/Serialization or default ClientBuilder #16227
Conversation
d53b2e8 to
994e154
Compare
|
Awesome to see Rehydration coming to Ember! |
|
To assuage any fears of file size bloat this takes ember.min.js (gzipped) from 115.73kb to 115.89. Which should definitely be addressed, but I shouldn't think be a blocker. |
Agreed. |
|
Relevant to this ticket: glimmerjs/glimmer-vm#780 |
|
After discussing this, it was decided that the configuration for renderMode should be a private var to avoid muddying the API surface. Updated the PR accordingly |
|
looks like this needs a rebase |
c6e16a3 to
26f9841
Compare
|
@rwjblue Rebased. I'm still running tests locally, but should be gtg |
|
Looks like I need to dig into this one. Working on it now. |
e633523 to
522a43b
Compare
rwjblue
left a comment
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.
Looking really nice! A few more things to cleanup...
- After the initial serialize render we should grab the actual
divelement so that we can ensure it is "rehydrated" - Add additional assertions that confirm the element is exactly the initial element
- Add additional assertion that confirm the template isn't rendered into the root element twice...
|
|
||
| ENV._APPLICATION_TEMPLATE_WRAPPER = false; | ||
|
|
||
| return this.runTask(() => { |
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 should remove this runTask (otherwise this makes a nested run loop and we shouldn't need that)
| .then((instance) => { | ||
| assert.equal( | ||
| instance.rootElement.firstChild.nodeValue, | ||
| '%+b:0%', |
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 don't really like the coupling to the internal / private mechanism that Glimmer's serialize mode renderer uses internally (generally speaking I'd much prefer to test the results rather than how it works internally) but I realize this is somewhat of a chicken or the egg situation.
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.
I totally agree that I'd prefer not to couple so tightly to the internal implementation. Though to ensure we are actually doing some work this seems to be necessary.
I'd like in the future to expose the leading comment node in the serializer builder in glimmer as an export so we don't have to hardcode this value. Perhaps that could be a next step?
| rootElement, | ||
| _renderMode: 'rehydrate' | ||
| }; | ||
| this.application.visit('/', bootOptions).then(instance => { |
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 should be able to do this.visit again (since you are properly destroying/clearing it above).
ClientBuilder Expose as a configurable option the `renderMode` option. This option would be to specify the clientBuilder to be used when Glimmer does it's append run. The serialization mode, used by SSR applications, is used to specify additional markings necessary to get enough fidelity to accurately rehydrate the DOM. For example, it would provide additional comment nodes with codes to ensure text nodes are separated when they are rather than merged. The rehydration mode is specifically designed to read DOM that is produced by the serialization mode and accurately reproduce it. A great description of how Rehydration works can be found in this commit: glimmerjs/glimmer-vm@316805b This PR allows the appropriate ElementBuilder interface to be used via the `visit` API. Additional Work: - Update Fastboot to pass the appropriate `renderMode` flag such that it generates the serialization format DOM - Update ember-cli-fastboot instance-initializer to not do a double boot and instead configure it to use the rehydration `renderMode` - See more information here: https://github.com/ember-fastboot/ember-cli-fastboot/blob/master/addon/instance-initializers/clear-double-boot.js Open Questions: - Is the `renderMode` flag Public API - Should this be put behind a feature flag - @rwjblue noted that this technically would be a bug fix as it would remove the double render problem with SSR ember apps
This is meant to be a temporary test. Want a more robust test that doesn't rely on the actual serialization format of glimmer's serializer builder
Formerly we were asserting on a string we manually created with knowledge of the glimmer-vm encoding for both serialization and rehydration. This test now generates an application instance with the serialize method and asserts that the first node is a node we know is set by glimmer-vm serializer Then we destroy that instance and create a new instance with the rehydrate _renderMode that uses it to rehydrate the dom. Thus we go through a closer to real-world scenario of serialization in an SSR visit with _renderMode set appropriately, through visit with an instance set to rehydrate the SSR generated content.
8501563 to
04ad41d
Compare
| _renderMode: 'rehydrate' | ||
| }; | ||
|
|
||
| this.application.visit('/', bootOptions).then(instance => { |
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 turns out this is actually necessary. When you remove the this.application and just call visit directly we get an error saying that you tried to use an object that is destroyed (sorry I don't have the exact wording of the error) . Either way nbd.
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.
Seems fine, but I still don't like it 😝
| @default false | ||
| @private | ||
| */ | ||
| this._renderMode = options._renderMode; |
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 was recently changed and I think the commit history of this PR is now a little inaccurate to what actually happened. I suspect we'll sqaush soon anyways, so I'm not worried about it, but if it is a concern I can flesh out the commit history.
This is part of an arching plan to introduce Glimmer's rehydration/serializtion modes to Ember proper. There are 4 PR's that are all interwoven, of which, this is one. In order of need to land they are: Glimmer.js: glimmerjs/glimmer-vm#783 (comment) This resolves a rather intimate API problem. Glimmer-vm expects a very specific comment node to exist to know whether or not the rehydration element builder can do it's job properly. If it is not found on the first node from `rootElement` it throws. In fastboot however we are certain that there will already be existant elements in the way that will happen before rendered content. This PR just iterates through the nodes until it finds the expected comment node. And only throws if it never finds one. --- Ember.js: emberjs/ember.js#16227 This PR modifies the `visit` API to allow a private _renderMode to be set to either serialize or rehydrate. In SSR environments the assumption (as it is here in this fastboot PR) is that we'll set the visit API to serialize mode which ensures glimmer-vm's serialize element builder is used to build the API. The serialize element builder ensures that we have the necessary fidelty to rehydrate correctly and is mandatory input for rehydration. --- Fastboot: ember-fastboot#185 This allows enviroment variable to set _renderMode to be used in Visit API. Fastboot must send content to browser made with the serialization element builder to ensure rehydration can be sucessful. --- EmberCLI Fastboot: ember-fastboot/ember-cli-fastboot#580 Finally this does the fun part of disabling the current clear-double-render instance-initializer We first check to ensure we are in a non-fastboot environment. Then we ensure that we can find the expected comment node from glimmer-vm's serialize element builder. This ensures that this change will only effect peoeple who use ember-cli-fastboot with the serialized output from the currently experimental fastboot setup Then we ensure `ApplicationInstance#_bootSync` specifies the rehydrate _renderMode. This is done in `_bootSync` this way because visit is currently not used to boot ember applications. And we must instead set bootOptions this way instead. We also remove the markings for `fastboot-body-start` and `fastboot-body-end` to ensure clear-double render instance-initializer is never called.
This is part of an arching plan to introduce Glimmer's rehydration/serializtion modes to Ember proper. There are 4 PR's that are all interwoven, of which, this is one. - [ ] Glimmer.js: glimmerjs/glimmer-vm#783 (comment) - [ ] Ember.js: emberjs/ember.js#16227 - [ ] Fastboot: ember-fastboot/fastboot#185 - [ ] EmberCLI Fastboot: ember-fastboot#580 In order of need to land they are: Glimmer.js: glimmerjs/glimmer-vm#783 (comment) This resolves a rather intimate API problem. Glimmer-vm expects a very specific comment node to exist to know whether or not the rehydration element builder can do it's job properly. If it is not found on the first node from `rootElement` it throws. In fastboot however we are certain that there will already be existant elements in the way that will happen before rendered content. This PR just iterates through the nodes until it finds the expected comment node. And only throws if it never finds one. --- Ember.js: emberjs/ember.js#16227 This PR modifies the `visit` API to allow a private _renderMode to be set to either serialize or rehydrate. In SSR environments the assumption (as it is here in this fastboot PR) is that we'll set the visit API to serialize mode which ensures glimmer-vm's serialize element builder is used to build the API. The serialize element builder ensures that we have the necessary fidelty to rehydrate correctly and is mandatory input for rehydration. --- Fastboot: ember-fastboot/fastboot#185 This allows enviroment variable to set _renderMode to be used in Visit API. Fastboot must send content to browser made with the serialization element builder to ensure rehydration can be sucessful. --- EmberCLI Fastboot: ember-fastboot#580 Finally this does the fun part of disabling the current clear-double-render instance-initializer We first check to ensure we are in a non-fastboot environment. Then we ensure that we can find the expected comment node from glimmer-vm's serialize element builder. This ensures that this change will only effect peoeple who use ember-cli-fastboot with the serialized output from the currently experimental fastboot setup Then we ensure `ApplicationInstance#_bootSync` specifies the rehydrate _renderMode. This is done in `_bootSync` this way because visit is currently not used to boot ember applications. And we must instead set bootOptions this way instead. We also remove the markings for `fastboot-body-start` and `fastboot-body-end` to ensure clear-double render instance-initializer is never called.
| _renderMode: 'rehydrate' | ||
| }; | ||
|
|
||
| this.application.visit('/', bootOptions).then(instance => { |
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.
Seems fine, but I still don't like it 😝
This is part of an arching plan to introduce Glimmer's rehydration/serializtion modes to Ember proper. There are 4 PR's that are all interwoven, of which, this is one. - [ ] Glimmer.js: glimmerjs/glimmer-vm#783 (comment) - [ ] Ember.js: emberjs/ember.js#16227 - [ ] Fastboot: ember-fastboot/fastboot#185 - [ ] EmberCLI Fastboot: ember-fastboot#580 In order of need to land they are: Glimmer.js: glimmerjs/glimmer-vm#783 (comment) This resolves a rather intimate API problem. Glimmer-vm expects a very specific comment node to exist to know whether or not the rehydration element builder can do it's job properly. If it is not found on the first node from `rootElement` it throws. In fastboot however we are certain that there will already be existant elements in the way that will happen before rendered content. This PR just iterates through the nodes until it finds the expected comment node. And only throws if it never finds one. --- Ember.js: emberjs/ember.js#16227 This PR modifies the `visit` API to allow a private _renderMode to be set to either serialize or rehydrate. In SSR environments the assumption (as it is here in this fastboot PR) is that we'll set the visit API to serialize mode which ensures glimmer-vm's serialize element builder is used to build the API. The serialize element builder ensures that we have the necessary fidelty to rehydrate correctly and is mandatory input for rehydration. --- Fastboot: ember-fastboot/fastboot#185 This allows enviroment variable to set _renderMode to be used in Visit API. Fastboot must send content to browser made with the serialization element builder to ensure rehydration can be sucessful. --- EmberCLI Fastboot: ember-fastboot#580 Finally this does the fun part of disabling the current clear-double-render instance-initializer We first check to ensure we are in a non-fastboot environment. Then we ensure that we can find the expected comment node from glimmer-vm's serialize element builder. This ensures that this change will only effect peoeple who use ember-cli-fastboot with the serialized output from the currently experimental fastboot setup Then we ensure `ApplicationInstance#_bootSync` specifies the rehydrate _renderMode. This is done in `_bootSync` this way because visit is currently not used to boot ember applications. And we must instead set bootOptions this way instead. We also remove the markings for `fastboot-body-start` and `fastboot-body-end` to ensure clear-double render instance-initializer is never called.
Expose as a configurable option the
renderModeoption. This optionwould be to specify the clientBuilder to be used when Glimmer does it's
append run.
The serialization mode, used by SSR applications, is used to specify
additional markings necessary to get enough fidelity to accurately
rehydrate the DOM. For example, it would provide additional comment
nodes with codes to ensure text nodes are separated when they are rather
than merged.
The rehydration mode is specifically designed to read DOM that is
produced by the serialization mode and accurately reproduce it.
A great description of how Rehydration works can be found in this
commit:
glimmerjs/glimmer-vm@316805b
This PR allows the appropriate ElementBuilder interface to be used via
the
visitAPI.Current plan:
This is part of an arching plan to introduce Glimmer's
rehydration/serializtion modes to Ember proper.
There are 4 PR's that are all interwoven, of which, this is one.
In order of need to land they are:
Glimmer.js:
glimmerjs/glimmer-vm#783 (comment)
This resolves a rather intimate API problem. Glimmer-vm expects a very
specific comment node to exist to know whether or not the rehydration
element builder can do it's job properly. If it is not found on the
first node from rootElement it throws.
In fastboot however we are certain that there will already be existant
elements in the way that will happen before rendered content.
This PR just iterates through the nodes until it finds the expected
comment node. And only throws if it never finds one.
Ember.js:
#16227
This PR modifies the visit API to allow a private _renderMode to be
set to either serialize or rehydrate. In SSR environments the
assumption (as it is here in this fastboot PR) is that we'll set the
visit API to serialize mode which ensures glimmer-vm's serialize element
builder is used to build the API.
The serialize element builder ensures that we have the necessary fidelty
to rehydrate correctly and is mandatory input for rehydration.
Fastboot:
ember-fastboot/fastboot#185
This allows enviroment variable to set _renderMode to be used in Visit
API. Fastboot must send content to browser made with the serialization
element builder to ensure rehydration can be sucessful.
EmberCLI Fastboot:
ember-fastboot/ember-cli-fastboot#580
Finally this does the fun part of disabling the current
clear-double-render instance-initializer
We first check to ensure we are in a non-fastboot environment. Then we
ensure that we can find the expected comment node from glimmer-vm's
serialize element builder. This ensures that this change will only
effect peoeple who use ember-cli-fastboot with the serialized output
from the currently experimental fastboot setup
Then we ensure ApplicationInstance#_bootSync specifies the rehydrate
_renderMode.
This is done in _bootSync this way because visit is currently not used
to boot ember applications. And we must instead set bootOptions this
way instead.
We also remove the markings for fastboot-body-start and
fastboot-body-end to ensure clear-double render instance-initializer
is never called.