Skip to content
File

Blob: src/client/hydrate.tsx

typescript46 lines
1/// <reference lib="dom" />
2/// <reference types="react" />
3 
4import type { ComponentType } from "react";
5 
6import { hydrateRoot } from "react-dom/client";
7 
8function readProps<P>(host: HTMLElement): P | null {
9 const script = host.querySelector<HTMLScriptElement>("script[data-island-props]");
10 if (!script?.textContent) {
11 return null;
12 }
13 
14 try {
15 return JSON.parse(script.textContent) as P;
16 } catch {
17 return null;
18 }
19}
20 
21export function hydrateIsland<P>(name: string, Component: ComponentType<P>) {
22 const hosts = document.querySelectorAll<HTMLElement>(`[data-island="${name}"]`);
23 
24 for (const host of Array.from(hosts)) {
25 if (host.dataset.islandHydrated === "true") {
26 continue;
27 }
28 
29 const root = host.querySelector<HTMLElement>("[data-island-root]");
30 const props = readProps<P>(host);
31 if (!root || !props) {
32 continue;
33 }
34 
35 hydrateRoot(root, <Component {...props} />, {
36 onRecoverableError(error, errorInfo) {
37 console.error(`Recoverable hydration error in island "${name}"`, {
38 error,
39 componentStack: errorInfo.componentStack,
40 });
41 },
42 });
43 host.dataset.islandHydrated = "true";
44 }
45}