Skip to content

Commit 952f158

Browse files
[defer-hydration] Initial draft (#15)
Merging as per #15 (review) * [defer-hydration] Initial draft * More details and examples * Fix readme link * Change status to "Proposal" * Correct merge. --------- Co-authored-by: Westbrook Johnson <westbrook.johnson@gmail.com>
1 parent f9624d6 commit 952f158

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ Check out the [Issues](https://github.com/webcomponents/community-protocols/issu
1313
| Proposal | Author | Status |
1414
|----------------|------------------|------------|
1515
| [Context] | Benjamin Delarre | Candidate |
16+
| [Defer Hydration] | Justin Fagnani | Proposal |
1617
| [Pending Task] | Justin Fagnani | Draft |
1718
| [Slottable Request] | Kevin Schaaf | Proposal |
1819

1920
[Context]: https://github.com/webcomponents/community-protocols/blob/main/proposals/context.md
21+
[Defer Hydration]: https://github.com/webcomponents/community-protocols/blob/main/proposals/defer-hydration.md
2022
[Pending Task]: https://github.com/webcomponents/community-protocols/blob/main/proposals/pending-task.md
2123
[Slottable Request]: https://github.com/webcomponents/community-protocols/blob/main/proposals/slottable-request.md
2224

proposals/defer-hydration.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Defer Hydration Protocol
2+
3+
An open protocol for controlling hydration on the client.
4+
5+
Author: Justin Fagnani
6+
7+
Status: Proposal
8+
9+
Last update: 2021-06-24
10+
11+
# Background
12+
13+
In server-side rendered (SSR) applications, the process of a component running code to re-associate its template with the server-rendered DOM is called "hydration". The defer-hydration protocol is design to allow controler over hydration to solve two related problems:
14+
15+
1. Interoperable incremental hydration across web components. Componentents should not automatically hydrate upon being defined, but wait for a signal from their parent or other coordinator.
16+
2. Hydration ordering independent of definition order. Because components usually depend on data from their parent, and the parent won't usually set data on a child until it's hydrated, we need hydration to occur in a top-down order.
17+
18+
`defer-hydration` enables us to decouple loading the code for web component definitions from starting the work of hydration, and enables top-down ordering and sophisticated coordination of hydration, including triggering hydration only on interaction or data changes for specific components.
19+
20+
# Overview
21+
22+
The Defer Hydration Protocol specifies an attribute named `defer-hydration` that is placed on elements, usually during server rendering, to tell them not to hydrate when they are upgraded. Removing this attribute is a signal that the element should hydrate. Elements can observe the attribute being removed via `observedAttribute` and `attributeChangedCallback`.
23+
24+
When an element hydrates it can remove the `defer-hydration` attribute from its shadow children to hydrate them, or keep the attribute if itself can determine a more optimal time to hydrate all or certain children. By making the parent responsible for removing the `defer-hydration` attribute from it's children, we ensure top-down ordering.
25+
26+
## Use case 1: Auto-hydration with top-down odering
27+
28+
In this use case we want to page to hydrate as soon as elements are defined, but we want to force top-down ordering to avoid invalid child states. Here we configure the server-rendering step to add the `defer-hydration` attribute to all elements _except_ the top-most defer-hydration-aware elements in the document.
29+
30+
When the top-most elements are defined, they will run their hydrations steps since they don't have a `defer-hydration` attribute, and will trigger their subtrees to hydrate by removing `defer-hydration` from children.
31+
32+
Example HTML:
33+
34+
```html
35+
<!doctype html>
36+
<html>
37+
<head>
38+
<script type="module" src="./app.js"></script>
39+
</head>
40+
<body>
41+
<x-nav>
42+
<template shadowroot="open">
43+
<x-header defer-hydration>
44+
<template shadowroot="open">
45+
<h1>Example</h1>
46+
</template>
47+
</header>
48+
</template>
49+
<x-article>
50+
<template shadowroot="open">
51+
<x-figure defer-hydration>...</x-figure>
52+
</template>
53+
</x-article>
54+
</body>
55+
<html>
56+
```
57+
58+
## Use case 2: On-demand hydration
59+
60+
Hydration can be deferred until some data or user-driven signal, such as interacting with an element. In this case server-rendering is configured to add `defer-hydration` to all elements so that nothing will automatically hydrate.
61+
62+
An app-level coordinator may implement an event delegation/buffering/replay system to detect user-events within an element and remove `defer-hydration` on demand before replaying events.
63+
64+
*TODO: do we need to have an event that signals that hydration is complete before replaying events?*
65+
66+
## Hydrating children
67+
68+
```ts
69+
class MyElement extends HTMLElement {
70+
static observedAttributes = ['defer-hydration'];
71+
72+
attributeChangedCallback(name, oldValue, newValue) {
73+
if (name === 'defer-hydration' && newValue === null) {
74+
this._hydrate();
75+
}
76+
}
77+
78+
_hydrate() {
79+
// do template hydrate work
80+
// ...
81+
82+
// hydrate children
83+
const deferredChildren =
84+
this.shadowRoot.querySelectorAll('[defer-hydration]');
85+
for (const child of deferredChildren) {
86+
child.removeAttribute('defer-hydration');
87+
}
88+
}
89+
}
90+
```

0 commit comments

Comments
 (0)