Skip to content

Conversation

@rondale-sc
Copy link
Contributor

@rondale-sc rondale-sc commented Feb 8, 2018

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.


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.

@rondale-sc rondale-sc force-pushed the utilize-rehydration-serialization-from-glimmer branch from d53b2e8 to 994e154 Compare February 8, 2018 21:48
@josemarluedke
Copy link
Contributor

Awesome to see Rehydration coming to Ember!

@rwjblue rwjblue changed the title Allow visit to specify Rehydration/Serialization or default ClientBuilder [WIP] Allow visit to specify Rehydration/Serialization or default ClientBuilder Feb 9, 2018
@rondale-sc
Copy link
Contributor Author

rondale-sc commented Feb 9, 2018

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.

@rwjblue
Copy link
Member

rwjblue commented Feb 9, 2018

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.

@rondale-sc
Copy link
Contributor Author

Relevant to this ticket: glimmerjs/glimmer-vm#780

@rondale-sc
Copy link
Contributor Author

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

@rwjblue
Copy link
Member

rwjblue commented Feb 13, 2018

looks like this needs a rebase

@rondale-sc rondale-sc force-pushed the utilize-rehydration-serialization-from-glimmer branch from c6e16a3 to 26f9841 Compare February 13, 2018 21:00
@rondale-sc
Copy link
Contributor Author

@rwjblue Rebased. I'm still running tests locally, but should be gtg

@rondale-sc
Copy link
Contributor Author

Looks like I need to dig into this one. Working on it now.

@rondale-sc rondale-sc force-pushed the utilize-rehydration-serialization-from-glimmer branch 3 times, most recently from e633523 to 522a43b Compare February 14, 2018 20:03
Copy link
Member

@rwjblue rwjblue left a 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 div element 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(() => {
Copy link
Member

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%',
Copy link
Member

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?

Copy link
Contributor Author

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 => {
Copy link
Member

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.
@rondale-sc rondale-sc force-pushed the utilize-rehydration-serialization-from-glimmer branch from 8501563 to 04ad41d Compare February 22, 2018 15:57
_renderMode: 'rehydrate'
};

this.application.visit('/', bootOptions).then(instance => {
Copy link
Contributor Author

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.

Copy link
Member

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;
Copy link
Contributor Author

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.

rondale-sc added a commit to rondale-sc/fastboot that referenced this pull request Feb 23, 2018
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.
rondale-sc added a commit to rondale-sc/ember-cli-fastboot that referenced this pull request Feb 23, 2018
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 => {
Copy link
Member

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 😝

@rwjblue rwjblue changed the title [WIP] Allow visit to specify Rehydration/Serialization or default ClientBuilder Allow visit to specify Rehydration/Serialization or default ClientBuilder Feb 25, 2018
@rwjblue rwjblue merged commit 8be1a9d into emberjs:master Feb 25, 2018
rondale-sc added a commit to rondale-sc/ember-cli-fastboot that referenced this pull request Mar 10, 2018
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants