reactRuntimeSource
The browser half, for one React and its Flight (by their pinned aliases, so it shares the app's React):
serverComponent() makes the stub component that renders a server component's tree, read with Flight's client.
The browser components (contexts, lazy ones) a tree names are found by hash, as Parcel's runtime would load them
(parcelRequire): those of the stubs rendered.
Under server rendering (the page's first paint), globalThis.__tcmSsr is set: stubs render through it instead
of fetching, with one response cache per request. In the browser, the trees recorded that way are read from
__TCM_TREES__ first, so hydration sees the same tree the HTML was made from.
On a static site (__TCM_STATIC__), there's no server to ask: a tree is read from the file the build kept it in
(treeName), which it rendered for every page it found. The trees a page of the app shows are read before
it's gone to (__tcmPrefetch(path), which useAppLinks calls when a link to it is pointed at or pressed), from the
map the build keeps of them, and each is read once. A server app's are rendered by the server before a page is gone
to (/__tcm/page), and kept half a minute. A server component that renders the same for the same props (one
cacheableComponents finds) is asked for with GET, so a browser keeps its tree, and it's kept through server
function calls.
import { treeName } from "#codebase/tcmts/cli/rsc"; export function reactRuntimeSource( react: string, flight: string, runtime: string, codec: string, ): string { return `import { createElement, startTransition, use, useEffect, useState } from ${JSON.stringify(react)}; import { createFromFetch, createFromReadableStream } from ${JSON.stringify(`${flight}/client`)}; import * as flightClient from ${JSON.stringify(`${flight}/client`)}; import { encode, decode } from ${JSON.stringify(codec)}; import { onServerCall, reloadOutdated, remote } from ${JSON.stringify(runtime)}; const treeName = ${treeName}; // what trees name, by hash: each as the last stub naming it rendered it (server rendering, which renders the // pages of several builds in one process, shares one map, as it shares \`parcelRequire\`) const known = (globalThis.__tcmKnown ??= new Map()); const LAZY = Symbol.for("react.lazy"); const CONTEXT = Symbol.for("react.context"); // Flight renders a reference as \`lazy\` does, which takes a component: a context is provided by one, and a lazy one // rendered by one const components = new WeakMap(); function asComponent(c) { if (!c || typeof c !== "object" || (c.$$typeof !== CONTEXT && c.$$typeof !== LAZY)) return c; let made = components.get(c); if (!made) { made = c.$$typeof === CONTEXT ? ({ value, children }) => createElement(c, { value }, children) : (props) => createElement(c, props); components.set(c, made); } return made; } globalThis.parcelRequire ??= Object.assign((id) => ({ c: asComponent(known.get(id)) }), { load: () => Promise.resolve(), extendImportMap() {}, meta: { // where a lazy component's chunks are (\`<script>\`s server rendering puts in the page, so they load with it) get publicUrl() { return (globalThis.__TCM_BASE__ ?? "") + "/_app/"; }, // in development, where Flight asks for the code of a server stack frame (\`tcm dev\` answers) ...(import.meta.env?.DEV && typeof window !== "undefined" ? { devServer: globalThis.__TCM_BASE__ ?? "" } : {}), }, }); // a server function a server component gave a browser component (a reference to its hash): called as any server // function is (server rendering's Flight has no calls to make) const calls = new Map(); flightClient.setServerCallback?.((id, args) => { const hash = id.slice(0, id.indexOf("#")); let call = calls.get(hash); if (!call) calls.set(hash, (call = remote(hash, "a server function", true))); return call(...args); }); // a lazy one a tree names starts loading as the tree arrives (its hash, in its reference's row or one of its own), // not when React gets to it function warm(text) { for (const m of text.matchAll(/"([a-z2-7]{52})"/g)) { const c = known.get(m[1]); if (c && c.$$typeof === LAZY) { try { c._init(c._payload); } catch { // (loading: React's own way of saying so) } } } } // what a response says, read as it arrives (and given to Flight as it was) function watched(r) { if (!r.body) return r; const [mine, flights] = r.body.tee(); void (async () => { const reader = mine.getReader(); const text = new TextDecoder(); let rest = ""; for (;;) { const { value, done } = await reader.read(); if (done) break; const t = rest + text.decode(value, { stream: true }); const nl = t.lastIndexOf("\\n"); warm(t.slice(0, nl + 1)); rest = t.slice(nl + 1); } warm(rest); })().catch(() => {}); return new Response(flights, { status: r.status, headers: r.headers }); } function remoteError(e) { const err = new Error(e && e.message ? e.message : "the server failed"); err.name = e && e.name ? e.name : "RemoteError"; if (e && e.status) err.status = e.status; return err; } // a tree as Flight's text (one the page or a site file has) const fromText = (text) => { warm(text); return createFromFetch(Promise.resolve(new Response(text))); }; // server components that render the same for the same props: their trees are asked for with GET (a browser keeps // them), and kept here through server function calls const pure = new Set(); function fetchTree(hash, name, body) { if (globalThis.__TCM_STATIC__) return readTree(hash, name, body); const url = (globalThis.__TCM_BASE__ ?? "") + "/__tcm/rpc/" + hash; const sent = pure.has(hash) && body.length < 4000 ? fetch(url + "?p=" + encodeURIComponent(body)) : fetch(url, { method: "POST", headers: { "content-type": "application/json" }, body }); return createFromFetch( sent.then( async (r) => { if (r.status === 410) { reloadOutdated(); return new Promise(() => {}); } if (!r.ok) throw remoteError(decode(await r.text())); return watched(r); }, (e) => { throw new Error(name + ": the server is unreachable (" + e.message + ")"); }, ), ); } // a static site's: what the build rendered, each file read once. The page names the site's map (the file each tree // is in, by what it was rendered from, and the trees each page shows); files are named by their content, so a // browser keeps them const read = new Map(); const siteFile = (rel) => { let t = read.get(rel); if (!t) { t = fetch((globalThis.__TCM_BASE__ ?? "") + "/_app/" + rel).then( (r) => (r.ok ? r.text() : Promise.reject(new Error("its file isn't there (" + r.status + ")"))), (e) => Promise.reject(new Error("the site is unreachable (" + e.message + ")")), ); // (one that failed is read again next time) t.catch(() => read.delete(rel)); read.set(rel, t); } return t; }; const siteMap = () => typeof __TCM_STATIC__ === "string" ? siteFile(__TCM_STATIC__ + ".json").then(JSON.parse) : Promise.resolve({ trees: {}, pages: {} }); const treeText = (file) => siteFile("trees/" + file + ".txt"); if (typeof __TCM_STATIC__ !== "undefined" && typeof window !== "undefined") { // the trees a page shows, read before it's gone to globalThis.__tcmPrefetch = (path) => void siteMap().then((m) => { for (const k of m.pages[path] ?? []) if (m.trees[k]) treeText(m.trees[k]).catch(() => {}); }, () => {}); // (read once the page is idle, so a link pointed at reads only its page's trees) (window.requestIdleCallback ?? ((f) => setTimeout(f, 200)))(() => void siteMap().catch(() => {})); } function readTree(hash, name, body) { return createFromFetch( (async () => { try { const file = (await siteMap()).trees[treeName(hash + body)]; if (!file) throw new Error("not rendered"); const text = await treeText(file); warm(text); return new Response(text); } catch (e) { throw new Error(name + (e.message === "not rendered" ? " wasn't rendered with these props when the site was built: only what its pages show was" : ": " + e.message)); } })(), ); } // responses by server component and props, for the current generation (each server function call starts one) let generation = 0; const responses = new Map(); const listeners = new Set(); onServerCall(() => { generation++; for (const [k, e] of responses) if (e.generation < generation && !e.pure) responses.delete(k); // a transition: what's on screen stays until the new trees are ready startTransition(() => { for (const f of listeners) f(); }); }); // trees the server rendered into this page: the first render reads them, so hydration matches the HTML const recorded = typeof __TCM_TREES__ === "string" ? decode(__TCM_TREES__) : {}; // a server app's: what a page of the app shows (the trees its server components render), rendered by the server // before it's gone to, when a link to it is pointed at or pressed. Kept half a minute, or until a server function call if (typeof __TCM_STATIC__ === "undefined" && typeof window !== "undefined" && typeof __TCM_TREES__ === "string") globalThis.__tcmPrefetch = (path) => { void fetch((globalThis.__TCM_BASE__ ?? "") + "/__tcm/page?path=" + encodeURIComponent(path)) .then((r) => (r.ok ? r.text() : Promise.reject(r.status))) .then((text) => { const at = generation; for (const [key, tree] of Object.entries(decode(text))) { const e = responses.get(key); if (e && (e.generation === at || e.pure)) continue; // (one that renders the same for the same props is kept as any of its trees is) const kept = pure.has(key.slice(0, 52)); responses.set(key, { generation: at, res: fromText(tree), pure: kept, ...(kept ? {} : { until: Date.now() + 30000 }) }); } }) .catch(() => {}); }; function responseFor(hash, name, body) { const key = hash + body; const ssr = globalThis.__tcmSsr; const cache = ssr ? ssr.cache() : responses; const entry = cache.get(key); if (entry && (entry.generation === generation || entry.pure) && !(entry.until < Date.now())) return entry.res; const seen = !ssr && generation === 0 ? recorded[key] : undefined; let res; if (seen !== undefined) res = fromText(seen); else if (ssr) { // (rendered in this process, for this page's request) const bytes = new TextEncoder(); res = createFromReadableStream( new ReadableStream({ start(c) { ssr.render(hash, body, (text) => c.enqueue(bytes.encode(text))).then(() => c.close(), (e) => c.error(e)); }, }), ); } else res = fetchTree(hash, name, body); cache.set(key, { generation, res, pure: pure.has(hash) }); return res; } /** * A component rendered on the server: suspends until its tree arrives, and follows server function calls (but one that * renders the same for the same props keeps its tree). */ export function serverComponent(hash, name, refs, cacheable) { if (cacheable) pure.add(hash); const C = (props) => { for (const h in refs) known.set(h, refs[h]); const body = encode([props], "props of " + name); const [, rerender] = useState(0); useEffect(() => { const f = () => rerender((n) => n + 1); listeners.add(f); return () => listeners.delete(f); }, []); return use(responseFor(hash, name, body)); }; Object.defineProperty(C, "name", { value: name }); return C; } `; }