Skip to content
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

feat: add hydration deferal to FAST #6403

Closed
nicholasrice opened this issue Sep 27, 2022 · 0 comments · Fixed by #6441
Closed

feat: add hydration deferal to FAST #6403

nicholasrice opened this issue Sep 27, 2022 · 0 comments · Fixed by #6441
Assignees
Labels
area:fast-element Pertains to fast-element area:ssr Pertains to SSR. feature A new feature task A task that's part of a body of feature work.
Milestone

Comments

@nicholasrice
Copy link
Contributor

nicholasrice commented Sep 27, 2022

🙋 Feature Request

FAST should support deferring element hydration for components rendered via the SSR renderer. Doing so will allow client-side applications to control the order and timing of element rendering, ensuring context / DI resolutions are timed correctly and that any async component fetching can performed prior to template rendering.

I propose aligning to the defer-hydration community protocol proposal. It defines a single boolean attribute, with removal of that attribute signaling to the element controller that the component should be hydrated.

What is Hydration, exactly?

Hydration is generally considered the taking-over of sever-rendered HTML by the client-side application. In component systems other than Web Components, hydration generally constructs component instances and runs any connection lifecycle hooks.

Web components are a little more complicated. Construction happens when the component is upgraded, and connectedCallback is invoked when the element is connected, regardless of the "hydration" state of the component. That means that both of these callbacks will be invoked prior to hydration. Historically, FAST has rendered the template during FASTElement.connectedCallback so many components make assumptions about template connectedness at that time, so this new behavior will likely require refactoring of components if hydration deferal is necessary for the SSR implementation.

Discussion Points

Because component constructors and connectedCallback can be invoked prior to hydration, a few questions are worth considering.

  1. Should behavior binding be defered until hydration is complete as well?
  2. Should ElementController.addStyles() add styles to the view before hydration?

Implementation

FAST-SSR

@microsoft/fast-ssr will yield the defer-hydration attribute during custom element rendering. We can make this behavior configurable, if necessary.

FAST-Element

ElementController will need to guard against rendering it's template and attaching main styles in cases where it detects the defer-hydration attribute during connection. This will require a slight refactoring the ElementController.

To detect removal of the defer-hydration attribute, there are two options:

observedAttributes and attributeChangedCallback()
By observing the defer-hydration attribute, the ElementController can be notified when the defer-hydration attribute is removed, performing any hydration steps necessary. This will be performant but comes with two slight disadvantages:

  1. Components will get notified for an attribute that was not enumerated by component authors. This could interfere with any code that assumes attributes invoking attributeChangedCallback() are user-defined.
  2. If, for whatever reason, the super.attributeChangedCallback() is not invoked, FASTElement will fail to hydrate.

Mutation Observer
FASTElement can set up a MutationObserver to observe only element instances for the defer-hydration attribute:

observer.observe(el, {
  attributeFilter: ['defer-hydration']
})

This approach works well because observed elements are held with weak references, meaning observing them will not prevent garbage collection, and observing the attribute will not alter component callback behaviors. There are disadvantages though:

  1. MutationObserver does not implement an unobserve(target) method (Disconnect single target instead of all whatwg/dom#126), so tearing down observers is complicated. Options include:
    1. Each element gets a dedicated MutationObserver, allowing disconnection after defer-hydration is removed
    2. Implement an unobserve(target) method that disconnects and then re-observers all other targets. This would require strong references, and is likely not very performant.
    3. Continue to observe targets until all elements implementing defer-hydration are hydrated, at which point the observer would disconnect.
@nicholasrice nicholasrice added status:triage New Issue - needs triage feature A new feature area:fast-element Pertains to fast-element task A task that's part of a body of feature work. area:ssr Pertains to SSR. and removed status:triage New Issue - needs triage labels Sep 27, 2022
@nicholasrice nicholasrice moved this from Triage to Todo in FAST Architecture Roadmap Sep 27, 2022
@nicholasrice nicholasrice added this to the SSR 1.0 milestone Sep 27, 2022
@EisenbergEffect EisenbergEffect moved this from Todo to In Progress in FAST Architecture Roadmap Sep 28, 2022
@EisenbergEffect EisenbergEffect moved this from In Progress to In Review in FAST Architecture Roadmap Sep 28, 2022
@EisenbergEffect EisenbergEffect moved this from In Review to Todo in FAST Architecture Roadmap Sep 30, 2022
@nicholasrice nicholasrice linked a pull request Oct 11, 2022 that will close this issue
9 tasks
@EisenbergEffect EisenbergEffect moved this from Todo to In Progress in FAST Architecture Roadmap Oct 12, 2022
Repository owner moved this from In Progress to Done in FAST Architecture Roadmap Oct 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:fast-element Pertains to fast-element area:ssr Pertains to SSR. feature A new feature task A task that's part of a body of feature work.
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

1 participant