@rsc-kit/core 0.20.8 → 0.20.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/earlyHints.d.ts +14 -2
- package/dist/earlyHints.js +15 -8
- package/dist/earlyHints.js.map +1 -1
- package/dist/host.d.ts +10 -1
- package/dist/host.js +16 -5
- package/dist/host.js.map +1 -1
- package/dist/js/segmentStore.d.ts +6 -0
- package/dist/js/segmentStore.js +17 -8
- package/dist/js/segmentStore.js.map +1 -1
- package/dist/prerender.d.ts +8 -0
- package/dist/prerender.js +9 -1
- package/dist/prerender.js.map +1 -1
- package/dist/vite.js +9 -2
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
package/dist/earlyHints.d.ts
CHANGED
|
@@ -13,5 +13,17 @@ export declare function linkHeader(assets: CriticalAssets): string;
|
|
|
13
13
|
* The first 16 KB, which is the head of any document this build writes.
|
|
14
14
|
*/
|
|
15
15
|
export declare function criticalAssetsOf(html: string): CriticalAssets;
|
|
16
|
-
/**
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* One set over another: the build's names, for a document whose own are not
|
|
18
|
+
* known.
|
|
19
|
+
*
|
|
20
|
+
* `primary` is null when nothing was read - a document rendered per request,
|
|
21
|
+
* whose head does not exist until after its headers have gone. A document
|
|
22
|
+
* that WAS read is the authority on itself, including when the answer is
|
|
23
|
+
* "nothing": a stored page with no client component names no module, and
|
|
24
|
+
* hinting the build's entry made the browser fetch 82 KB of runtime that
|
|
25
|
+
* the page never runs - the whole claim of a route that ships no
|
|
26
|
+
* JavaScript, undone by its own headers. Per field it was worse still: a
|
|
27
|
+
* page with its stylesheet inlined was hinted the build's stylesheet too.
|
|
28
|
+
*/
|
|
29
|
+
export declare function mergeAssets(primary: CriticalAssets | null, fallback: CriticalAssets | null): CriticalAssets;
|
package/dist/earlyHints.js
CHANGED
|
@@ -52,14 +52,21 @@ export function criticalAssetsOf(html) {
|
|
|
52
52
|
found.modules.push(entry[1]);
|
|
53
53
|
return found;
|
|
54
54
|
}
|
|
55
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* One set over another: the build's names, for a document whose own are not
|
|
57
|
+
* known.
|
|
58
|
+
*
|
|
59
|
+
* `primary` is null when nothing was read - a document rendered per request,
|
|
60
|
+
* whose head does not exist until after its headers have gone. A document
|
|
61
|
+
* that WAS read is the authority on itself, including when the answer is
|
|
62
|
+
* "nothing": a stored page with no client component names no module, and
|
|
63
|
+
* hinting the build's entry made the browser fetch 82 KB of runtime that
|
|
64
|
+
* the page never runs - the whole claim of a route that ships no
|
|
65
|
+
* JavaScript, undone by its own headers. Per field it was worse still: a
|
|
66
|
+
* page with its stylesheet inlined was hinted the build's stylesheet too.
|
|
67
|
+
*/
|
|
56
68
|
export function mergeAssets(primary, fallback) {
|
|
57
|
-
|
|
58
|
-
return primary;
|
|
59
|
-
return {
|
|
60
|
-
styles: primary.styles.length ? primary.styles : fallback.styles,
|
|
61
|
-
modules: primary.modules.length ? primary.modules : fallback.modules,
|
|
62
|
-
fonts: primary.fonts.length ? primary.fonts : fallback.fonts,
|
|
63
|
-
};
|
|
69
|
+
return primary ?? fallback ?? EMPTY;
|
|
64
70
|
}
|
|
71
|
+
const EMPTY = { styles: [], modules: [], fonts: [] };
|
|
65
72
|
//# sourceMappingURL=earlyHints.js.map
|
package/dist/earlyHints.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"earlyHints.js","sourceRoot":"","sources":["../src/earlyHints.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,yEAAyE;AACzE,wEAAwE;AACxE,sEAAsE;AACtE,yEAAyE;AACzE,oBAAoB;AACpB,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,0EAA0E;AAC1E,4EAA4E;AAC5E,4EAA4E;AAC5E,+DAA+D;AAW/D,0EAA0E;AAC1E,MAAM,UAAU,UAAU,CAAC,MAAsB;IAC/C,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,0BAA0B,CAAC,CAAA;IAChF,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,sBAAsB,CAAC,CAAA;IAC7E,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,sCAAsC,CAAC,CAAA;IAE3F,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,GAAG,MAAM,CAAA;AACzB,MAAM,IAAI,GAAG,gBAAgB,CAAA;AAC7B,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,GAAW,EAAiB,EAAE;IACxD,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,IAAI,mBAAmB,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAEtE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAChC,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAA;IACtC,MAAM,KAAK,GAAmB,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;IAEpE,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,WAAW,EAAE,CAAA;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAE9B,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QAE5C,IAAI,GAAG,KAAK,YAAY;YAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;aAC5C,IAAI,GAAG,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,WAAW,EAAE,KAAK,MAAM;YAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACjG,CAAC;IAED,2EAA2E;IAC3E,yEAAyE;IACzE,MAAM,KAAK,GAAG,kCAAkC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,kCAAkC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEzH,IAAI,KAAK;QAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAEvC,OAAO,KAAK,CAAA;AACd,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"earlyHints.js","sourceRoot":"","sources":["../src/earlyHints.ts"],"names":[],"mappings":"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","sourcesContent":["// The Link header a document answers with, for a CDN to send ahead as 103\n// Early Hints - so the stylesheet, the client entry and the fonts are on\n// their way while the HTML is still being written. Cloudflare turns the\n// header into hints and caches them at the edge for the next visitor;\n// anything else passes it through, where a browser still reads it as the\n// document arrives.\n//\n// The critical set and nothing more: a hint promotes whatever it names, and\n// naming every chunk demotes the document behind them. The stylesheet and\n// the client entry come from the build's own manifest, the same names the\n// document carries. The fonts are the app's - preloaded in its layout - and\n// are read from a stored document's own head; a rendered document's head is\n// not known until it is rendered, after its headers have gone.\n\nexport interface CriticalAssets {\n /** Stylesheets the document links: `<link rel=\"stylesheet\">`. */\n styles: string[];\n /** The client entry: `<script type=\"module\">`'s import. */\n modules: string[];\n /** Fonts the document preloads: `<link rel=\"preload\" as=\"font\">`. */\n fonts: string[];\n}\n\n/** One `Link` header value for the set. Empty string for an empty set. */\nexport function linkHeader(assets: CriticalAssets): string {\n const parts: string[] = []\n\n for (const href of assets.styles) parts.push(`<${href}>; rel=preload; as=style`)\n for (const href of assets.modules) parts.push(`<${href}>; rel=modulepreload`)\n for (const href of assets.fonts) parts.push(`<${href}>; rel=preload; as=font; crossorigin`)\n\n return parts.join(', ')\n}\n\nconst HEAD_LIMIT = 16_384\nconst LINK = /<link\\s[^>]*>/g\nconst ATTR = (name: string, tag: string): string | null => {\n const match = new RegExp(`\\\\b${name}=[\"']([^\"']*)[\"']`, 'i').exec(tag)\n\n return match ? match[1] : null\n}\n\n/**\n * What a stored document's head names: its stylesheets and preloaded fonts.\n * The first 16 KB, which is the head of any document this build writes.\n */\nexport function criticalAssetsOf(html: string): CriticalAssets {\n const head = html.slice(0, HEAD_LIMIT)\n const found: CriticalAssets = { styles: [], modules: [], fonts: [] }\n\n for (const tag of head.match(LINK) ?? []) {\n const rel = ATTR('rel', tag)?.toLowerCase()\n const href = ATTR('href', tag)\n\n if (!href || !href.startsWith('/')) continue\n\n if (rel === 'stylesheet') found.styles.push(href)\n else if (rel === 'preload' && ATTR('as', tag)?.toLowerCase() === 'font') found.fonts.push(href)\n }\n\n // The bootstrap script is the last thing in the body, after the shell; its\n // import names the entry. The tail, then, and the head for a short page.\n const entry = /import\\([\"'](\\/[^\"']+\\.js)[\"']\\)/.exec(html.slice(-4096)) ?? /import\\([\"'](\\/[^\"']+\\.js)[\"']\\)/.exec(head)\n\n if (entry) found.modules.push(entry[1])\n\n return found\n}\n\n/**\n * One set over another: the build's names, for a document whose own are not\n * known.\n *\n * `primary` is null when nothing was read - a document rendered per request,\n * whose head does not exist until after its headers have gone. A document\n * that WAS read is the authority on itself, including when the answer is\n * \"nothing\": a stored page with no client component names no module, and\n * hinting the build's entry made the browser fetch 82 KB of runtime that\n * the page never runs - the whole claim of a route that ships no\n * JavaScript, undone by its own headers. Per field it was worse still: a\n * page with its stylesheet inlined was hinted the build's stylesheet too.\n */\nexport function mergeAssets(primary: CriticalAssets | null, fallback: CriticalAssets | null): CriticalAssets {\n return primary ?? fallback ?? EMPTY\n}\n\nconst EMPTY: CriticalAssets = { styles: [], modules: [], fonts: [] }\n"]}
|
package/dist/host.d.ts
CHANGED
|
@@ -60,7 +60,16 @@ export interface RscEngine {
|
|
|
60
60
|
handleRscResume?(component: string, props?: Record<string, unknown>, layouts?: {
|
|
61
61
|
component: string;
|
|
62
62
|
props: Record<string, unknown>;
|
|
63
|
-
}[], loadings?: string[], parallelSlots?: Record<string, string>, slotOverrides?: Record<string, unknown>, postponed?: unknown, nonce?: string, pageKey?: string, pathname?: string | null
|
|
63
|
+
}[], loadings?: string[], parallelSlots?: Record<string, string>, slotOverrides?: Record<string, unknown>, postponed?: unknown, nonce?: string, pageKey?: string, pathname?: string | null,
|
|
64
|
+
/**
|
|
65
|
+
* The real params, for the holes.
|
|
66
|
+
*
|
|
67
|
+
* Separate from `props`, which is the shape the shell was frozen with.
|
|
68
|
+
* A pattern shell is rendered with a placeholder per param, and the
|
|
69
|
+
* resume has to render the same tree above the holes or React cannot
|
|
70
|
+
* line them up; the values the holes need travel here.
|
|
71
|
+
*/
|
|
72
|
+
params?: Record<string, string>): Promise<{
|
|
64
73
|
htmlStream: ReadableStream;
|
|
65
74
|
}>;
|
|
66
75
|
handleRscRevalidate?(target: string, page: unknown): Promise<{
|
package/dist/host.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// const rsc = createRscHandler({ engine, manifest, assets })
|
|
15
15
|
// Bun.serve({ fetch: (req) => rsc(req).then((r) => r ?? new Response('', { status: 404 })) })
|
|
16
16
|
import { allowFor, matchApiRoute, matchIntercept, matchRoute, retentionKey, sharedDepth, } from "./routing.js";
|
|
17
|
-
import { pathKey, patternKey } from "./prerender.js";
|
|
17
|
+
import { PARAM_PLACEHOLDER, pathKey, patternKey } from "./prerender.js";
|
|
18
18
|
import { apiKey } from "./apiPrerender.js";
|
|
19
19
|
import { hostPath, hostSegment, routableHost } from "./hostRouting.js";
|
|
20
20
|
import { withRevalidation } from "./revalidate.js";
|
|
@@ -374,7 +374,6 @@ export function createRscHandler(options) {
|
|
|
374
374
|
/** What a stored document's head names, read once per file, for the Link header. */
|
|
375
375
|
const hinted = new WeakMap();
|
|
376
376
|
const hintsByKey = new Map();
|
|
377
|
-
const EMPTY_ASSETS = { styles: [], modules: [], fonts: [] };
|
|
378
377
|
/**
|
|
379
378
|
* The page a payload url belongs to, if this is one.
|
|
380
379
|
*
|
|
@@ -482,7 +481,7 @@ export function createRscHandler(options) {
|
|
|
482
481
|
// document, stored ones included - a stored document's own head
|
|
483
482
|
// names its fonts; a rendered one's is not known until too late.
|
|
484
483
|
if (response.status === 200 && (response.headers.get("Content-Type") ?? "").startsWith("text/html")) {
|
|
485
|
-
const link = linkHeader(mergeAssets(hinted.get(response) ??
|
|
484
|
+
const link = linkHeader(mergeAssets(hinted.get(response) ?? null, engine.criticalAssets?.() ?? null));
|
|
486
485
|
if (link)
|
|
487
486
|
response.headers.set("Link", link);
|
|
488
487
|
}
|
|
@@ -1035,7 +1034,19 @@ export function createRscHandler(options) {
|
|
|
1035
1034
|
// good. Fall through and render the page now instead.
|
|
1036
1035
|
if (state === null || !engine.handleRscResume || !route)
|
|
1037
1036
|
return null;
|
|
1038
|
-
|
|
1037
|
+
// A shell stored for the pattern was frozen with a placeholder for
|
|
1038
|
+
// every param - the build had no url to render for - and the tree
|
|
1039
|
+
// above its holes was shaped by those. Handing the real ones back
|
|
1040
|
+
// here renders a different tree wherever anything branches on a
|
|
1041
|
+
// param above a boundary, and React refuses to line the slots up:
|
|
1042
|
+
// "Expected the resume to render <X> in this slot but instead it
|
|
1043
|
+
// rendered <Y>", every hole client-rendered, a production page that
|
|
1044
|
+
// arrives inert. So the resume gets the shape the shell had, and the
|
|
1045
|
+
// values go to the holes through `params`.
|
|
1046
|
+
const forShape = shellKey === key
|
|
1047
|
+
? route.params
|
|
1048
|
+
: Object.fromEntries(Object.keys(route.params).map((name) => [name, PARAM_PLACEHOLDER]));
|
|
1049
|
+
const { htmlStream } = await engine.handleRscResume(route.route.component, forShape,
|
|
1039
1050
|
// Empty props, because that is what the build passed. Resuming replays
|
|
1040
1051
|
// the tree against the slots the shell left, and React matches those by
|
|
1041
1052
|
// key — so an argument that differs from the frozen render at all is a
|
|
@@ -1047,7 +1058,7 @@ export function createRscHandler(options) {
|
|
|
1047
1058
|
// key the tree differently from the one being resumed.
|
|
1048
1059
|
shellKey === key ? url.pathname : "",
|
|
1049
1060
|
// But the url itself, for the hooks: the holes are rendered for it.
|
|
1050
|
-
url.pathname);
|
|
1061
|
+
url.pathname, route.params);
|
|
1051
1062
|
// A shell stored for the pattern was built without a url, so its title
|
|
1052
1063
|
// is the layouts' - the page's generateMetadata reads the params and
|
|
1053
1064
|
// was left out. This request has the params.
|