@rangojs/router 0.11.0 → 0.12.1
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/testing/vitest.js +23 -3
- package/dist/types/deps/rsc-client.d.ts +1 -0
- package/dist/types/deps/rsc.d.ts +1 -1
- package/dist/types/deps/ssr.d.ts +1 -1
- package/dist/types/rsc/types.d.ts +9 -9
- package/dist/types/ssr/index.d.ts +27 -4
- package/dist/types/testing/flight.d.ts +4 -3
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +2 -0
- package/dist/types/testing/vitest.d.ts +2 -1
- package/dist/types/vite/plugins/vercel-output.d.ts +22 -3
- package/dist/types/vite/plugins/virtual-entries.d.ts +3 -2
- package/dist/vite/index.js +148 -72
- package/package.json +8 -3
- package/skills/testing/setup.md +7 -7
- package/src/cache/cache-runtime.ts +1 -1
- package/src/cache/segment-codec.ts +2 -2
- package/src/deps/rsc-client.ts +8 -0
- package/src/deps/rsc.ts +4 -2
- package/src/deps/ssr.ts +1 -0
- package/src/rsc/handler.ts +3 -3
- package/src/rsc/types.ts +9 -9
- package/src/ssr/index.tsx +132 -51
- package/src/testing/flight.ts +4 -3
- package/src/testing/vitest-stubs/plugin-rsc.ts +13 -5
- package/src/testing/vitest.ts +43 -6
- package/src/vite/plugins/use-cache-transform.ts +65 -1
- package/src/vite/plugins/vercel-output.ts +146 -88
- package/src/vite/plugins/virtual-entries.ts +14 -11
package/dist/testing/vitest.js
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
// src/testing/vitest.ts
|
|
2
|
-
import {
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
3
4
|
function here(relativeFromRoot) {
|
|
4
5
|
return fileURLToPath(new URL(`../../${relativeFromRoot}`, import.meta.url));
|
|
5
6
|
}
|
|
7
|
+
var RSD_SERVER_EDGE_SPEC = "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge";
|
|
8
|
+
var requireFromHere = createRequire(
|
|
9
|
+
import.meta.url
|
|
10
|
+
);
|
|
11
|
+
function resolveFromRouter(spec) {
|
|
12
|
+
try {
|
|
13
|
+
return requireFromHere.resolve(spec);
|
|
14
|
+
} catch {
|
|
15
|
+
return void 0;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
var rsdServerEdgePath = resolveFromRouter(RSD_SERVER_EDGE_SPEC);
|
|
6
19
|
function rangoTestAliases(opts = {}) {
|
|
7
20
|
const aliases = [
|
|
8
21
|
// Real impls (index.rsc.ts) for the bare specifier ONLY — exact regex so
|
|
@@ -14,10 +27,16 @@ function rangoTestAliases(opts = {}) {
|
|
|
14
27
|
replacement: here("src/testing/vitest-stubs/version.ts")
|
|
15
28
|
},
|
|
16
29
|
{
|
|
17
|
-
find: /^@vitejs\/plugin-rsc\/rsc
|
|
30
|
+
find: /^@vitejs\/plugin-rsc\/rsc(\/(server|client))?$/,
|
|
18
31
|
replacement: here("src/testing/vitest-stubs/plugin-rsc.ts")
|
|
19
32
|
}
|
|
20
33
|
];
|
|
34
|
+
if (rsdServerEdgePath) {
|
|
35
|
+
aliases.push({
|
|
36
|
+
find: RSD_SERVER_EDGE_SPEC,
|
|
37
|
+
replacement: rsdServerEdgePath
|
|
38
|
+
});
|
|
39
|
+
}
|
|
21
40
|
if (opts.preset === "cloudflare") {
|
|
22
41
|
aliases.push(
|
|
23
42
|
{
|
|
@@ -63,8 +82,9 @@ function rangoUseClientTransform() {
|
|
|
63
82
|
});
|
|
64
83
|
if (!result) return void 0;
|
|
65
84
|
const { output } = result;
|
|
85
|
+
const rsdHref = rsdServerEdgePath ? pathToFileURL(rsdServerEdgePath).href : RSD_SERVER_EDGE_SPEC;
|
|
66
86
|
output.prepend(
|
|
67
|
-
`import * as $$RangoRSD from
|
|
87
|
+
`import * as $$RangoRSD from ${JSON.stringify(rsdHref)};
|
|
68
88
|
`
|
|
69
89
|
);
|
|
70
90
|
return {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createFromReadableStream, encodeReply, createClientTemporaryReferenceSet, } from "@vitejs/plugin-rsc/rsc/client";
|
package/dist/types/deps/rsc.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { renderToReadableStream, decodeReply, createTemporaryReferenceSet, loadServerAction, decodeAction, decodeFormState, } from "@vitejs/plugin-rsc/rsc";
|
|
1
|
+
export { renderToReadableStream, decodeReply, createTemporaryReferenceSet, loadServerAction, decodeAction, decodeFormState, } from "@vitejs/plugin-rsc/rsc/server";
|
package/dist/types/deps/ssr.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { createFromReadableStream, setOnClientReference, } from "@vitejs/plugin-rsc/ssr";
|
|
1
|
+
export { createFromReadableStream, setOnClientReference, getClientEntryUrl, } from "@vitejs/plugin-rsc/ssr";
|
|
@@ -107,37 +107,37 @@ export interface RscPayload {
|
|
|
107
107
|
*/
|
|
108
108
|
export type ReactFormState = unknown;
|
|
109
109
|
/**
|
|
110
|
-
* RSC dependencies from @vitejs/plugin-rsc/rsc
|
|
110
|
+
* RSC dependencies from @vitejs/plugin-rsc/rsc/server
|
|
111
111
|
*/
|
|
112
112
|
export interface RSCDependencies {
|
|
113
113
|
/**
|
|
114
|
-
* renderToReadableStream from @vitejs/plugin-rsc/rsc
|
|
114
|
+
* renderToReadableStream from @vitejs/plugin-rsc/rsc/server
|
|
115
115
|
*/
|
|
116
116
|
renderToReadableStream: <T>(payload: T, options?: {
|
|
117
117
|
temporaryReferences?: unknown;
|
|
118
118
|
onError?: (error: unknown) => string | void;
|
|
119
119
|
}) => ReadableStream<Uint8Array>;
|
|
120
120
|
/**
|
|
121
|
-
* decodeReply from @vitejs/plugin-rsc/rsc
|
|
121
|
+
* decodeReply from @vitejs/plugin-rsc/rsc/server
|
|
122
122
|
*/
|
|
123
123
|
decodeReply: (body: FormData | string, options?: {
|
|
124
124
|
temporaryReferences?: unknown;
|
|
125
125
|
}) => Promise<unknown[]>;
|
|
126
126
|
/**
|
|
127
|
-
* createTemporaryReferenceSet from @vitejs/plugin-rsc/rsc
|
|
127
|
+
* createTemporaryReferenceSet from @vitejs/plugin-rsc/rsc/server
|
|
128
128
|
*/
|
|
129
129
|
createTemporaryReferenceSet: () => unknown;
|
|
130
130
|
/**
|
|
131
|
-
* loadServerAction from @vitejs/plugin-rsc/rsc
|
|
131
|
+
* loadServerAction from @vitejs/plugin-rsc/rsc/server
|
|
132
132
|
*/
|
|
133
133
|
loadServerAction: (actionId: string) => Promise<Function>;
|
|
134
134
|
/**
|
|
135
|
-
* decodeAction from @vitejs/plugin-rsc/rsc
|
|
135
|
+
* decodeAction from @vitejs/plugin-rsc/rsc/server
|
|
136
136
|
* Decodes a FormData into a bound action function (for useActionState forms)
|
|
137
137
|
*/
|
|
138
138
|
decodeAction: (body: FormData) => Promise<() => Promise<unknown>>;
|
|
139
139
|
/**
|
|
140
|
-
* decodeFormState from @vitejs/plugin-rsc/rsc
|
|
140
|
+
* decodeFormState from @vitejs/plugin-rsc/rsc/server
|
|
141
141
|
* Decodes the action result into a ReactFormState for useActionState progressive enhancement
|
|
142
142
|
*/
|
|
143
143
|
decodeFormState: (actionResult: unknown, body: FormData) => Promise<ReactFormState | null>;
|
|
@@ -268,8 +268,8 @@ export interface CreateRSCHandlerOptions<TEnv = unknown, TRoutes extends Record<
|
|
|
268
268
|
*/
|
|
269
269
|
router: RangoInternal<TEnv, TRoutes>;
|
|
270
270
|
/**
|
|
271
|
-
* RSC dependencies from @vitejs/plugin-rsc/rsc.
|
|
272
|
-
* Defaults to the exports from @vitejs/plugin-rsc/rsc.
|
|
271
|
+
* RSC dependencies from @vitejs/plugin-rsc/rsc/server.
|
|
272
|
+
* Defaults to the exports from @vitejs/plugin-rsc/rsc/server.
|
|
273
273
|
*/
|
|
274
274
|
deps?: RSCDependencies;
|
|
275
275
|
/**
|
|
@@ -117,10 +117,19 @@ export interface SSRDependencies<TEnv = unknown> {
|
|
|
117
117
|
*/
|
|
118
118
|
injectRSCPayload: (rscStream: ReadableStream<Uint8Array>, options?: InjectRSCPayloadOptions) => TransformStream<Uint8Array, Uint8Array>;
|
|
119
119
|
/**
|
|
120
|
-
* Function to load bootstrap script content
|
|
121
|
-
*
|
|
120
|
+
* Function to load bootstrap script content.
|
|
121
|
+
* Required unless `getClientEntryUrl` is provided with `headScripts: "preinit"`.
|
|
122
|
+
* Custom SSR entries typically: `() => import.meta.viteRsc.loadBootstrapScriptContent("index")`
|
|
123
|
+
* (deprecated in `@vitejs/plugin-rsc` 0.5.33 in favor of `getClientEntryUrl`).
|
|
122
124
|
*/
|
|
123
|
-
loadBootstrapScriptContent
|
|
125
|
+
loadBootstrapScriptContent?: () => Promise<string>;
|
|
126
|
+
/**
|
|
127
|
+
* Client entry URL from `@vitejs/plugin-rsc/ssr` `getClientEntryUrl()`.
|
|
128
|
+
* Preferred when `headScripts` is `"preinit"`: Fizz receives `bootstrapModules`
|
|
129
|
+
* without the deprecated `loadBootstrapScriptContent` round-trip. Custom SSR
|
|
130
|
+
* entries can omit this and keep the inline bootstrap path.
|
|
131
|
+
*/
|
|
132
|
+
getClientEntryUrl?: () => string;
|
|
124
133
|
/**
|
|
125
134
|
* Document script strategy; the generated virtual SSR entry threads the
|
|
126
135
|
* `rango({ headScripts })` plugin option here (canonical docs on
|
|
@@ -251,7 +260,10 @@ interface ShellResumeOptions {
|
|
|
251
260
|
* @example
|
|
252
261
|
* ```tsx
|
|
253
262
|
* import { createSSRHandler } from "@rangojs/router/ssr";
|
|
254
|
-
* import {
|
|
263
|
+
* import {
|
|
264
|
+
* createFromReadableStream,
|
|
265
|
+
* getClientEntryUrl,
|
|
266
|
+
* } from "@rangojs/router/internal/deps/ssr";
|
|
255
267
|
* import { renderToReadableStream } from "react-dom/server.edge";
|
|
256
268
|
* import { injectRSCPayload } from "@rangojs/router/internal/deps/html-stream-server";
|
|
257
269
|
*
|
|
@@ -259,6 +271,17 @@ interface ShellResumeOptions {
|
|
|
259
271
|
* createFromReadableStream,
|
|
260
272
|
* renderToReadableStream,
|
|
261
273
|
* injectRSCPayload,
|
|
274
|
+
* getClientEntryUrl,
|
|
275
|
+
* headScripts: "preinit", // getClientEntryUrl is only used under "preinit"
|
|
276
|
+
* });
|
|
277
|
+
* ```
|
|
278
|
+
*
|
|
279
|
+
* Custom SSR entries that still use the deprecated bootstrap helper:
|
|
280
|
+
* ```tsx
|
|
281
|
+
* export const renderHTML = createSSRHandler({
|
|
282
|
+
* createFromReadableStream,
|
|
283
|
+
* renderToReadableStream,
|
|
284
|
+
* injectRSCPayload,
|
|
262
285
|
* loadBootstrapScriptContent: () =>
|
|
263
286
|
* import.meta.viteRsc.loadBootstrapScriptContent("index"),
|
|
264
287
|
* });
|
|
@@ -6,14 +6,15 @@
|
|
|
6
6
|
* the same react-server-dom serializer the router uses at runtime. It runs in
|
|
7
7
|
* plain node (no Vite, no browser), but ONLY under the `react-server` export
|
|
8
8
|
* condition. The serializer is the VENDORED build shipped with
|
|
9
|
-
* @vitejs/plugin-rsc — the public `@vitejs/plugin-rsc/rsc` entry
|
|
10
|
-
* imports Vite virtual modules and is not usable outside a Vite
|
|
9
|
+
* @vitejs/plugin-rsc — the public `@vitejs/plugin-rsc/rsc/server` entry
|
|
10
|
+
* top-level imports Vite virtual modules and is not usable outside a Vite
|
|
11
|
+
* build.
|
|
11
12
|
*
|
|
12
13
|
* Run the example/tests for this module via the dedicated rsc vitest project
|
|
13
14
|
* (vitest.rsc.config.ts), which forces `--conditions=react-server` on the
|
|
14
15
|
* worker. The main vitest project must NOT use that condition (it would flip
|
|
15
16
|
* React to the no-hooks server build and break the ~50 tests that mock
|
|
16
|
-
* @vitejs/plugin-rsc/rsc).
|
|
17
|
+
* @vitejs/plugin-rsc/rsc/server).
|
|
17
18
|
*
|
|
18
19
|
* Scope / limitations (v1):
|
|
19
20
|
* - Server-only / leaf trees. A tree containing a CLIENT component emits an
|
|
@@ -5,3 +5,5 @@ export declare const decodeReply: () => undefined;
|
|
|
5
5
|
export declare const decodeAction: () => undefined;
|
|
6
6
|
export declare const decodeFormState: () => undefined;
|
|
7
7
|
export declare const createTemporaryReferenceSet: () => Record<string, never>;
|
|
8
|
+
export declare const encodeReply: () => never;
|
|
9
|
+
export declare const createClientTemporaryReferenceSet: () => Record<string, never>;
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
* `@rangojs/router` specifier to its react-server entry (real impls) while
|
|
19
19
|
* leaving React as the client build — which is exactly what this helper does.
|
|
20
20
|
* - The build-only `@rangojs/router:version` virtual and `@vitejs/plugin-rsc/rsc`
|
|
21
|
-
* (whose real body imports unresolvable
|
|
21
|
+
* plus `/rsc/server`, `/rsc/client` (whose real body imports unresolvable
|
|
22
|
+
* Vite virtuals) are stubbed.
|
|
22
23
|
* - Cloudflare apps additionally import the `cloudflare:workers` /
|
|
23
24
|
* `cloudflare:email` runtime virtuals; pass `{ preset: "cloudflare" }` to stub them.
|
|
24
25
|
*
|
|
@@ -28,9 +28,11 @@
|
|
|
28
28
|
* type:module in scope the deployed (isolated) function loads them as
|
|
29
29
|
* CommonJS and fails on the first `import`.
|
|
30
30
|
*
|
|
31
|
-
* The launcher is bundled with
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* The launcher is bundled with rolldown (Vite 8's bundler — a production
|
|
32
|
+
* dependency of `vite`, resolved through the app's vite install) so a
|
|
33
|
+
* standalone consumer does not need `esbuild`. srvx (the Web->Node streaming
|
|
34
|
+
* bridge, a @rangojs/router dependency) and @vercel/functions (resolved from
|
|
35
|
+
* the app) are inlined; the RSC bundle stays a runtime-relative external.
|
|
34
36
|
*
|
|
35
37
|
* Timing: this runs in the `buildApp` hook (order "post"), which fires once
|
|
36
38
|
* after every environment has built, so dist/{client,rsc,ssr} all exist.
|
|
@@ -41,6 +43,23 @@
|
|
|
41
43
|
*/
|
|
42
44
|
import type { Plugin } from "vite";
|
|
43
45
|
import type { RangoVercelOptions, VercelPresetOptions } from "../plugin-types.js";
|
|
46
|
+
/**
|
|
47
|
+
* Resolve rolldown through the app's vite install (rolldown is a production
|
|
48
|
+
* dependency of Vite 8, unlike esbuild which is only an optional peer). Fall
|
|
49
|
+
* back to the app root, then the plugin's own vite, so a hoisted or
|
|
50
|
+
* workspace copy still works. Issue #785: the previous "esbuild ships with
|
|
51
|
+
* Vite" path broke standalone consumers on Vite 8.
|
|
52
|
+
*/
|
|
53
|
+
export declare function resolveRolldownPath(root: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Bundle the Node launcher into `funcDir/index.mjs`: srvx + @vercel/functions
|
|
56
|
+
* inlined, `./rsc/index.js` left as a runtime-relative external.
|
|
57
|
+
*/
|
|
58
|
+
export declare function bundleVercelLauncher(opts: {
|
|
59
|
+
root: string;
|
|
60
|
+
funcDir: string;
|
|
61
|
+
srvxNodePath: string;
|
|
62
|
+
}): Promise<void>;
|
|
44
63
|
/**
|
|
45
64
|
* Reject a non-Node runtime for the vercel preset. The preset only emits a Node
|
|
46
65
|
* serverless function (launcherType "Nodejs", bundled Node APIs, response
|
|
@@ -3,8 +3,9 @@ export declare const VIRTUAL_ENTRY_BROWSER: string;
|
|
|
3
3
|
/**
|
|
4
4
|
* Generate the virtual SSR entry. `headScripts` mirrors the rango() plugin
|
|
5
5
|
* option: "preinit" (default) installs the client-reference preinit hook and
|
|
6
|
-
*
|
|
7
|
-
* "preload" omits the hook and
|
|
6
|
+
* threads `getClientEntryUrl` so Fizz emits `bootstrapModules`;
|
|
7
|
+
* "preload" omits the hook and uses the deprecated inline
|
|
8
|
+
* `loadBootstrapScriptContent` bootstrap.
|
|
8
9
|
*/
|
|
9
10
|
export declare function getVirtualEntrySSR(headScripts?: HeadScriptsOption, progressiveChunkSize?: number): string;
|
|
10
11
|
/**
|
package/dist/vite/index.js
CHANGED
|
@@ -3048,6 +3048,7 @@ function useCacheTransform() {
|
|
|
3048
3048
|
} catch {
|
|
3049
3049
|
return;
|
|
3050
3050
|
}
|
|
3051
|
+
stripNullDirectiveFields(ast);
|
|
3051
3052
|
const filePath = normalizePath(path5.relative(projectRoot, id));
|
|
3052
3053
|
const isLayoutOrTemplate = LAYOUT_TEMPLATE_PATTERN.test(id);
|
|
3053
3054
|
if (hasDirective(ast.body, "use cache")) {
|
|
@@ -3058,7 +3059,8 @@ function useCacheTransform() {
|
|
|
3058
3059
|
id,
|
|
3059
3060
|
isBuild,
|
|
3060
3061
|
isLayoutOrTemplate,
|
|
3061
|
-
transformWrapExport
|
|
3062
|
+
transformWrapExport,
|
|
3063
|
+
hasDirective
|
|
3062
3064
|
);
|
|
3063
3065
|
}
|
|
3064
3066
|
const functionResult = transformFunctionLevelUseCache(
|
|
@@ -3077,7 +3079,7 @@ function useCacheTransform() {
|
|
|
3077
3079
|
}
|
|
3078
3080
|
};
|
|
3079
3081
|
}
|
|
3080
|
-
function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLayoutOrTemplate, transformWrapExport) {
|
|
3082
|
+
function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLayoutOrTemplate, transformWrapExport, hasDirective) {
|
|
3081
3083
|
const unconfirmedExports = [];
|
|
3082
3084
|
const { exportNames, output } = transformWrapExport(code, ast, {
|
|
3083
3085
|
runtime: (value, name) => {
|
|
@@ -3087,6 +3089,11 @@ function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLa
|
|
|
3087
3089
|
rejectNonAsyncFunction: false,
|
|
3088
3090
|
filter: (name, meta) => {
|
|
3089
3091
|
if (name === "default" && isLayoutOrTemplate) return false;
|
|
3092
|
+
if (name.startsWith("$$hoist_")) return false;
|
|
3093
|
+
if (isHoistedServerReferenceRebind(meta.valueNode)) return false;
|
|
3094
|
+
if (functionHasUseServerDirective(meta.valueNode, hasDirective)) {
|
|
3095
|
+
return false;
|
|
3096
|
+
}
|
|
3090
3097
|
if (meta.isFunction !== true) {
|
|
3091
3098
|
unconfirmedExports.push(name);
|
|
3092
3099
|
return false;
|
|
@@ -3158,6 +3165,36 @@ function transformFunctionLevelUseCache(code, ast, filePath, sourceId, isBuild,
|
|
|
3158
3165
|
return;
|
|
3159
3166
|
}
|
|
3160
3167
|
}
|
|
3168
|
+
function stripNullDirectiveFields(node) {
|
|
3169
|
+
if (!node || typeof node !== "object") return;
|
|
3170
|
+
const rec = node;
|
|
3171
|
+
if (rec.type === "ExpressionStatement" && typeof rec.directive !== "string") {
|
|
3172
|
+
delete rec.directive;
|
|
3173
|
+
}
|
|
3174
|
+
for (const value of Object.values(rec)) {
|
|
3175
|
+
if (Array.isArray(value)) {
|
|
3176
|
+
for (const item of value) stripNullDirectiveFields(item);
|
|
3177
|
+
} else if (value && typeof value === "object" && "type" in value) {
|
|
3178
|
+
stripNullDirectiveFields(value);
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3182
|
+
function isHoistedServerReferenceRebind(valueNode) {
|
|
3183
|
+
if (!valueNode || valueNode.type !== "CallExpression") return false;
|
|
3184
|
+
const first = valueNode.arguments[0];
|
|
3185
|
+
return first !== void 0 && first.type === "Identifier" && first.name.startsWith("$$hoist_");
|
|
3186
|
+
}
|
|
3187
|
+
function functionHasUseServerDirective(valueNode, hasDirective) {
|
|
3188
|
+
if (!valueNode || !("body" in valueNode)) return false;
|
|
3189
|
+
const { body } = valueNode;
|
|
3190
|
+
if (!body || Array.isArray(body) || body.type !== "BlockStatement") {
|
|
3191
|
+
return false;
|
|
3192
|
+
}
|
|
3193
|
+
return hasDirective(
|
|
3194
|
+
body.body,
|
|
3195
|
+
"use server"
|
|
3196
|
+
);
|
|
3197
|
+
}
|
|
3161
3198
|
function findFileLevelDirective(ast) {
|
|
3162
3199
|
for (const node of ast.body ?? []) {
|
|
3163
3200
|
if (node.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string" && node.expression.value.startsWith("use cache")) {
|
|
@@ -3501,7 +3538,7 @@ function emitProgressiveChunkSize(value) {
|
|
|
3501
3538
|
}
|
|
3502
3539
|
function getVirtualEntrySSR(headScripts = "preinit", progressiveChunkSize) {
|
|
3503
3540
|
const preinit = headScripts !== "preload";
|
|
3504
|
-
const depsImportNames = preinit ? "createFromReadableStream,\n setOnClientReference," : "createFromReadableStream,";
|
|
3541
|
+
const depsImportNames = preinit ? "createFromReadableStream,\n setOnClientReference,\n getClientEntryUrl," : "createFromReadableStream,";
|
|
3505
3542
|
const ssrImportNames = preinit ? "\n installClientReferencePreinit," : "";
|
|
3506
3543
|
const install = preinit ? `
|
|
3507
3544
|
// Upgrade client-reference modulepreload hints to executing module scripts in
|
|
@@ -3509,6 +3546,8 @@ function getVirtualEntrySSR(headScripts = "preinit", progressiveChunkSize) {
|
|
|
3509
3546
|
// See src/ssr/preinit-client-references.ts for the full rationale.
|
|
3510
3547
|
installClientReferencePreinit(setOnClientReference);
|
|
3511
3548
|
` : "";
|
|
3549
|
+
const bootstrapDep = preinit ? "getClientEntryUrl," : `loadBootstrapScriptContent: () =>
|
|
3550
|
+
import.meta.viteRsc.loadBootstrapScriptContent("index"),`;
|
|
3512
3551
|
const hs = JSON.stringify(headScripts);
|
|
3513
3552
|
const pcs = progressiveChunkSize !== void 0 ? `
|
|
3514
3553
|
progressiveChunkSize: ${emitProgressiveChunkSize(progressiveChunkSize)},` : "";
|
|
@@ -3530,8 +3569,7 @@ export const renderHTML = createSSRHandler({
|
|
|
3530
3569
|
renderToReadableStream,
|
|
3531
3570
|
injectRSCPayload,
|
|
3532
3571
|
headScripts: ${hs},${pcs}
|
|
3533
|
-
|
|
3534
|
-
import.meta.viteRsc.loadBootstrapScriptContent("index"),
|
|
3572
|
+
${bootstrapDep}
|
|
3535
3573
|
});
|
|
3536
3574
|
|
|
3537
3575
|
export const captureShellHTML = createShellCaptureHandler({
|
|
@@ -3541,8 +3579,7 @@ export const captureShellHTML = createShellCaptureHandler({
|
|
|
3541
3579
|
prerender,
|
|
3542
3580
|
resume,
|
|
3543
3581
|
headScripts: ${hs},${pcs}
|
|
3544
|
-
|
|
3545
|
-
import.meta.viteRsc.loadBootstrapScriptContent("index"),
|
|
3582
|
+
${bootstrapDep}
|
|
3546
3583
|
});
|
|
3547
3584
|
|
|
3548
3585
|
export const resumeShellHTML = createShellResumeHandler({
|
|
@@ -3552,8 +3589,7 @@ export const resumeShellHTML = createShellResumeHandler({
|
|
|
3552
3589
|
prerender,
|
|
3553
3590
|
resume,
|
|
3554
3591
|
headScripts: ${hs},${pcs}
|
|
3555
|
-
|
|
3556
|
-
import.meta.viteRsc.loadBootstrapScriptContent("index"),
|
|
3592
|
+
${bootstrapDep}
|
|
3557
3593
|
});
|
|
3558
3594
|
`.trim();
|
|
3559
3595
|
}
|
|
@@ -3710,7 +3746,7 @@ import { resolve } from "node:path";
|
|
|
3710
3746
|
// package.json
|
|
3711
3747
|
var package_default = {
|
|
3712
3748
|
name: "@rangojs/router",
|
|
3713
|
-
version: "0.
|
|
3749
|
+
version: "0.12.1",
|
|
3714
3750
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
3715
3751
|
keywords: [
|
|
3716
3752
|
"react",
|
|
@@ -3798,6 +3834,11 @@ var package_default = {
|
|
|
3798
3834
|
"react-server": "./src/deps/rsc.ts",
|
|
3799
3835
|
default: "./src/deps/rsc.ts"
|
|
3800
3836
|
},
|
|
3837
|
+
"./internal/deps/rsc-client": {
|
|
3838
|
+
types: "./dist/types/deps/rsc-client.d.ts",
|
|
3839
|
+
"react-server": "./src/deps/rsc-client.ts",
|
|
3840
|
+
default: "./src/deps/rsc-client.ts"
|
|
3841
|
+
},
|
|
3801
3842
|
"./internal/deps/html-stream-client": {
|
|
3802
3843
|
types: "./dist/types/deps/html-stream-client.d.ts",
|
|
3803
3844
|
default: "./src/deps/html-stream-client.ts"
|
|
@@ -3903,7 +3944,7 @@ var package_default = {
|
|
|
3903
3944
|
},
|
|
3904
3945
|
dependencies: {
|
|
3905
3946
|
"@types/debug": "^4.1.12",
|
|
3906
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
3947
|
+
"@vitejs/plugin-rsc": "^0.5.34",
|
|
3907
3948
|
debug: "^4.4.1",
|
|
3908
3949
|
"magic-string": "^0.30.17",
|
|
3909
3950
|
picomatch: "^4.0.4",
|
|
@@ -3936,7 +3977,7 @@ var package_default = {
|
|
|
3936
3977
|
"@playwright/test": "^1.49.1",
|
|
3937
3978
|
"@testing-library/react": ">=16",
|
|
3938
3979
|
"@vercel/functions": "^3.0.0",
|
|
3939
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
3980
|
+
"@vitejs/plugin-rsc": "^0.5.34",
|
|
3940
3981
|
react: ">=19.2.8 <20",
|
|
3941
3982
|
"react-dom": ">=19.2.8 <20",
|
|
3942
3983
|
vite: "^8.0.16",
|
|
@@ -5641,6 +5682,7 @@ import { existsSync as existsSync5 } from "node:fs";
|
|
|
5641
5682
|
import { resolve as resolve5, join as join4 } from "node:path";
|
|
5642
5683
|
import { createRequire as createRequire2 } from "node:module";
|
|
5643
5684
|
import { pathToFileURL } from "node:url";
|
|
5685
|
+
var VIRTUAL_LAUNCHER_ID = "\0rango-vercel-launcher";
|
|
5644
5686
|
var LAUNCHER_SOURCE = `import { toNodeHandler } from "srvx/node";
|
|
5645
5687
|
import { waitUntil } from "@vercel/functions";
|
|
5646
5688
|
import rscHandler from "./rsc/index.js";
|
|
@@ -5660,6 +5702,99 @@ const fetchHandler = (request) =>
|
|
|
5660
5702
|
|
|
5661
5703
|
export default toNodeHandler(fetchHandler);
|
|
5662
5704
|
`;
|
|
5705
|
+
function resolveRolldownPath(root) {
|
|
5706
|
+
const appRequire = createRequire2(join4(root, "package.json"));
|
|
5707
|
+
const rangoRequire = createRequire2(import.meta.url);
|
|
5708
|
+
const attempts = [
|
|
5709
|
+
() => createRequire2(appRequire.resolve("vite")).resolve("rolldown"),
|
|
5710
|
+
() => appRequire.resolve("rolldown"),
|
|
5711
|
+
() => createRequire2(rangoRequire.resolve("vite")).resolve("rolldown"),
|
|
5712
|
+
() => rangoRequire.resolve("rolldown")
|
|
5713
|
+
];
|
|
5714
|
+
for (const attempt of attempts) {
|
|
5715
|
+
try {
|
|
5716
|
+
return attempt();
|
|
5717
|
+
} catch {
|
|
5718
|
+
}
|
|
5719
|
+
}
|
|
5720
|
+
throw new Error(
|
|
5721
|
+
'[rango] preset "vercel" requires "rolldown" to bundle the function launcher. Vite 8 depends on it; reinstall dependencies.'
|
|
5722
|
+
);
|
|
5723
|
+
}
|
|
5724
|
+
async function bundleVercelLauncher(opts) {
|
|
5725
|
+
const { root, funcDir, srvxNodePath } = opts;
|
|
5726
|
+
const appRequire = createRequire2(join4(root, "package.json"));
|
|
5727
|
+
let vercelFunctionsPath;
|
|
5728
|
+
try {
|
|
5729
|
+
vercelFunctionsPath = appRequire.resolve("@vercel/functions");
|
|
5730
|
+
} catch {
|
|
5731
|
+
throw new Error(
|
|
5732
|
+
'[rango] preset "vercel": could not resolve "@vercel/functions". Add it to your app dependencies (it also backs VercelCacheStore).'
|
|
5733
|
+
);
|
|
5734
|
+
}
|
|
5735
|
+
let rolldownModule;
|
|
5736
|
+
try {
|
|
5737
|
+
rolldownModule = await import(pathToFileURL(resolveRolldownPath(root)).href);
|
|
5738
|
+
} catch {
|
|
5739
|
+
throw new Error(
|
|
5740
|
+
'[rango] preset "vercel" requires "rolldown" to bundle the function launcher. Vite 8 depends on it; reinstall dependencies.'
|
|
5741
|
+
);
|
|
5742
|
+
}
|
|
5743
|
+
const rolldownFn = rolldownModule.rolldown ?? rolldownModule.default?.rolldown;
|
|
5744
|
+
if (typeof rolldownFn !== "function") {
|
|
5745
|
+
throw new Error('[rango] preset "vercel": could not load rolldown().');
|
|
5746
|
+
}
|
|
5747
|
+
let bundle;
|
|
5748
|
+
try {
|
|
5749
|
+
bundle = await rolldownFn({
|
|
5750
|
+
input: VIRTUAL_LAUNCHER_ID,
|
|
5751
|
+
cwd: root,
|
|
5752
|
+
platform: "node",
|
|
5753
|
+
logLevel: "silent",
|
|
5754
|
+
resolve: {
|
|
5755
|
+
alias: {
|
|
5756
|
+
"srvx/node": srvxNodePath,
|
|
5757
|
+
"@vercel/functions": vercelFunctionsPath
|
|
5758
|
+
}
|
|
5759
|
+
},
|
|
5760
|
+
plugins: [
|
|
5761
|
+
{
|
|
5762
|
+
name: "rango-vercel-launcher",
|
|
5763
|
+
resolveId(id) {
|
|
5764
|
+
if (id === VIRTUAL_LAUNCHER_ID) return VIRTUAL_LAUNCHER_ID;
|
|
5765
|
+
if (id === "./rsc/index.js") {
|
|
5766
|
+
return { id: "./rsc/index.js", external: true };
|
|
5767
|
+
}
|
|
5768
|
+
return null;
|
|
5769
|
+
},
|
|
5770
|
+
load(id) {
|
|
5771
|
+
if (id === VIRTUAL_LAUNCHER_ID) return LAUNCHER_SOURCE;
|
|
5772
|
+
return null;
|
|
5773
|
+
}
|
|
5774
|
+
}
|
|
5775
|
+
]
|
|
5776
|
+
});
|
|
5777
|
+
await bundle.write({
|
|
5778
|
+
file: join4(funcDir, "index.mjs"),
|
|
5779
|
+
format: "esm",
|
|
5780
|
+
exports: "default",
|
|
5781
|
+
// @vercel/functions (and srvx) may contain dynamic import(); the
|
|
5782
|
+
// launcher must stay a single index.mjs — Vercel's handler field
|
|
5783
|
+
// points at that one file.
|
|
5784
|
+
codeSplitting: false
|
|
5785
|
+
});
|
|
5786
|
+
} catch (error) {
|
|
5787
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5788
|
+
if (/@vercel\/functions/.test(message)) {
|
|
5789
|
+
throw new Error(
|
|
5790
|
+
'[rango] preset "vercel": could not resolve "@vercel/functions". Add it to your app dependencies (it also backs VercelCacheStore).\n' + message
|
|
5791
|
+
);
|
|
5792
|
+
}
|
|
5793
|
+
throw error;
|
|
5794
|
+
} finally {
|
|
5795
|
+
await bundle?.close();
|
|
5796
|
+
}
|
|
5797
|
+
}
|
|
5663
5798
|
function assertVercelNodeRuntime(runtime2) {
|
|
5664
5799
|
if (runtime2 != null && !runtime2.startsWith("nodejs")) {
|
|
5665
5800
|
throw new Error(
|
|
@@ -5747,66 +5882,7 @@ async function assemble(root, options, assetsDir, publicDir) {
|
|
|
5747
5882
|
'[rango] preset "vercel" requires "srvx" (a dependency of @rangojs/router). Reinstall dependencies.'
|
|
5748
5883
|
);
|
|
5749
5884
|
}
|
|
5750
|
-
|
|
5751
|
-
const resolveEsbuildPath = () => {
|
|
5752
|
-
try {
|
|
5753
|
-
const viteRequire = createRequire2(appRequire.resolve("vite"));
|
|
5754
|
-
return viteRequire.resolve("esbuild");
|
|
5755
|
-
} catch {
|
|
5756
|
-
}
|
|
5757
|
-
try {
|
|
5758
|
-
return appRequire.resolve("esbuild");
|
|
5759
|
-
} catch {
|
|
5760
|
-
}
|
|
5761
|
-
return rangoRequire.resolve("esbuild");
|
|
5762
|
-
};
|
|
5763
|
-
let esbuildModule;
|
|
5764
|
-
try {
|
|
5765
|
-
esbuildModule = await import(pathToFileURL(resolveEsbuildPath()).href);
|
|
5766
|
-
} catch {
|
|
5767
|
-
throw new Error(
|
|
5768
|
-
'[rango] preset "vercel" requires "esbuild" to bundle the function launcher. It ships with Vite; reinstall dependencies (or add esbuild to your app dependencies).'
|
|
5769
|
-
);
|
|
5770
|
-
}
|
|
5771
|
-
const esbuildBuild = esbuildModule.build ?? esbuildModule.default?.build;
|
|
5772
|
-
if (typeof esbuildBuild !== "function") {
|
|
5773
|
-
throw new Error('[rango] preset "vercel": could not load esbuild.build.');
|
|
5774
|
-
}
|
|
5775
|
-
try {
|
|
5776
|
-
await esbuildBuild({
|
|
5777
|
-
stdin: {
|
|
5778
|
-
contents: LAUNCHER_SOURCE,
|
|
5779
|
-
resolveDir: root,
|
|
5780
|
-
sourcefile: "func-entry.mjs",
|
|
5781
|
-
loader: "js"
|
|
5782
|
-
},
|
|
5783
|
-
outfile: join4(funcDir, "index.mjs"),
|
|
5784
|
-
bundle: true,
|
|
5785
|
-
format: "esm",
|
|
5786
|
-
platform: "node",
|
|
5787
|
-
target: "node18",
|
|
5788
|
-
alias: { "srvx/node": srvxNodePath },
|
|
5789
|
-
plugins: [
|
|
5790
|
-
{
|
|
5791
|
-
name: "external-rsc-entry",
|
|
5792
|
-
setup(b) {
|
|
5793
|
-
b.onResolve({ filter: /^\.\/rsc\/index\.js$/ }, () => ({
|
|
5794
|
-
path: "./rsc/index.js",
|
|
5795
|
-
external: true
|
|
5796
|
-
}));
|
|
5797
|
-
}
|
|
5798
|
-
}
|
|
5799
|
-
]
|
|
5800
|
-
});
|
|
5801
|
-
} catch (error) {
|
|
5802
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
5803
|
-
if (/@vercel\/functions/.test(message)) {
|
|
5804
|
-
throw new Error(
|
|
5805
|
-
'[rango] preset "vercel": could not resolve "@vercel/functions". Add it to your app dependencies (it also backs VercelCacheStore).\n' + message
|
|
5806
|
-
);
|
|
5807
|
-
}
|
|
5808
|
-
throw error;
|
|
5809
|
-
}
|
|
5885
|
+
await bundleVercelLauncher({ root, funcDir, srvxNodePath });
|
|
5810
5886
|
await writeFile(
|
|
5811
5887
|
join4(funcDir, "package.json"),
|
|
5812
5888
|
JSON.stringify({ type: "module" }, null, 2) + "\n"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rangojs/router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "Django-inspired RSC router with composable URL patterns",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -88,6 +88,11 @@
|
|
|
88
88
|
"react-server": "./src/deps/rsc.ts",
|
|
89
89
|
"default": "./src/deps/rsc.ts"
|
|
90
90
|
},
|
|
91
|
+
"./internal/deps/rsc-client": {
|
|
92
|
+
"types": "./dist/types/deps/rsc-client.d.ts",
|
|
93
|
+
"react-server": "./src/deps/rsc-client.ts",
|
|
94
|
+
"default": "./src/deps/rsc-client.ts"
|
|
95
|
+
},
|
|
91
96
|
"./internal/deps/html-stream-client": {
|
|
92
97
|
"types": "./dist/types/deps/html-stream-client.d.ts",
|
|
93
98
|
"default": "./src/deps/html-stream-client.ts"
|
|
@@ -179,7 +184,7 @@
|
|
|
179
184
|
},
|
|
180
185
|
"dependencies": {
|
|
181
186
|
"@types/debug": "^4.1.12",
|
|
182
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
187
|
+
"@vitejs/plugin-rsc": "^0.5.34",
|
|
183
188
|
"debug": "^4.4.1",
|
|
184
189
|
"magic-string": "^0.30.17",
|
|
185
190
|
"picomatch": "^4.0.4",
|
|
@@ -212,7 +217,7 @@
|
|
|
212
217
|
"@playwright/test": "^1.49.1",
|
|
213
218
|
"@testing-library/react": ">=16",
|
|
214
219
|
"@vercel/functions": "^3.0.0",
|
|
215
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
220
|
+
"@vitejs/plugin-rsc": "^0.5.34",
|
|
216
221
|
"react": ">=19.2.8 <20",
|
|
217
222
|
"react-dom": ">=19.2.8 <20",
|
|
218
223
|
"vite": "^8.0.16",
|