Skip to content

investigation: Hydration and Hydration markup #7176

@janechu

Description

@janechu

Note This document is in progress

Updated Hydration Implementation Proposal

Current implementation of hydration requires bindings to be rationalized with either comment or attribute markers. Doing this everywhere is compute intensive and can significantly grow the HTML being delivered, is there a way to create a rationalization of bindings from initial state and the declarative template?

Proposed Markup & Developer Experience

The DSD (Declarative Shadow DOM) created by a backend service should be as light as possible, if we remove hydration markup this may look something like so:

DOM:

<my-component greeting="Hello" name="world">
    <template shadowrootmode="open">
        Hello world
    </template>
</my-component>
<f-template name="my-component">
    <template>
        {{greeting}} {{name}}
    </template>
</f-template>

TypeScript:

class MyElement extends FASTElement {
    @attr
    greeting

    @attr
    name
}
MyElement.defineAsync({
    name: "my-component",
    templateOptions: "hydrate",
});

TemplateElement.define({
    name: "f-template",
});

In this simple case we have a single binding, defined as an attribute.

FAST Implementation Details

In order to achieve rationalization with DSD FAST needs to know the following:

  • Initial state (attributes, properties, etc., applied to the class instance and defined on the class prototype)
  • Template
  • Rendered output (DSD)

During registration the class prototype should be made available with all attribute and property lookups. We might safely assume that anything that is bound in the template is either one of these if we expect reactivity.

Possible sequence of events:

  • Partial definition with class created
  • Template evaluated for bindings
  • Initial state gathered
    • if no templateOptions are specified, do not attempt hydration, simply render the template and attach it to shadow DOM
    • if hydrate is used immediately gather initial state from available attributes and observables
    • if defer-and-hydrate is used, wait for defer-hydration to be removed then gather initial state
  • Render DOM in JS with createElement etc.
  • Walk the DSD and rationalize it with the rendered DOM (this needs some experimenting), throw errors when inconsistencies arise.
    Possible errors:
    • Initial state mismatch
    • Unexpected DOM nodes not matching with the template
    • In a debug mode potentially report the expected DOM
  • Finish hydration

Additional Complications

Acceptable Incomplete State

The potential exists for the desire for incomplete state, or, some method of determining a server only binding that is not expected to be tied to an attribute or property as it does not need to be updated, as outlined by #7133. This might mean a potential solution is that FASTElement itself leaves comment markers where certain types of mismatched DOM is expected, and to ignore the rendering of that piece.

Possible Outcomes

The investigation could result in one of (or more) potential outcomes:

  • A non comment/attribute hydration markup is not feasible
    • either will take too long to implement due to current core implementations that need to change
    • is horrendously perf heavy negating any perf gains
  • A non comment/attribute hydration markup is feasible

Future Possibilities

Using the f-template exclusively to identify @attr and @observable

Currently we have an implementation of a JSON schema being applied to the FAST definition of a component created when evaluating the f-template. If we can further reconcile this with @attr and @observable we can determine from the f-template alone where data can come from.

Example:

<f-template
    name="my-component"
    data-@attr-text="text|string"
>
    <template>
        {{text}}
    </template>
</f-template>

Metadata

Metadata

Type

Projects

Status

In Progress

Relationships

None yet

Development

No branches or pull requests

Issue actions