Skip to content
This repository was archived by the owner on Oct 29, 2024. It is now read-only.

Commit 4b00cf6

Browse files
committed
internal: Example of using incremental rehydration
This PR adds an example showing how to use intersection observer in conjunction with partial rehydration.
1 parent f4e2e65 commit 4b00cf6

File tree

7 files changed

+95
-41
lines changed

7 files changed

+95
-41
lines changed

packages/example-apps/basic/src/MyComponent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ setComponentTemplate(
5757
{{else}}
5858
<p>Component is not in a CJK locale</p>
5959
{{/if}}
60-
6160
<OtherComponent @count={{this.count}} /> <br/>
6261
<button {{on "click" this.increment}}>Increment</button>
6362
<TemplateOnlyComponent @name="For Glimmer"/>
63+
6464
`
6565
),
6666
MyComponent
Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,36 @@
11
import { renderComponent } from '@glimmer/core';
2-
import RehydratingComponent from './src/RehydratingComponent';
3-
4-
document.addEventListener(
5-
'DOMContentLoaded',
6-
() => {
7-
const element = document.querySelector('.static-component');
8-
renderComponent(RehydratingComponent, {
9-
element: element!,
10-
rehydrate: true,
11-
});
2+
import RehydratableCounter from './src/RehydratableCounter';
3+
4+
rehydrate({
5+
get RehydratableCounter() {
6+
// Can load components async
7+
return Promise.resolve(RehydratableCounter);
128
},
13-
{ once: true }
14-
);
9+
});
10+
11+
function rehydrate(componentMapping) {
12+
const hasHydrated = new WeakSet();
13+
const observer = new IntersectionObserver(
14+
(entries) => {
15+
entries.forEach(async (entry) => {
16+
if (entry.isIntersecting && !hasHydrated.has(entry.target)) {
17+
await renderComponent(await componentMapping[entry.target.dataset.hydrate], {
18+
element: entry.target.parentElement,
19+
args: JSON.parse(entry.target.querySelector('script').textContent),
20+
rehydrate: true,
21+
});
22+
hasHydrated.add(entry.target);
23+
}
24+
});
25+
},
26+
{
27+
root: null,
28+
}
29+
);
30+
31+
const rehydratables = Array.from(document.querySelectorAll('[data-hydrate]'));
32+
33+
for (const el of rehydratables) {
34+
observer.observe(el);
35+
}
36+
}

packages/example-apps/partial-rehydration/server.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export default async function handler(
1111
clientsideBundleLocation: string
1212
): Promise<void> {
1313
const ssrOutput = await renderToString(StaticComponent, {
14+
args: { foo: { bar: 'bar' } },
1415
rehydrate: true,
1516
});
1617

@@ -22,7 +23,7 @@ export default async function handler(
2223
</head>
2324
<body>
2425
<div id="app">${ssrOutput}</div>
25-
<script src="${clientsideBundleLocation}"></script>
26+
<script async src="${clientsideBundleLocation}"></script>
2627
</body>
2728
</html>
2829
`);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Component from '@glimmer/component';
2+
import { tracked } from '@glimmer/tracking';
3+
import { createTemplate, setComponentTemplate } from '@glimmer/core';
4+
import { on, action } from '@glimmer/modifier';
5+
import RehydratableRegion from './RehydratableRegion';
6+
7+
class RehydratableCounter extends Component {
8+
@tracked count = 1;
9+
10+
@action increment(): void {
11+
this.count++;
12+
}
13+
}
14+
15+
setComponentTemplate(
16+
createTemplate(
17+
{ on, RehydratableRegion },
18+
`<RehydratableRegion @name="RehydratableCounter" @data={{this.args}}>
19+
<h1>{{@message}}</h1>
20+
<p>{{@foo.bar}}</p>
21+
<p>You have clicked the button {{this.count}} times.</p>
22+
<button {{on "click" this.increment}}>Click</button>
23+
</RehydratableRegion>
24+
`
25+
),
26+
RehydratableCounter
27+
);
28+
29+
export default RehydratableCounter;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { createTemplate, setComponentTemplate, templateOnlyComponent } from '@glimmer/core';
2+
3+
function toJSON(args) {
4+
return JSON.stringify(args);
5+
}
6+
7+
export default setComponentTemplate(
8+
createTemplate(
9+
{ toJSON },
10+
`<div data-hydrate="{{@name}}" ...attributes>
11+
<script type="application/hydrate">{{toJSON @data}}</script>
12+
{{yield}}
13+
</div>
14+
`
15+
),
16+
templateOnlyComponent()
17+
);

packages/example-apps/partial-rehydration/src/RehydratingComponent.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

packages/example-apps/partial-rehydration/src/StaticComponent.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
import { createTemplate, setComponentTemplate, templateOnlyComponent } from '@glimmer/core';
2-
import RehydratingComponent from './RehydratingComponent';
2+
import RehydratableCounter from './RehydratableCounter';
33

44
const StaticComponent = setComponentTemplate(
55
createTemplate(
6-
{ RehydratingComponent },
6+
{ RehydratableCounter },
77
`<div class="static-component">
88
<h1>Hello I am a static component. I don't change after page load.</h1>
9-
<RehydratingComponent/>
9+
<div><RehydratableCounter @message="Hello World" @foo={{@foo}} /></div>
10+
<div><RehydratableCounter @message="Bye" /></div>
11+
<div><RehydratableCounter @message="Ciao" /></div>
12+
<div><RehydratableCounter @message="Adios" /></div>
13+
<div><RehydratableCounter @message="Hey1" /></div>
14+
<div><RehydratableCounter @message="Hey2" /></div>
15+
<div><RehydratableCounter @message="Hey3" /></div>
16+
<div><RehydratableCounter @message="Hey4" /></div>
17+
<div><RehydratableCounter @message="Hey5" /></div>
18+
<div><RehydratableCounter @message="Hey6" /></div>
1019
</div>
1120
`
1221
),

0 commit comments

Comments
 (0)