@rangojs/router 0.0.0-experimental.146 → 0.0.0-experimental.148
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/bin/rango.js +7 -0
- package/dist/vite/index.js +823 -235
- package/package.json +6 -1
- package/skills/mime-routes/SKILL.md +25 -17
- package/skills/ppr/SKILL.md +20 -10
- package/src/browser/event-controller.ts +16 -2
- package/src/browser/rsc-router.tsx +11 -0
- package/src/cache/cache-scope.ts +11 -2
- package/src/cache/cf/cf-cache-store.ts +60 -2
- package/src/cache/memory-segment-store.ts +32 -0
- package/src/cache/segment-codec.ts +47 -0
- package/src/cache/types.ts +14 -0
- package/src/cache/vercel/vercel-cache-store.ts +71 -2
- package/src/index.rsc.ts +6 -0
- package/src/prerender/build-shell-capture.ts +253 -0
- package/src/prerender/shell-manifest-key.ts +20 -0
- package/src/prerender/store.ts +10 -1
- package/src/router/content-negotiation.ts +47 -5
- package/src/router/match-middleware/cache-lookup.ts +12 -1
- package/src/router/metrics.ts +17 -2
- package/src/router/prerender-match.ts +21 -0
- package/src/router/router-interfaces.ts +7 -0
- package/src/router/router-options.ts +13 -0
- package/src/router.ts +5 -0
- package/src/rsc/capture-queue.ts +67 -0
- package/src/rsc/handler.ts +4 -2
- package/src/rsc/rsc-rendering.ts +131 -23
- package/src/rsc/shell-build-manifest.ts +274 -0
- package/src/rsc/shell-capture.ts +486 -63
- package/src/rsc/shell-serve.ts +44 -0
- package/src/rsc/ssr-setup.ts +54 -22
- package/src/segment-fragments.ts +124 -0
- package/src/server/context.ts +1 -0
- package/src/server/request-context.ts +65 -11
- package/src/ssr/index.tsx +47 -9
- package/src/ssr/ssr-root.tsx +35 -2
- package/src/urls/pattern-types.ts +27 -0
- package/src/vite/discovery/discover-routers.ts +27 -0
- package/src/vite/discovery/prerender-collection.ts +16 -0
- package/src/vite/discovery/shell-prerender-phase.ts +397 -0
- package/src/vite/discovery/state.ts +44 -0
- package/src/vite/plugins/version-plugin.ts +8 -0
- package/src/vite/rango.ts +1 -0
- package/src/vite/router-discovery.ts +310 -8
- package/src/vite/utils/prerender-utils.ts +25 -6
package/dist/vite/index.js
CHANGED
|
@@ -1,6 +1,201 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res, err) => function __init() {
|
|
4
|
+
if (err) throw err[0];
|
|
5
|
+
try {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
} catch (e) {
|
|
8
|
+
throw err = [e], e;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/vite/debug.ts
|
|
17
|
+
import debugFactory from "debug";
|
|
18
|
+
function createRangoDebugger(namespace) {
|
|
19
|
+
const primary = debugFactory(namespace);
|
|
20
|
+
const shadow = debugFactory(`vite:${namespace}`);
|
|
21
|
+
if (primary.enabled) return primary;
|
|
22
|
+
if (shadow.enabled) return shadow;
|
|
23
|
+
return void 0;
|
|
24
|
+
}
|
|
25
|
+
async function timed(debug12, label, fn) {
|
|
26
|
+
if (!debug12) return await fn();
|
|
27
|
+
const start = performance.now();
|
|
28
|
+
try {
|
|
29
|
+
return await fn();
|
|
30
|
+
} finally {
|
|
31
|
+
debug12("%s (%sms)", label, (performance.now() - start).toFixed(1));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function timedSync(debug12, label, fn) {
|
|
35
|
+
if (!debug12) return fn();
|
|
36
|
+
const start = performance.now();
|
|
37
|
+
try {
|
|
38
|
+
return fn();
|
|
39
|
+
} finally {
|
|
40
|
+
debug12("%s (%sms)", label, (performance.now() - start).toFixed(1));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function createCounter(debug12, label) {
|
|
44
|
+
if (!debug12) return void 0;
|
|
45
|
+
let n = 0;
|
|
46
|
+
let totalMs = 0;
|
|
47
|
+
let slowestMs = 0;
|
|
48
|
+
let slowestFile = "";
|
|
49
|
+
const record = (file, ms) => {
|
|
50
|
+
n++;
|
|
51
|
+
totalMs += ms;
|
|
52
|
+
if (ms > slowestMs) {
|
|
53
|
+
slowestMs = ms;
|
|
54
|
+
slowestFile = file;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
record,
|
|
59
|
+
time(file, fn) {
|
|
60
|
+
const start = performance.now();
|
|
61
|
+
let out;
|
|
62
|
+
try {
|
|
63
|
+
out = fn();
|
|
64
|
+
} catch (err) {
|
|
65
|
+
record(file, performance.now() - start);
|
|
66
|
+
throw err;
|
|
67
|
+
}
|
|
68
|
+
if (out && typeof out.then === "function") {
|
|
69
|
+
return out.finally(
|
|
70
|
+
() => record(file, performance.now() - start)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
record(file, performance.now() - start);
|
|
74
|
+
return out;
|
|
75
|
+
},
|
|
76
|
+
flush() {
|
|
77
|
+
if (n === 0) return;
|
|
78
|
+
debug12(
|
|
79
|
+
"%s: %d files, %sms total, slowest %sms %s",
|
|
80
|
+
label,
|
|
81
|
+
n,
|
|
82
|
+
totalMs.toFixed(1),
|
|
83
|
+
slowestMs.toFixed(1),
|
|
84
|
+
slowestFile
|
|
85
|
+
);
|
|
86
|
+
n = 0;
|
|
87
|
+
totalMs = 0;
|
|
88
|
+
slowestMs = 0;
|
|
89
|
+
slowestFile = "";
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
var NS;
|
|
94
|
+
var init_debug = __esm({
|
|
95
|
+
"src/vite/debug.ts"() {
|
|
96
|
+
"use strict";
|
|
97
|
+
NS = {
|
|
98
|
+
config: "rango:config",
|
|
99
|
+
discovery: "rango:discovery",
|
|
100
|
+
routes: "rango:routes",
|
|
101
|
+
prerender: "rango:prerender",
|
|
102
|
+
build: "rango:build",
|
|
103
|
+
dev: "rango:dev",
|
|
104
|
+
transform: "rango:transform",
|
|
105
|
+
chunks: "rango:chunks"
|
|
106
|
+
};
|
|
107
|
+
if (process.env.INTERNAL_RANGO_DEBUG) {
|
|
108
|
+
const existing = debugFactory.disable();
|
|
109
|
+
debugFactory.enable(existing ? `${existing},rango:*` : "rango:*");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// src/vite/plugins/client-ref-hashing.ts
|
|
115
|
+
var client_ref_hashing_exports = {};
|
|
116
|
+
__export(client_ref_hashing_exports, {
|
|
117
|
+
computeProductionHash: () => computeProductionHash,
|
|
118
|
+
hashClientRefs: () => hashClientRefs,
|
|
119
|
+
hashRefKey: () => hashRefKey,
|
|
120
|
+
transformClientRefs: () => transformClientRefs
|
|
121
|
+
});
|
|
122
|
+
import { relative as relative2 } from "node:path";
|
|
123
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
124
|
+
function hashRefKey(relativeId) {
|
|
125
|
+
return createHash2("sha256").update(relativeId).digest("hex").slice(0, 12);
|
|
126
|
+
}
|
|
127
|
+
function computeProductionHash(projectRoot, refKey) {
|
|
128
|
+
let toHash;
|
|
129
|
+
if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
|
|
130
|
+
toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
|
|
131
|
+
} else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
|
|
132
|
+
const absPath = decodeURIComponent(
|
|
133
|
+
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
|
|
134
|
+
);
|
|
135
|
+
toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
|
|
136
|
+
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
137
|
+
const absPath = refKey.slice(FS_PREFIX.length - 1);
|
|
138
|
+
toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
|
|
139
|
+
} else if (refKey.startsWith("/")) {
|
|
140
|
+
toHash = refKey.slice(1);
|
|
141
|
+
} else {
|
|
142
|
+
return refKey;
|
|
143
|
+
}
|
|
144
|
+
return hashRefKey(toHash);
|
|
145
|
+
}
|
|
146
|
+
function transformClientRefs(code, projectRoot) {
|
|
147
|
+
if (!code.includes("registerClientReference")) return null;
|
|
148
|
+
let hasReplacement = false;
|
|
149
|
+
const result = code.replace(
|
|
150
|
+
REGISTER_CLIENT_REF_RE,
|
|
151
|
+
(match, refKey) => {
|
|
152
|
+
const hash = computeProductionHash(projectRoot, refKey);
|
|
153
|
+
if (hash === refKey) return match;
|
|
154
|
+
hasReplacement = true;
|
|
155
|
+
return match.replace(`"${refKey}"`, `"${hash}"`);
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
return hasReplacement ? result : null;
|
|
159
|
+
}
|
|
160
|
+
function hashClientRefs(projectRoot) {
|
|
161
|
+
const counter = createCounter(debug7, "hash-client-refs");
|
|
162
|
+
return {
|
|
163
|
+
name: "@rangojs/router:hash-client-refs",
|
|
164
|
+
enforce: "post",
|
|
165
|
+
applyToEnvironment(env) {
|
|
166
|
+
return env.name === "rsc";
|
|
167
|
+
},
|
|
168
|
+
buildEnd() {
|
|
169
|
+
counter?.flush();
|
|
170
|
+
},
|
|
171
|
+
transform(code, id) {
|
|
172
|
+
const start = counter ? performance.now() : 0;
|
|
173
|
+
try {
|
|
174
|
+
const result = transformClientRefs(code, projectRoot);
|
|
175
|
+
if (result === null) return;
|
|
176
|
+
return { code: result, map: null };
|
|
177
|
+
} finally {
|
|
178
|
+
counter?.record(id, performance.now() - start);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
var debug7, CLIENT_PKG_PROXY_PREFIX, CLIENT_IN_SERVER_PKG_PROXY_PREFIX, FS_PREFIX, REGISTER_CLIENT_REF_RE;
|
|
184
|
+
var init_client_ref_hashing = __esm({
|
|
185
|
+
"src/vite/plugins/client-ref-hashing.ts"() {
|
|
186
|
+
"use strict";
|
|
187
|
+
init_debug();
|
|
188
|
+
debug7 = createRangoDebugger(NS.transform);
|
|
189
|
+
CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
|
|
190
|
+
CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
|
|
191
|
+
FS_PREFIX = "/@fs/";
|
|
192
|
+
REGISTER_CLIENT_REF_RE = /registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
1
196
|
// src/vite/rango.ts
|
|
2
|
-
import { readFileSync as
|
|
3
|
-
import { resolve as
|
|
197
|
+
import { readFileSync as readFileSync8, existsSync as existsSync9 } from "node:fs";
|
|
198
|
+
import { resolve as resolve12 } from "node:path";
|
|
4
199
|
|
|
5
200
|
// src/vite/plugins/expose-action-id.ts
|
|
6
201
|
import MagicString from "magic-string";
|
|
@@ -251,99 +446,8 @@ function findCallParenAfterGenerics(code, afterCalleeIndex) {
|
|
|
251
446
|
return -1;
|
|
252
447
|
}
|
|
253
448
|
|
|
254
|
-
// src/vite/debug.ts
|
|
255
|
-
import debugFactory from "debug";
|
|
256
|
-
var NS = {
|
|
257
|
-
config: "rango:config",
|
|
258
|
-
discovery: "rango:discovery",
|
|
259
|
-
routes: "rango:routes",
|
|
260
|
-
prerender: "rango:prerender",
|
|
261
|
-
build: "rango:build",
|
|
262
|
-
dev: "rango:dev",
|
|
263
|
-
transform: "rango:transform",
|
|
264
|
-
chunks: "rango:chunks"
|
|
265
|
-
};
|
|
266
|
-
if (process.env.INTERNAL_RANGO_DEBUG) {
|
|
267
|
-
const existing = debugFactory.disable();
|
|
268
|
-
debugFactory.enable(existing ? `${existing},rango:*` : "rango:*");
|
|
269
|
-
}
|
|
270
|
-
function createRangoDebugger(namespace) {
|
|
271
|
-
const primary = debugFactory(namespace);
|
|
272
|
-
const shadow = debugFactory(`vite:${namespace}`);
|
|
273
|
-
if (primary.enabled) return primary;
|
|
274
|
-
if (shadow.enabled) return shadow;
|
|
275
|
-
return void 0;
|
|
276
|
-
}
|
|
277
|
-
async function timed(debug11, label, fn) {
|
|
278
|
-
if (!debug11) return await fn();
|
|
279
|
-
const start = performance.now();
|
|
280
|
-
try {
|
|
281
|
-
return await fn();
|
|
282
|
-
} finally {
|
|
283
|
-
debug11("%s (%sms)", label, (performance.now() - start).toFixed(1));
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
function timedSync(debug11, label, fn) {
|
|
287
|
-
if (!debug11) return fn();
|
|
288
|
-
const start = performance.now();
|
|
289
|
-
try {
|
|
290
|
-
return fn();
|
|
291
|
-
} finally {
|
|
292
|
-
debug11("%s (%sms)", label, (performance.now() - start).toFixed(1));
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
function createCounter(debug11, label) {
|
|
296
|
-
if (!debug11) return void 0;
|
|
297
|
-
let n = 0;
|
|
298
|
-
let totalMs = 0;
|
|
299
|
-
let slowestMs = 0;
|
|
300
|
-
let slowestFile = "";
|
|
301
|
-
const record = (file, ms) => {
|
|
302
|
-
n++;
|
|
303
|
-
totalMs += ms;
|
|
304
|
-
if (ms > slowestMs) {
|
|
305
|
-
slowestMs = ms;
|
|
306
|
-
slowestFile = file;
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
return {
|
|
310
|
-
record,
|
|
311
|
-
time(file, fn) {
|
|
312
|
-
const start = performance.now();
|
|
313
|
-
let out;
|
|
314
|
-
try {
|
|
315
|
-
out = fn();
|
|
316
|
-
} catch (err) {
|
|
317
|
-
record(file, performance.now() - start);
|
|
318
|
-
throw err;
|
|
319
|
-
}
|
|
320
|
-
if (out && typeof out.then === "function") {
|
|
321
|
-
return out.finally(
|
|
322
|
-
() => record(file, performance.now() - start)
|
|
323
|
-
);
|
|
324
|
-
}
|
|
325
|
-
record(file, performance.now() - start);
|
|
326
|
-
return out;
|
|
327
|
-
},
|
|
328
|
-
flush() {
|
|
329
|
-
if (n === 0) return;
|
|
330
|
-
debug11(
|
|
331
|
-
"%s: %d files, %sms total, slowest %sms %s",
|
|
332
|
-
label,
|
|
333
|
-
n,
|
|
334
|
-
totalMs.toFixed(1),
|
|
335
|
-
slowestMs.toFixed(1),
|
|
336
|
-
slowestFile
|
|
337
|
-
);
|
|
338
|
-
n = 0;
|
|
339
|
-
totalMs = 0;
|
|
340
|
-
slowestMs = 0;
|
|
341
|
-
slowestFile = "";
|
|
342
|
-
}
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
|
|
346
449
|
// src/vite/plugins/expose-action-id.ts
|
|
450
|
+
init_debug();
|
|
347
451
|
var debug = createRangoDebugger(NS.transform);
|
|
348
452
|
function getRscPluginApi(config) {
|
|
349
453
|
let plugin = config.plugins.find((p) => p.name === "rsc:minimal");
|
|
@@ -1299,10 +1403,14 @@ ${binding.localName}.$$id = "${handlerId}";`;
|
|
|
1299
1403
|
return hasChanges;
|
|
1300
1404
|
}
|
|
1301
1405
|
|
|
1406
|
+
// src/vite/plugins/expose-internal-ids.ts
|
|
1407
|
+
init_debug();
|
|
1408
|
+
|
|
1302
1409
|
// src/vite/plugins/expose-ids/router-transform.ts
|
|
1303
1410
|
import MagicString2 from "magic-string";
|
|
1304
1411
|
import path3 from "node:path";
|
|
1305
1412
|
import { createHash } from "node:crypto";
|
|
1413
|
+
init_debug();
|
|
1306
1414
|
var debug2 = createRangoDebugger(NS.transform);
|
|
1307
1415
|
function skipLeadingTrivia(code, start, end) {
|
|
1308
1416
|
let i = start;
|
|
@@ -1922,6 +2030,7 @@ ${lazyImports.join(",\n")}
|
|
|
1922
2030
|
// src/vite/plugins/use-cache-transform.ts
|
|
1923
2031
|
import path5 from "node:path";
|
|
1924
2032
|
import MagicString4 from "magic-string";
|
|
2033
|
+
init_debug();
|
|
1925
2034
|
var debug4 = createRangoDebugger(NS.transform);
|
|
1926
2035
|
var CACHE_RUNTIME_IMPORT = "@rangojs/router/cache-runtime";
|
|
1927
2036
|
var LAYOUT_TEMPLATE_PATTERN = /\/(layout|template)\.(tsx?|jsx?)$/;
|
|
@@ -2115,6 +2224,7 @@ function warnOnNearMissDirectives(ast, fileId, warn) {
|
|
|
2115
2224
|
}
|
|
2116
2225
|
|
|
2117
2226
|
// src/vite/plugins/client-ref-dedup.ts
|
|
2227
|
+
init_debug();
|
|
2118
2228
|
var debug5 = createRangoDebugger(NS.transform);
|
|
2119
2229
|
var CLIENT_IN_SERVER_PROXY_PREFIX = "virtual:vite-rsc/client-in-server-package-proxy/";
|
|
2120
2230
|
function extractPackageName(absolutePath) {
|
|
@@ -2410,7 +2520,7 @@ import { resolve } from "node:path";
|
|
|
2410
2520
|
// package.json
|
|
2411
2521
|
var package_default = {
|
|
2412
2522
|
name: "@rangojs/router",
|
|
2413
|
-
version: "0.0.0-experimental.
|
|
2523
|
+
version: "0.0.0-experimental.148",
|
|
2414
2524
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
2415
2525
|
keywords: [
|
|
2416
2526
|
"react",
|
|
@@ -2538,6 +2648,11 @@ var package_default = {
|
|
|
2538
2648
|
types: "./src/build/index.ts",
|
|
2539
2649
|
import: "./src/build/index.ts"
|
|
2540
2650
|
},
|
|
2651
|
+
"./build/shell-capture": {
|
|
2652
|
+
types: "./src/prerender/build-shell-capture.ts",
|
|
2653
|
+
"react-server": "./src/prerender/build-shell-capture.ts",
|
|
2654
|
+
import: "./src/prerender/build-shell-capture.ts"
|
|
2655
|
+
},
|
|
2541
2656
|
"./host": {
|
|
2542
2657
|
types: "./src/host/index.ts",
|
|
2543
2658
|
"react-server": "./src/host/index.ts",
|
|
@@ -3849,6 +3964,13 @@ function createVersionPlugin() {
|
|
|
3849
3964
|
return {
|
|
3850
3965
|
name: "@rangojs/router:version",
|
|
3851
3966
|
enforce: "pre",
|
|
3967
|
+
// The build-time shell capture phase (producer B, #699) stamps entries
|
|
3968
|
+
// with THIS instance's version — the value folded into the shipped worker
|
|
3969
|
+
// — never the discovery temp server's own version-plugin value (a
|
|
3970
|
+
// different Date.now() stamp that would fail the serve-side gate).
|
|
3971
|
+
api: {
|
|
3972
|
+
getBuildVersion: () => currentVersion
|
|
3973
|
+
},
|
|
3852
3974
|
configResolved(config) {
|
|
3853
3975
|
isDev = config.command === "serve";
|
|
3854
3976
|
resolvedCacheDir = config.cacheDir ? String(config.cacheDir).replace(/\\/g, "/") : void 0;
|
|
@@ -3939,6 +4061,7 @@ import * as Vite from "vite";
|
|
|
3939
4061
|
import { isAbsolute, resolve as resolve4 } from "node:path";
|
|
3940
4062
|
|
|
3941
4063
|
// src/vite/plugins/performance-tracks.ts
|
|
4064
|
+
init_debug();
|
|
3942
4065
|
import { readFile } from "node:fs/promises";
|
|
3943
4066
|
var debug6 = createRangoDebugger(NS.transform);
|
|
3944
4067
|
var RSDW_PATCH_RE = /((?:var|let|const)\s+\w+\s*=\s*root\._children\s*,\s*(\w+)\s*=\s*root\._debugInfo\s*[;,])/;
|
|
@@ -4121,75 +4244,9 @@ function getManualChunks(id) {
|
|
|
4121
4244
|
return void 0;
|
|
4122
4245
|
}
|
|
4123
4246
|
|
|
4124
|
-
// src/vite/plugins/client-ref-hashing.ts
|
|
4125
|
-
import { relative as relative2 } from "node:path";
|
|
4126
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
4127
|
-
var debug7 = createRangoDebugger(NS.transform);
|
|
4128
|
-
var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
|
|
4129
|
-
var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
|
|
4130
|
-
var FS_PREFIX = "/@fs/";
|
|
4131
|
-
function hashRefKey(relativeId) {
|
|
4132
|
-
return createHash2("sha256").update(relativeId).digest("hex").slice(0, 12);
|
|
4133
|
-
}
|
|
4134
|
-
function computeProductionHash(projectRoot, refKey) {
|
|
4135
|
-
let toHash;
|
|
4136
|
-
if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
|
|
4137
|
-
toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
|
|
4138
|
-
} else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
|
|
4139
|
-
const absPath = decodeURIComponent(
|
|
4140
|
-
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
|
|
4141
|
-
);
|
|
4142
|
-
toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
|
|
4143
|
-
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
4144
|
-
const absPath = refKey.slice(FS_PREFIX.length - 1);
|
|
4145
|
-
toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
|
|
4146
|
-
} else if (refKey.startsWith("/")) {
|
|
4147
|
-
toHash = refKey.slice(1);
|
|
4148
|
-
} else {
|
|
4149
|
-
return refKey;
|
|
4150
|
-
}
|
|
4151
|
-
return hashRefKey(toHash);
|
|
4152
|
-
}
|
|
4153
|
-
var REGISTER_CLIENT_REF_RE = /registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
|
|
4154
|
-
function transformClientRefs(code, projectRoot) {
|
|
4155
|
-
if (!code.includes("registerClientReference")) return null;
|
|
4156
|
-
let hasReplacement = false;
|
|
4157
|
-
const result = code.replace(
|
|
4158
|
-
REGISTER_CLIENT_REF_RE,
|
|
4159
|
-
(match, refKey) => {
|
|
4160
|
-
const hash = computeProductionHash(projectRoot, refKey);
|
|
4161
|
-
if (hash === refKey) return match;
|
|
4162
|
-
hasReplacement = true;
|
|
4163
|
-
return match.replace(`"${refKey}"`, `"${hash}"`);
|
|
4164
|
-
}
|
|
4165
|
-
);
|
|
4166
|
-
return hasReplacement ? result : null;
|
|
4167
|
-
}
|
|
4168
|
-
function hashClientRefs(projectRoot) {
|
|
4169
|
-
const counter = createCounter(debug7, "hash-client-refs");
|
|
4170
|
-
return {
|
|
4171
|
-
name: "@rangojs/router:hash-client-refs",
|
|
4172
|
-
enforce: "post",
|
|
4173
|
-
applyToEnvironment(env) {
|
|
4174
|
-
return env.name === "rsc";
|
|
4175
|
-
},
|
|
4176
|
-
buildEnd() {
|
|
4177
|
-
counter?.flush();
|
|
4178
|
-
},
|
|
4179
|
-
transform(code, id) {
|
|
4180
|
-
const start = counter ? performance.now() : 0;
|
|
4181
|
-
try {
|
|
4182
|
-
const result = transformClientRefs(code, projectRoot);
|
|
4183
|
-
if (result === null) return;
|
|
4184
|
-
return { code: result, map: null };
|
|
4185
|
-
} finally {
|
|
4186
|
-
counter?.record(id, performance.now() - start);
|
|
4187
|
-
}
|
|
4188
|
-
}
|
|
4189
|
-
};
|
|
4190
|
-
}
|
|
4191
|
-
|
|
4192
4247
|
// src/vite/utils/client-chunks.ts
|
|
4248
|
+
init_debug();
|
|
4249
|
+
init_client_ref_hashing();
|
|
4193
4250
|
var debugChunks = createRangoDebugger(NS.chunks);
|
|
4194
4251
|
function isSharedRuntime(meta) {
|
|
4195
4252
|
return [meta.id, meta.normalizedId].some(
|
|
@@ -4545,6 +4602,7 @@ function createVersionInjectorPlugin(rscEntryPath) {
|
|
|
4545
4602
|
}
|
|
4546
4603
|
|
|
4547
4604
|
// src/vite/plugins/cjs-to-esm.ts
|
|
4605
|
+
init_debug();
|
|
4548
4606
|
var debug8 = createRangoDebugger(NS.transform);
|
|
4549
4607
|
function createCjsToEsmPlugin() {
|
|
4550
4608
|
let isProduction = false;
|
|
@@ -4608,11 +4666,18 @@ function createCjsToEsmPlugin() {
|
|
|
4608
4666
|
|
|
4609
4667
|
// src/vite/router-discovery.ts
|
|
4610
4668
|
import { createServer as createViteServer } from "vite";
|
|
4611
|
-
import { resolve as
|
|
4612
|
-
import { readFileSync as
|
|
4669
|
+
import { resolve as resolve11 } from "node:path";
|
|
4670
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
4613
4671
|
import { createRequire as createRequire3, register } from "node:module";
|
|
4614
4672
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
4615
4673
|
|
|
4674
|
+
// src/rsc/shell-serve.ts
|
|
4675
|
+
import React from "react";
|
|
4676
|
+
var DEV_SHELL_PROBE_TIMEOUT_MS = 1e4;
|
|
4677
|
+
function normalizeCaptureTimeout(value) {
|
|
4678
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 1 ? value : void 0;
|
|
4679
|
+
}
|
|
4680
|
+
|
|
4616
4681
|
// src/vite/inject-client-debug.ts
|
|
4617
4682
|
function isRouterInternalDebugId(id) {
|
|
4618
4683
|
if (!id.includes("internal-debug")) return false;
|
|
@@ -4773,6 +4838,9 @@ function walk(node, visit) {
|
|
|
4773
4838
|
}
|
|
4774
4839
|
}
|
|
4775
4840
|
|
|
4841
|
+
// src/vite/router-discovery.ts
|
|
4842
|
+
init_client_ref_hashing();
|
|
4843
|
+
|
|
4776
4844
|
// src/vite/utils/bundle-analysis.ts
|
|
4777
4845
|
function findMatchingParenInBundle(code, openParenPos) {
|
|
4778
4846
|
let depth = 1;
|
|
@@ -4877,6 +4945,9 @@ function createDiscoveryState(entryPath, opts) {
|
|
|
4877
4945
|
perRouterManifestDataMap: /* @__PURE__ */ new Map(),
|
|
4878
4946
|
prerenderManifestEntries: null,
|
|
4879
4947
|
staticManifestEntries: null,
|
|
4948
|
+
shellCandidates: null,
|
|
4949
|
+
prerenderPayloadValues: null,
|
|
4950
|
+
shellPhaseTempServer: null,
|
|
4880
4951
|
handlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
4881
4952
|
staticHandlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
4882
4953
|
rscEntryFileName: null,
|
|
@@ -5459,18 +5530,24 @@ function getStagedAssetDir(projectRoot) {
|
|
|
5459
5530
|
function resetStagedBuildAssets(projectRoot) {
|
|
5460
5531
|
rmSync(getStagedAssetDir(projectRoot), { recursive: true, force: true });
|
|
5461
5532
|
}
|
|
5462
|
-
function
|
|
5463
|
-
|
|
5464
|
-
mkdirSync(stagedDir, { recursive: true });
|
|
5533
|
+
function writeBuildAssetModule(dir, prefix, exportValue) {
|
|
5534
|
+
mkdirSync(dir, { recursive: true });
|
|
5465
5535
|
const contentHash = createHash4("sha256").update(exportValue).digest("hex").slice(0, 8);
|
|
5466
5536
|
const fileName = `${prefix}-${contentHash}.js`;
|
|
5467
|
-
const filePath = resolve7(
|
|
5537
|
+
const filePath = resolve7(dir, fileName);
|
|
5468
5538
|
if (!existsSync5(filePath)) {
|
|
5469
5539
|
writeFileSync2(filePath, `export default ${exportValue};
|
|
5470
5540
|
`);
|
|
5471
5541
|
}
|
|
5472
5542
|
return fileName;
|
|
5473
5543
|
}
|
|
5544
|
+
function stageBuildAssetModule(projectRoot, prefix, exportValue) {
|
|
5545
|
+
return writeBuildAssetModule(
|
|
5546
|
+
getStagedAssetDir(projectRoot),
|
|
5547
|
+
prefix,
|
|
5548
|
+
exportValue
|
|
5549
|
+
);
|
|
5550
|
+
}
|
|
5474
5551
|
function copyStagedBuildAssets(projectRoot, fileNames) {
|
|
5475
5552
|
const stagedDir = getStagedAssetDir(projectRoot);
|
|
5476
5553
|
const distAssetsDir = resolve7(projectRoot, "dist/rsc/assets");
|
|
@@ -5486,6 +5563,7 @@ function copyStagedBuildAssets(projectRoot, fileNames) {
|
|
|
5486
5563
|
}
|
|
5487
5564
|
|
|
5488
5565
|
// src/vite/discovery/prerender-collection.ts
|
|
5566
|
+
init_debug();
|
|
5489
5567
|
var debug9 = createRangoDebugger(NS.prerender);
|
|
5490
5568
|
async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
5491
5569
|
if (!state.opts?.enableBuildPrerender || !state.isBuildMode) return;
|
|
@@ -5693,6 +5771,18 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
5693
5771
|
"__pr",
|
|
5694
5772
|
mainValue
|
|
5695
5773
|
);
|
|
5774
|
+
if (result.ppr !== void 0 && result.ppr !== false) {
|
|
5775
|
+
(state.shellCandidates ??= []).push({
|
|
5776
|
+
urlPath: entry.urlPath,
|
|
5777
|
+
routeName: result.routeName,
|
|
5778
|
+
paramHash,
|
|
5779
|
+
ppr: result.ppr === true ? true : result.ppr
|
|
5780
|
+
});
|
|
5781
|
+
(state.prerenderPayloadValues ??= /* @__PURE__ */ new Map()).set(
|
|
5782
|
+
mainKey,
|
|
5783
|
+
mainValue
|
|
5784
|
+
);
|
|
5785
|
+
}
|
|
5696
5786
|
if (result.interceptSegments?.length) {
|
|
5697
5787
|
const interceptKey = `${result.routeName}/${paramHash}/i`;
|
|
5698
5788
|
const interceptValue = JSON.stringify({
|
|
@@ -5943,6 +6033,8 @@ function describeDiscoveryFailure(err, opts = {}) {
|
|
|
5943
6033
|
}
|
|
5944
6034
|
|
|
5945
6035
|
// src/vite/discovery/discover-routers.ts
|
|
6036
|
+
init_debug();
|
|
6037
|
+
init_client_ref_hashing();
|
|
5946
6038
|
var debug10 = createRangoDebugger(NS.discovery);
|
|
5947
6039
|
async function discoverRouters(state, rscEnv) {
|
|
5948
6040
|
if (!state.resolvedEntryPath) return;
|
|
@@ -6163,11 +6255,286 @@ async function discoverRouters(state, rscEnv) {
|
|
|
6163
6255
|
state.perRouterPrecomputedMap = newPerRouterPrecomputedMap;
|
|
6164
6256
|
state.perRouterTrieMap = newPerRouterTrieMap;
|
|
6165
6257
|
state.mergedRouteTrie = newMergedRouteTrie;
|
|
6258
|
+
if (serverMod.setRouteTrie && newMergedRouteTrie) {
|
|
6259
|
+
serverMod.setRouteTrie(newMergedRouteTrie);
|
|
6260
|
+
}
|
|
6261
|
+
const perRouterSetters = [
|
|
6262
|
+
[newPerRouterManifestDataMap, "setRouterManifest"],
|
|
6263
|
+
[newPerRouterTrieMap, "setRouterTrie"],
|
|
6264
|
+
[newPerRouterPrecomputedMap, "setRouterPrecomputedEntries"]
|
|
6265
|
+
];
|
|
6266
|
+
for (const [map, fn] of perRouterSetters) {
|
|
6267
|
+
const setter = serverMod[fn];
|
|
6268
|
+
if (typeof setter !== "function") continue;
|
|
6269
|
+
for (const [routerId, value] of map) setter(routerId, value);
|
|
6270
|
+
}
|
|
6166
6271
|
await expandPrerenderRoutes(state, rscEnv, registry, allManifests);
|
|
6167
6272
|
await renderStaticHandlers(state, rscEnv, registry);
|
|
6168
6273
|
return serverMod;
|
|
6169
6274
|
}
|
|
6170
6275
|
|
|
6276
|
+
// src/vite/discovery/shell-prerender-phase.ts
|
|
6277
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
6278
|
+
import { join as join4, resolve as resolve8 } from "node:path";
|
|
6279
|
+
|
|
6280
|
+
// src/prerender/shell-manifest-key.ts
|
|
6281
|
+
function buildShellManifestKey(pathname) {
|
|
6282
|
+
return pathname;
|
|
6283
|
+
}
|
|
6284
|
+
|
|
6285
|
+
// src/vite/discovery/shell-prerender-phase.ts
|
|
6286
|
+
init_debug();
|
|
6287
|
+
var debug11 = createRangoDebugger(NS.prerender);
|
|
6288
|
+
async function runShellPrerenderPhase(s, builder) {
|
|
6289
|
+
const tempServer = s.shellPhaseTempServer;
|
|
6290
|
+
if (!s.isBuildMode || !s.shellCandidates?.length || !tempServer) return;
|
|
6291
|
+
const candidates = s.shellCandidates;
|
|
6292
|
+
const startTotal = performance.now();
|
|
6293
|
+
console.log(`[rango] Shell-prerendering ${candidates.length} URL(s)...`);
|
|
6294
|
+
let restoreClientRequire;
|
|
6295
|
+
try {
|
|
6296
|
+
const rscEnv = tempServer.environments?.rsc;
|
|
6297
|
+
const ssrEnv = tempServer.environments?.ssr;
|
|
6298
|
+
if (!rscEnv?.runner || !ssrEnv?.runner) {
|
|
6299
|
+
console.warn(
|
|
6300
|
+
`[rango] shell prerender: temp server runners unavailable (rsc=${String(!!rscEnv?.runner)}, ssr=${String(!!ssrEnv?.runner)}); skipping \u2014 routes keep runtime shell capture.`
|
|
6301
|
+
);
|
|
6302
|
+
return;
|
|
6303
|
+
}
|
|
6304
|
+
const versionPlugin = (builder?.config?.plugins ?? []).find(
|
|
6305
|
+
(p) => p?.name === "@rangojs/router:version"
|
|
6306
|
+
);
|
|
6307
|
+
const buildVersion = versionPlugin?.api?.getBuildVersion?.();
|
|
6308
|
+
if (!buildVersion) {
|
|
6309
|
+
console.warn(
|
|
6310
|
+
"[rango] shell prerender: main build version unavailable; skipping \u2014 routes keep runtime shell capture."
|
|
6311
|
+
);
|
|
6312
|
+
return;
|
|
6313
|
+
}
|
|
6314
|
+
const payloads = s.prerenderPayloadValues ?? /* @__PURE__ */ new Map();
|
|
6315
|
+
const fetchedKeys = /* @__PURE__ */ new Set();
|
|
6316
|
+
globalThis.__loadPrerenderManifestModule = async () => ({
|
|
6317
|
+
default: Object.fromEntries([...payloads.keys()].map((k) => [k, k])),
|
|
6318
|
+
loadPrerenderAsset: async (spec) => {
|
|
6319
|
+
fetchedKeys.add(spec);
|
|
6320
|
+
return { default: JSON.parse(payloads.get(spec)) };
|
|
6321
|
+
}
|
|
6322
|
+
});
|
|
6323
|
+
const ssrRunner = ssrEnv.runner;
|
|
6324
|
+
const ssrPkg = await ssrRunner.import("@rangojs/router/ssr");
|
|
6325
|
+
const ssrDeps = await ssrRunner.import("@rangojs/router/internal/deps/ssr");
|
|
6326
|
+
const reactDomServer = await ssrRunner.import("react-dom/server.edge");
|
|
6327
|
+
const reactDomStatic = await ssrRunner.import("react-dom/static.edge");
|
|
6328
|
+
const htmlStream = await ssrRunner.import(
|
|
6329
|
+
"@rangojs/router/internal/deps/html-stream-server"
|
|
6330
|
+
);
|
|
6331
|
+
const clientOutDir = builder?.environments?.client?.config?.build?.outDir ?? resolve8(s.projectRoot, "dist/client");
|
|
6332
|
+
const clientAssetsDir = join4(clientOutDir, "assets");
|
|
6333
|
+
const entryFile = existsSync6(clientAssetsDir) ? readdirSync2(clientAssetsDir).find((f) => /^index-.*\.js$/.test(f)) : void 0;
|
|
6334
|
+
if (!entryFile) {
|
|
6335
|
+
console.warn(
|
|
6336
|
+
`[rango] shell prerender: built client entry not found under ${clientAssetsDir}; skipping \u2014 routes keep runtime shell capture.`
|
|
6337
|
+
);
|
|
6338
|
+
return;
|
|
6339
|
+
}
|
|
6340
|
+
const base = builder?.config?.base ?? "/";
|
|
6341
|
+
const normalizedBase = base.endsWith("/") ? base : `${base}/`;
|
|
6342
|
+
const bootstrapContent = `import("${normalizedBase}assets/${entryFile}")`;
|
|
6343
|
+
debug11?.("shell prerender bootstrap: %s", bootstrapContent);
|
|
6344
|
+
const minimalPlugin = (tempServer.config?.plugins ?? []).find(
|
|
6345
|
+
(p) => p?.name === "rsc:minimal"
|
|
6346
|
+
);
|
|
6347
|
+
const rscManager = minimalPlugin?.api?.manager;
|
|
6348
|
+
const { computeProductionHash: computeProductionHash2 } = await Promise.resolve().then(() => (init_client_ref_hashing(), client_ref_hashing_exports));
|
|
6349
|
+
let hashToDevKey = /* @__PURE__ */ new Map();
|
|
6350
|
+
const rebuildHashMap = () => {
|
|
6351
|
+
hashToDevKey = /* @__PURE__ */ new Map();
|
|
6352
|
+
const metaMap = rscManager?.clientReferenceMetaMap ?? {};
|
|
6353
|
+
for (const meta of Object.values(metaMap)) {
|
|
6354
|
+
hashToDevKey.set(
|
|
6355
|
+
computeProductionHash2(s.projectRoot, meta.referenceKey),
|
|
6356
|
+
meta.referenceKey
|
|
6357
|
+
);
|
|
6358
|
+
}
|
|
6359
|
+
};
|
|
6360
|
+
const origClientRequire = globalThis.__vite_rsc_client_require__;
|
|
6361
|
+
if (typeof origClientRequire === "function") {
|
|
6362
|
+
restoreClientRequire = () => {
|
|
6363
|
+
globalThis.__vite_rsc_client_require__ = origClientRequire;
|
|
6364
|
+
};
|
|
6365
|
+
globalThis.__vite_rsc_client_require__ = (id) => {
|
|
6366
|
+
const base2 = id.split("$$cache=")[0];
|
|
6367
|
+
let mapped = hashToDevKey.get(base2);
|
|
6368
|
+
if (mapped === void 0) {
|
|
6369
|
+
rebuildHashMap();
|
|
6370
|
+
mapped = hashToDevKey.get(base2);
|
|
6371
|
+
}
|
|
6372
|
+
return origClientRequire(mapped ?? id);
|
|
6373
|
+
};
|
|
6374
|
+
}
|
|
6375
|
+
const captureShellHTML = ssrPkg.createShellCaptureHandler({
|
|
6376
|
+
createFromReadableStream: ssrDeps.createFromReadableStream,
|
|
6377
|
+
renderToReadableStream: reactDomServer.renderToReadableStream ?? reactDomServer.default?.renderToReadableStream,
|
|
6378
|
+
resume: reactDomServer.resume ?? reactDomServer.default?.resume,
|
|
6379
|
+
prerender: reactDomStatic.prerender ?? reactDomStatic.default?.prerender,
|
|
6380
|
+
injectRSCPayload: htmlStream.injectRSCPayload,
|
|
6381
|
+
headScripts: "preinit",
|
|
6382
|
+
loadBootstrapScriptContent: async () => bootstrapContent
|
|
6383
|
+
});
|
|
6384
|
+
const rscRunner = rscEnv.runner;
|
|
6385
|
+
const captureMod = await rscRunner.import(
|
|
6386
|
+
"@rangojs/router/build/shell-capture"
|
|
6387
|
+
);
|
|
6388
|
+
const serverMod = await rscRunner.import("@rangojs/router/server");
|
|
6389
|
+
const registry = serverMod.RouterRegistry;
|
|
6390
|
+
const staged = [];
|
|
6391
|
+
let skipCount = 0;
|
|
6392
|
+
const pathCounts = /* @__PURE__ */ new Map();
|
|
6393
|
+
for (const cand of candidates) {
|
|
6394
|
+
pathCounts.set(cand.urlPath, (pathCounts.get(cand.urlPath) ?? 0) + 1);
|
|
6395
|
+
}
|
|
6396
|
+
for (const cand of candidates) {
|
|
6397
|
+
if ((pathCounts.get(cand.urlPath) ?? 0) > 1) {
|
|
6398
|
+
console.warn(
|
|
6399
|
+
`[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} - pathname claimed by multiple prerender routes; routes keep runtime capture`
|
|
6400
|
+
);
|
|
6401
|
+
skipCount++;
|
|
6402
|
+
continue;
|
|
6403
|
+
}
|
|
6404
|
+
const startUrl = performance.now();
|
|
6405
|
+
const policy = captureMod.resolveBuildPprConfig(cand.ppr);
|
|
6406
|
+
const mainKey = `${cand.routeName}/${cand.paramHash}`;
|
|
6407
|
+
let handled = false;
|
|
6408
|
+
const mismatches = [];
|
|
6409
|
+
for (const [, routerInstance] of registry) {
|
|
6410
|
+
if (typeof routerInstance.match !== "function") continue;
|
|
6411
|
+
try {
|
|
6412
|
+
const res = await captureMod.captureShellForBuild({
|
|
6413
|
+
router: routerInstance,
|
|
6414
|
+
urlPath: cand.urlPath,
|
|
6415
|
+
routeName: cand.routeName,
|
|
6416
|
+
key: `${cand.urlPath}:shell`,
|
|
6417
|
+
ttl: policy.ttl,
|
|
6418
|
+
swr: policy.swr,
|
|
6419
|
+
tags: policy.tags,
|
|
6420
|
+
maxSnapshotBytes: policy.maxSnapshotBytes,
|
|
6421
|
+
captureTimeout: policy.captureTimeout,
|
|
6422
|
+
buildEnv: s.resolvedBuildEnv,
|
|
6423
|
+
buildVersion,
|
|
6424
|
+
captureShellHTML,
|
|
6425
|
+
debug: !!debug11
|
|
6426
|
+
});
|
|
6427
|
+
if (res.outcome === "route-mismatch") {
|
|
6428
|
+
mismatches.push(res.matchedRouteName ?? "(no match)");
|
|
6429
|
+
continue;
|
|
6430
|
+
}
|
|
6431
|
+
handled = true;
|
|
6432
|
+
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
6433
|
+
if (res.outcome !== "stored" || !res.entry) {
|
|
6434
|
+
console.warn(
|
|
6435
|
+
`[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} (${elapsed}ms) - capture ${res.outcome}; route keeps runtime capture`
|
|
6436
|
+
);
|
|
6437
|
+
skipCount++;
|
|
6438
|
+
break;
|
|
6439
|
+
}
|
|
6440
|
+
if (!fetchedKeys.has(mainKey)) {
|
|
6441
|
+
console.warn(
|
|
6442
|
+
`[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} (${elapsed}ms) - capture did not replay the prerender store; route keeps runtime capture`
|
|
6443
|
+
);
|
|
6444
|
+
skipCount++;
|
|
6445
|
+
break;
|
|
6446
|
+
}
|
|
6447
|
+
const value = {
|
|
6448
|
+
entry: res.entry,
|
|
6449
|
+
ttl: policy.ttl,
|
|
6450
|
+
swr: policy.swr,
|
|
6451
|
+
tags: res.tags,
|
|
6452
|
+
routeName: cand.routeName
|
|
6453
|
+
};
|
|
6454
|
+
staged.push({
|
|
6455
|
+
key: buildShellManifestKey(cand.urlPath),
|
|
6456
|
+
value: JSON.stringify(value)
|
|
6457
|
+
});
|
|
6458
|
+
console.log(
|
|
6459
|
+
`[rango] SHELL OK ${cand.urlPath.padEnd(34)} (${elapsed}ms)`
|
|
6460
|
+
);
|
|
6461
|
+
break;
|
|
6462
|
+
} catch (err) {
|
|
6463
|
+
handled = true;
|
|
6464
|
+
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
6465
|
+
console.warn(
|
|
6466
|
+
`[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} (${elapsed}ms) - ${err?.message ?? err}; route keeps runtime capture`
|
|
6467
|
+
);
|
|
6468
|
+
skipCount++;
|
|
6469
|
+
break;
|
|
6470
|
+
}
|
|
6471
|
+
}
|
|
6472
|
+
if (!handled) {
|
|
6473
|
+
console.warn(
|
|
6474
|
+
`[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} - no router matched "${cand.routeName}"` + (mismatches.length > 0 ? ` (matched: ${mismatches.join(", ")})` : "") + "; route keeps runtime capture"
|
|
6475
|
+
);
|
|
6476
|
+
skipCount++;
|
|
6477
|
+
}
|
|
6478
|
+
}
|
|
6479
|
+
if (staged.length > 0) {
|
|
6480
|
+
const rscOutDir = builder?.environments?.rsc?.config?.build?.outDir ?? resolve8(s.projectRoot, "dist/rsc");
|
|
6481
|
+
writeShellManifest(s, rscOutDir, staged);
|
|
6482
|
+
}
|
|
6483
|
+
const totalElapsed = (performance.now() - startTotal).toFixed(0);
|
|
6484
|
+
const parts = [`${staged.length} done`];
|
|
6485
|
+
if (skipCount > 0) parts.push(`${skipCount} skipped`);
|
|
6486
|
+
console.log(
|
|
6487
|
+
`[rango] Shell prerender complete: ${parts.join(", ")} (${totalElapsed}ms total)`
|
|
6488
|
+
);
|
|
6489
|
+
} catch (err) {
|
|
6490
|
+
console.warn(
|
|
6491
|
+
`[rango] shell prerender phase failed: ${err?.message ?? err}; routes keep runtime shell capture.`
|
|
6492
|
+
);
|
|
6493
|
+
} finally {
|
|
6494
|
+
delete globalThis.__loadPrerenderManifestModule;
|
|
6495
|
+
restoreClientRequire?.();
|
|
6496
|
+
}
|
|
6497
|
+
}
|
|
6498
|
+
function writeShellManifest(s, rscOutDir, staged) {
|
|
6499
|
+
const rscEntryPath = resolve8(rscOutDir, s.rscEntryFileName ?? "index.js");
|
|
6500
|
+
if (!existsSync6(rscEntryPath)) {
|
|
6501
|
+
console.warn(
|
|
6502
|
+
`[rango] shell prerender: RSC entry not found at ${rscEntryPath}; entries not persisted \u2014 routes keep runtime capture.`
|
|
6503
|
+
);
|
|
6504
|
+
return;
|
|
6505
|
+
}
|
|
6506
|
+
const assetsDir = resolve8(rscOutDir, "assets");
|
|
6507
|
+
let totalBytes = 0;
|
|
6508
|
+
const manifestMap = {};
|
|
6509
|
+
const countedFiles = /* @__PURE__ */ new Set();
|
|
6510
|
+
for (const { key, value } of staged) {
|
|
6511
|
+
const fileName = writeBuildAssetModule(assetsDir, "__ps", value);
|
|
6512
|
+
if (!countedFiles.has(fileName)) {
|
|
6513
|
+
countedFiles.add(fileName);
|
|
6514
|
+
totalBytes += Buffer.byteLength(value) + "export default ;\n".length;
|
|
6515
|
+
}
|
|
6516
|
+
manifestMap[key] = `./assets/${fileName}`;
|
|
6517
|
+
}
|
|
6518
|
+
const manifestCode = [
|
|
6519
|
+
`const m=${jsonParseExpression(manifestMap)};`,
|
|
6520
|
+
`export function loadShellAsset(s){return import(s)}`,
|
|
6521
|
+
`export default m;`,
|
|
6522
|
+
""
|
|
6523
|
+
].join("\n");
|
|
6524
|
+
writeFileSync3(resolve8(rscOutDir, "__shell-manifest.js"), manifestCode);
|
|
6525
|
+
totalBytes += Buffer.byteLength(manifestCode);
|
|
6526
|
+
const rscCode = readFileSync4(rscEntryPath, "utf-8");
|
|
6527
|
+
if (!rscCode.includes("__shell-manifest.js")) {
|
|
6528
|
+
const injection = `globalThis.__loadShellManifestModule = () => import("./__shell-manifest.js");
|
|
6529
|
+
`;
|
|
6530
|
+
writeFileSync3(rscEntryPath, injection + rscCode);
|
|
6531
|
+
}
|
|
6532
|
+
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
6533
|
+
console.log(
|
|
6534
|
+
`[rango] Wrote shell assets (${totalKB} KB total, ${staged.length} entries)`
|
|
6535
|
+
);
|
|
6536
|
+
}
|
|
6537
|
+
|
|
6171
6538
|
// src/vite/discovery/dev-prerender-cache.ts
|
|
6172
6539
|
function payloadBodiesFromResult(result) {
|
|
6173
6540
|
const main = JSON.stringify({
|
|
@@ -6206,8 +6573,8 @@ function createDevPrerenderCache(maxEntriesPerRouter = MAX_ENTRIES_PER_ROUTER) {
|
|
|
6206
6573
|
}
|
|
6207
6574
|
|
|
6208
6575
|
// src/vite/discovery/route-types-writer.ts
|
|
6209
|
-
import { dirname as dirname3, join as
|
|
6210
|
-
import { readFileSync as
|
|
6576
|
+
import { dirname as dirname3, join as join5, resolve as resolve9 } from "node:path";
|
|
6577
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync7, unlinkSync as unlinkSync2 } from "node:fs";
|
|
6211
6578
|
function filterUserNamedRoutes(manifest) {
|
|
6212
6579
|
const filtered = {};
|
|
6213
6580
|
for (const [name, pattern] of Object.entries(manifest)) {
|
|
@@ -6218,10 +6585,10 @@ function filterUserNamedRoutes(manifest) {
|
|
|
6218
6585
|
return filtered;
|
|
6219
6586
|
}
|
|
6220
6587
|
function writeGenFileIfChanged(state, outPath, source, opts) {
|
|
6221
|
-
const existing =
|
|
6588
|
+
const existing = existsSync7(outPath) ? readFileSync5(outPath, "utf-8") : null;
|
|
6222
6589
|
if (existing === source) return;
|
|
6223
6590
|
markSelfGenWrite(state, outPath, source);
|
|
6224
|
-
|
|
6591
|
+
writeFileSync4(outPath, source);
|
|
6225
6592
|
if (opts?.log) console.log(`[rango] Generated route types -> ${outPath}`);
|
|
6226
6593
|
}
|
|
6227
6594
|
function writeCombinedRouteTypesWithTracking(state, opts) {
|
|
@@ -6236,10 +6603,10 @@ function writeRouteTypesFiles(state) {
|
|
|
6236
6603
|
if (state.perRouterManifests.length === 0) return;
|
|
6237
6604
|
try {
|
|
6238
6605
|
const entryDir = dirname3(
|
|
6239
|
-
|
|
6606
|
+
resolve9(state.projectRoot, state.resolvedEntryPath)
|
|
6240
6607
|
);
|
|
6241
|
-
const oldCombinedPath =
|
|
6242
|
-
if (
|
|
6608
|
+
const oldCombinedPath = join5(entryDir, "named-routes.gen.ts");
|
|
6609
|
+
if (existsSync7(oldCombinedPath)) {
|
|
6243
6610
|
unlinkSync2(oldCombinedPath);
|
|
6244
6611
|
console.log(
|
|
6245
6612
|
`[rango] Removed stale combined route types: ${oldCombinedPath}`
|
|
@@ -6320,7 +6687,7 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
6320
6687
|
}
|
|
6321
6688
|
|
|
6322
6689
|
// src/vite/discovery/virtual-module-codegen.ts
|
|
6323
|
-
import { dirname as dirname4, basename, join as
|
|
6690
|
+
import { dirname as dirname4, basename, join as join6 } from "node:path";
|
|
6324
6691
|
function generateRoutesManifestModule(state) {
|
|
6325
6692
|
const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
|
|
6326
6693
|
if (hasManifest) {
|
|
@@ -6335,7 +6702,7 @@ function generateRoutesManifestModule(state) {
|
|
|
6335
6702
|
/\.(tsx?|jsx?)$/,
|
|
6336
6703
|
""
|
|
6337
6704
|
);
|
|
6338
|
-
const genPath =
|
|
6705
|
+
const genPath = join6(
|
|
6339
6706
|
routerDir,
|
|
6340
6707
|
`${routerBasename}.named-routes.gen.js`
|
|
6341
6708
|
).replaceAll("\\", "/");
|
|
@@ -6420,7 +6787,7 @@ function generatePerRouterModule(state, routerId) {
|
|
|
6420
6787
|
/\.(tsx?|jsx?)$/,
|
|
6421
6788
|
""
|
|
6422
6789
|
);
|
|
6423
|
-
const genPath =
|
|
6790
|
+
const genPath = join6(
|
|
6424
6791
|
routerDir,
|
|
6425
6792
|
`${routerBasename}.named-routes.gen.js`
|
|
6426
6793
|
).replaceAll("\\", "/");
|
|
@@ -6447,13 +6814,13 @@ function generatePerRouterModule(state, routerId) {
|
|
|
6447
6814
|
}
|
|
6448
6815
|
|
|
6449
6816
|
// src/vite/discovery/bundle-postprocess.ts
|
|
6450
|
-
import { resolve as
|
|
6451
|
-
import { readFileSync as
|
|
6817
|
+
import { resolve as resolve10 } from "node:path";
|
|
6818
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync8 } from "node:fs";
|
|
6452
6819
|
function postprocessBundle(state) {
|
|
6453
6820
|
const hasPrerenderData = state.prerenderManifestEntries && Object.keys(state.prerenderManifestEntries).length > 0;
|
|
6454
6821
|
const hasStaticData = state.staticManifestEntries && Object.keys(state.staticManifestEntries).length > 0;
|
|
6455
6822
|
if (!hasPrerenderData && !hasStaticData) return;
|
|
6456
|
-
const rscEntryPath =
|
|
6823
|
+
const rscEntryPath = resolve10(
|
|
6457
6824
|
state.projectRoot,
|
|
6458
6825
|
"dist/rsc",
|
|
6459
6826
|
state.rscEntryFileName ?? "index.js"
|
|
@@ -6474,9 +6841,9 @@ function postprocessBundle(state) {
|
|
|
6474
6841
|
];
|
|
6475
6842
|
for (const target of evictionTargets) {
|
|
6476
6843
|
for (const info of target.infos) {
|
|
6477
|
-
const chunkPath =
|
|
6844
|
+
const chunkPath = resolve10(state.projectRoot, "dist/rsc", info.fileName);
|
|
6478
6845
|
try {
|
|
6479
|
-
const code =
|
|
6846
|
+
const code = readFileSync6(chunkPath, "utf-8");
|
|
6480
6847
|
const result = evictHandlerCode(
|
|
6481
6848
|
code,
|
|
6482
6849
|
info.exports,
|
|
@@ -6484,7 +6851,7 @@ function postprocessBundle(state) {
|
|
|
6484
6851
|
target.brand
|
|
6485
6852
|
);
|
|
6486
6853
|
if (result) {
|
|
6487
|
-
|
|
6854
|
+
writeFileSync5(chunkPath, result.code);
|
|
6488
6855
|
const savedKB = (result.savedBytes / 1024).toFixed(1);
|
|
6489
6856
|
console.log(
|
|
6490
6857
|
`[rango] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
|
|
@@ -6499,8 +6866,8 @@ function postprocessBundle(state) {
|
|
|
6499
6866
|
}
|
|
6500
6867
|
state.handlerChunkInfoMap.clear();
|
|
6501
6868
|
state.staticHandlerChunkInfoMap.clear();
|
|
6502
|
-
if (hasPrerenderData &&
|
|
6503
|
-
const rscCode =
|
|
6869
|
+
if (hasPrerenderData && existsSync8(rscEntryPath)) {
|
|
6870
|
+
const rscCode = readFileSync6(rscEntryPath, "utf-8");
|
|
6504
6871
|
if (!rscCode.includes("__prerender-manifest.js")) {
|
|
6505
6872
|
try {
|
|
6506
6873
|
let totalBytes = copyStagedBuildAssets(
|
|
@@ -6519,15 +6886,15 @@ function postprocessBundle(state) {
|
|
|
6519
6886
|
`export default m;`,
|
|
6520
6887
|
""
|
|
6521
6888
|
].join("\n");
|
|
6522
|
-
const manifestPath =
|
|
6889
|
+
const manifestPath = resolve10(
|
|
6523
6890
|
state.projectRoot,
|
|
6524
6891
|
"dist/rsc/__prerender-manifest.js"
|
|
6525
6892
|
);
|
|
6526
|
-
|
|
6893
|
+
writeFileSync5(manifestPath, manifestCode);
|
|
6527
6894
|
totalBytes += Buffer.byteLength(manifestCode);
|
|
6528
6895
|
const injection = `globalThis.__loadPrerenderManifestModule = () => import("./__prerender-manifest.js");
|
|
6529
6896
|
`;
|
|
6530
|
-
|
|
6897
|
+
writeFileSync5(rscEntryPath, injection + rscCode);
|
|
6531
6898
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
6532
6899
|
console.log(
|
|
6533
6900
|
`[rango] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.prerenderManifestEntries).length} entries)`
|
|
@@ -6539,8 +6906,8 @@ function postprocessBundle(state) {
|
|
|
6539
6906
|
}
|
|
6540
6907
|
}
|
|
6541
6908
|
}
|
|
6542
|
-
if (hasStaticData &&
|
|
6543
|
-
const rscCode =
|
|
6909
|
+
if (hasStaticData && existsSync8(rscEntryPath)) {
|
|
6910
|
+
const rscCode = readFileSync6(rscEntryPath, "utf-8");
|
|
6544
6911
|
if (!rscCode.includes("__static-manifest.js")) {
|
|
6545
6912
|
try {
|
|
6546
6913
|
const manifestEntries = [];
|
|
@@ -6557,15 +6924,15 @@ function postprocessBundle(state) {
|
|
|
6557
6924
|
}
|
|
6558
6925
|
const manifestCode = `const m={${manifestEntries.join(",")}};globalThis.__STATIC_MANIFEST=m;export default m;
|
|
6559
6926
|
`;
|
|
6560
|
-
const manifestPath =
|
|
6927
|
+
const manifestPath = resolve10(
|
|
6561
6928
|
state.projectRoot,
|
|
6562
6929
|
"dist/rsc/__static-manifest.js"
|
|
6563
6930
|
);
|
|
6564
|
-
|
|
6931
|
+
writeFileSync5(manifestPath, manifestCode);
|
|
6565
6932
|
totalBytes += Buffer.byteLength(manifestCode);
|
|
6566
6933
|
const injection = `import "./__static-manifest.js";
|
|
6567
6934
|
`;
|
|
6568
|
-
|
|
6935
|
+
writeFileSync5(rscEntryPath, injection + rscCode);
|
|
6569
6936
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
6570
6937
|
console.log(
|
|
6571
6938
|
`[rango] Wrote static assets (${totalKB} KB total, ${Object.keys(state.staticManifestEntries).length} entries)`
|
|
@@ -6580,7 +6947,7 @@ function postprocessBundle(state) {
|
|
|
6580
6947
|
}
|
|
6581
6948
|
|
|
6582
6949
|
// src/vite/discovery/gate-state.ts
|
|
6583
|
-
function createDiscoveryGate(s,
|
|
6950
|
+
function createDiscoveryGate(s, debug12) {
|
|
6584
6951
|
let gatePending = false;
|
|
6585
6952
|
let gateResolver = () => {
|
|
6586
6953
|
};
|
|
@@ -6589,15 +6956,15 @@ function createDiscoveryGate(s, debug11) {
|
|
|
6589
6956
|
let pendingEvents = false;
|
|
6590
6957
|
const beginGate = () => {
|
|
6591
6958
|
if (gatePending) return;
|
|
6592
|
-
s.discoveryDone = new Promise((
|
|
6593
|
-
gateResolver =
|
|
6959
|
+
s.discoveryDone = new Promise((resolve13) => {
|
|
6960
|
+
gateResolver = resolve13;
|
|
6594
6961
|
});
|
|
6595
6962
|
gatePending = true;
|
|
6596
6963
|
};
|
|
6597
6964
|
const resolveGate = () => {
|
|
6598
6965
|
if (!gatePending) return;
|
|
6599
6966
|
if (inProgress || queued || pendingEvents) {
|
|
6600
|
-
|
|
6967
|
+
debug12?.(
|
|
6601
6968
|
"hmr: resolveGate deferred \u2014 work in flight (inProgress=%s queued=%s pendingEvents=%s)",
|
|
6602
6969
|
inProgress,
|
|
6603
6970
|
queued,
|
|
@@ -6606,7 +6973,7 @@ function createDiscoveryGate(s, debug11) {
|
|
|
6606
6973
|
return;
|
|
6607
6974
|
}
|
|
6608
6975
|
gatePending = false;
|
|
6609
|
-
|
|
6976
|
+
debug12?.("hmr: discoveryDone resolved");
|
|
6610
6977
|
gateResolver();
|
|
6611
6978
|
};
|
|
6612
6979
|
const noteRouteEvent = () => {
|
|
@@ -6616,7 +6983,7 @@ function createDiscoveryGate(s, debug11) {
|
|
|
6616
6983
|
const runRefreshCycle = async (work) => {
|
|
6617
6984
|
if (inProgress) {
|
|
6618
6985
|
queued = true;
|
|
6619
|
-
|
|
6986
|
+
debug12?.("hmr: rediscovery in flight \u2014 queued for a follow-up cycle");
|
|
6620
6987
|
return;
|
|
6621
6988
|
}
|
|
6622
6989
|
pendingEvents = false;
|
|
@@ -6627,16 +6994,16 @@ function createDiscoveryGate(s, debug11) {
|
|
|
6627
6994
|
inProgress = false;
|
|
6628
6995
|
if (queued) {
|
|
6629
6996
|
queued = false;
|
|
6630
|
-
|
|
6997
|
+
debug12?.("hmr: consuming queued rediscovery");
|
|
6631
6998
|
runRefreshCycle(work).catch((err) => {
|
|
6632
|
-
|
|
6999
|
+
debug12?.(
|
|
6633
7000
|
"hmr: queued cycle rejected \u2014 releasing gate (%s)",
|
|
6634
7001
|
err instanceof Error ? err.message : String(err)
|
|
6635
7002
|
);
|
|
6636
7003
|
resolveGate();
|
|
6637
7004
|
});
|
|
6638
7005
|
} else if (pendingEvents) {
|
|
6639
|
-
|
|
7006
|
+
debug12?.(
|
|
6640
7007
|
"hmr: holding gate for pending events (debounce not yet fired)"
|
|
6641
7008
|
);
|
|
6642
7009
|
} else {
|
|
@@ -6682,15 +7049,15 @@ function selectForwardableResolvePlugins(plugins) {
|
|
|
6682
7049
|
}
|
|
6683
7050
|
function pickForwardedRunnerConfig(config) {
|
|
6684
7051
|
const r = config.resolve ?? {};
|
|
6685
|
-
const
|
|
6686
|
-
if (r.alias !== void 0)
|
|
6687
|
-
if (r.dedupe !== void 0)
|
|
6688
|
-
if (r.conditions !== void 0)
|
|
6689
|
-
if (r.mainFields !== void 0)
|
|
6690
|
-
if (r.extensions !== void 0)
|
|
7052
|
+
const resolve13 = {};
|
|
7053
|
+
if (r.alias !== void 0) resolve13.alias = r.alias;
|
|
7054
|
+
if (r.dedupe !== void 0) resolve13.dedupe = r.dedupe;
|
|
7055
|
+
if (r.conditions !== void 0) resolve13.conditions = r.conditions;
|
|
7056
|
+
if (r.mainFields !== void 0) resolve13.mainFields = r.mainFields;
|
|
7057
|
+
if (r.extensions !== void 0) resolve13.extensions = r.extensions;
|
|
6691
7058
|
if (r.preserveSymlinks !== void 0)
|
|
6692
|
-
|
|
6693
|
-
if (r.tsconfigPaths !== void 0)
|
|
7059
|
+
resolve13.preserveSymlinks = r.preserveSymlinks;
|
|
7060
|
+
if (r.tsconfigPaths !== void 0) resolve13.tsconfigPaths = r.tsconfigPaths;
|
|
6694
7061
|
const userOxc = config.oxc;
|
|
6695
7062
|
const userJsx = userOxc && typeof userOxc === "object" && typeof userOxc.jsx === "object" && userOxc.jsx !== null ? userOxc.jsx : {};
|
|
6696
7063
|
const oxc = userOxc && typeof userOxc === "object" ? {
|
|
@@ -6698,13 +7065,14 @@ function pickForwardedRunnerConfig(config) {
|
|
|
6698
7065
|
jsx: { ...userJsx, runtime: "automatic", importSource: "react" }
|
|
6699
7066
|
} : { jsx: { runtime: "automatic", importSource: "react" } };
|
|
6700
7067
|
return {
|
|
6701
|
-
resolve:
|
|
7068
|
+
resolve: resolve13,
|
|
6702
7069
|
define: config.define,
|
|
6703
7070
|
oxc
|
|
6704
7071
|
};
|
|
6705
7072
|
}
|
|
6706
7073
|
|
|
6707
7074
|
// src/vite/router-discovery.ts
|
|
7075
|
+
init_debug();
|
|
6708
7076
|
var debugDiscovery = createRangoDebugger(NS.discovery);
|
|
6709
7077
|
var debugRoutes = createRangoDebugger(NS.routes);
|
|
6710
7078
|
var debugBuild = createRangoDebugger(NS.build);
|
|
@@ -6754,6 +7122,20 @@ async function createTempRscServer(state, options = {}) {
|
|
|
6754
7122
|
// hashClientRefs only in build mode — production bundles need hashed refs
|
|
6755
7123
|
...options.forceBuild ? [hashClientRefs(state.projectRoot)] : [],
|
|
6756
7124
|
createVersionPlugin(),
|
|
7125
|
+
// Before the stub plugin, so "virtual:entry-ssr" resolves to the real
|
|
7126
|
+
// SSR entry when the shell endpoint needs it (see the option doc).
|
|
7127
|
+
...options.realSsrEntry ? [
|
|
7128
|
+
{
|
|
7129
|
+
name: "@rangojs/router:temp-real-ssr-entry",
|
|
7130
|
+
enforce: "pre",
|
|
7131
|
+
resolveId(id) {
|
|
7132
|
+
return id === "virtual:entry-ssr" ? "\0rango-temp-real-ssr-entry" : null;
|
|
7133
|
+
},
|
|
7134
|
+
load(id) {
|
|
7135
|
+
return id === "\0rango-temp-real-ssr-entry" ? getVirtualEntrySSR(state.opts?.headScripts) : null;
|
|
7136
|
+
}
|
|
7137
|
+
}
|
|
7138
|
+
] : [],
|
|
6757
7139
|
createVirtualStubPlugin(),
|
|
6758
7140
|
createCloudflareProtocolStubPlugin(),
|
|
6759
7141
|
// Dev prerender must use dev-mode IDs (path-based) to match the workerd
|
|
@@ -6777,7 +7159,7 @@ async function resolveBuildEnv(option, factoryCtx) {
|
|
|
6777
7159
|
}
|
|
6778
7160
|
try {
|
|
6779
7161
|
const userRequire = createRequire3(
|
|
6780
|
-
|
|
7162
|
+
resolve11(factoryCtx.root, "package.json")
|
|
6781
7163
|
);
|
|
6782
7164
|
const wranglerPath = userRequire.resolve("wrangler");
|
|
6783
7165
|
const { getPlatformProxy } = await import(pathToFileURL2(wranglerPath).href);
|
|
@@ -6814,6 +7196,12 @@ async function acquireBuildEnv(s, command, mode) {
|
|
|
6814
7196
|
globalThis[BUILD_ENV_GLOBAL_KEY] = result.env;
|
|
6815
7197
|
return true;
|
|
6816
7198
|
}
|
|
7199
|
+
function resetPrerenderCollection(s) {
|
|
7200
|
+
s.prerenderManifestEntries = null;
|
|
7201
|
+
s.staticManifestEntries = null;
|
|
7202
|
+
s.shellCandidates = null;
|
|
7203
|
+
s.prerenderPayloadValues = null;
|
|
7204
|
+
}
|
|
6817
7205
|
async function releaseBuildEnv(s) {
|
|
6818
7206
|
if (s.buildEnvDispose) {
|
|
6819
7207
|
try {
|
|
@@ -6878,8 +7266,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
6878
7266
|
s.devServer = server;
|
|
6879
7267
|
server.middlewares.use(internalDebugNoCacheMiddleware());
|
|
6880
7268
|
let resolveDiscovery;
|
|
6881
|
-
const discoveryPromise = new Promise((
|
|
6882
|
-
resolveDiscovery =
|
|
7269
|
+
const discoveryPromise = new Promise((resolve13) => {
|
|
7270
|
+
resolveDiscovery = resolve13;
|
|
6883
7271
|
});
|
|
6884
7272
|
const gate = createDiscoveryGate(s, debugDiscovery);
|
|
6885
7273
|
const beginDiscoveryGate = gate.beginGate;
|
|
@@ -6969,7 +7357,11 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
6969
7357
|
);
|
|
6970
7358
|
try {
|
|
6971
7359
|
prerenderTempServer = await createTempRscServer(s, {
|
|
6972
|
-
cacheDir: "node_modules/.vite_prerender"
|
|
7360
|
+
cacheDir: "node_modules/.vite_prerender",
|
|
7361
|
+
// The dev /__rsc_shell endpoint drives captureShellHTML in this
|
|
7362
|
+
// server's SSR realm; the entry is only imported when a shell
|
|
7363
|
+
// capture runs, so discovery cost is unchanged.
|
|
7364
|
+
realSsrEntry: true
|
|
6973
7365
|
});
|
|
6974
7366
|
const tempRscEnv = prerenderTempServer.environments?.rsc;
|
|
6975
7367
|
if (tempRscEnv?.runner) {
|
|
@@ -7301,6 +7693,162 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
7301
7693
|
res.end("No prerender match");
|
|
7302
7694
|
logResult(404, "no match");
|
|
7303
7695
|
});
|
|
7696
|
+
server.middlewares.use("/__rsc_shell", async (req, res) => {
|
|
7697
|
+
await s.discoveryDone;
|
|
7698
|
+
const url = new URL(req.url ?? "", "http://localhost");
|
|
7699
|
+
const pathname = url.searchParams.get("pathname");
|
|
7700
|
+
const routeName = url.searchParams.get("routeName");
|
|
7701
|
+
const version = url.searchParams.get("version");
|
|
7702
|
+
const ttlRaw = url.searchParams.get("ttl");
|
|
7703
|
+
if (!pathname || !routeName || !version || !ttlRaw) {
|
|
7704
|
+
res.statusCode = 400;
|
|
7705
|
+
res.end("Missing pathname/routeName/version/ttl");
|
|
7706
|
+
return;
|
|
7707
|
+
}
|
|
7708
|
+
const ttl = Number(ttlRaw);
|
|
7709
|
+
const swrRaw = url.searchParams.get("swr");
|
|
7710
|
+
const swr = swrRaw === null ? void 0 : Number(swrRaw);
|
|
7711
|
+
const tagsRaw = url.searchParams.get("tags");
|
|
7712
|
+
const tags = tagsRaw ? tagsRaw.split(",") : void 0;
|
|
7713
|
+
const maxSnapshotBytesRaw = url.searchParams.get("maxSnapshotBytes");
|
|
7714
|
+
const maxSnapshotBytes = maxSnapshotBytesRaw === null ? void 0 : Number(maxSnapshotBytesRaw);
|
|
7715
|
+
const captureTimeout = normalizeCaptureTimeout(
|
|
7716
|
+
Number(url.searchParams.get("captureTimeout"))
|
|
7717
|
+
);
|
|
7718
|
+
const rscEnvMain = server.environments?.rsc;
|
|
7719
|
+
let rscRealm = null;
|
|
7720
|
+
let ssrRealm = null;
|
|
7721
|
+
let ssrEntryId;
|
|
7722
|
+
if (rscEnvMain?.runner && s.resolvedEntryPath) {
|
|
7723
|
+
try {
|
|
7724
|
+
await rscEnvMain.runner.import(s.resolvedEntryPath);
|
|
7725
|
+
} catch (err) {
|
|
7726
|
+
res.statusCode = 500;
|
|
7727
|
+
res.end(`Shell capture module refresh failed: ${err.message}`);
|
|
7728
|
+
return;
|
|
7729
|
+
}
|
|
7730
|
+
rscRealm = rscEnvMain;
|
|
7731
|
+
ssrRealm = server.environments?.ssr;
|
|
7732
|
+
ssrEntryId = server.environments?.ssr?.config?.build?.rollupOptions?.input?.index ?? VIRTUAL_IDS.ssr;
|
|
7733
|
+
} else {
|
|
7734
|
+
const tempRscEnv = await getOrCreateTempServer();
|
|
7735
|
+
if (tempRscEnv) {
|
|
7736
|
+
try {
|
|
7737
|
+
await importEntryAndRegistry(tempRscEnv);
|
|
7738
|
+
} catch (err) {
|
|
7739
|
+
res.statusCode = 500;
|
|
7740
|
+
res.end(`Shell capture module refresh failed: ${err.message}`);
|
|
7741
|
+
return;
|
|
7742
|
+
}
|
|
7743
|
+
}
|
|
7744
|
+
rscRealm = tempRscEnv;
|
|
7745
|
+
ssrRealm = prerenderTempServer?.environments?.ssr;
|
|
7746
|
+
ssrEntryId = "virtual:entry-ssr";
|
|
7747
|
+
}
|
|
7748
|
+
if (!rscRealm?.runner || !ssrRealm?.runner) {
|
|
7749
|
+
res.statusCode = 503;
|
|
7750
|
+
res.end("Shell capture runners not available");
|
|
7751
|
+
return;
|
|
7752
|
+
}
|
|
7753
|
+
let registry = null;
|
|
7754
|
+
try {
|
|
7755
|
+
const serverMod = await rscRealm.runner.import(
|
|
7756
|
+
"@rangojs/router/server"
|
|
7757
|
+
);
|
|
7758
|
+
registry = serverMod.RouterRegistry ?? null;
|
|
7759
|
+
} catch {
|
|
7760
|
+
registry = null;
|
|
7761
|
+
}
|
|
7762
|
+
if (!registry || registry.size === 0) {
|
|
7763
|
+
res.statusCode = 503;
|
|
7764
|
+
res.end("Shell capture registry not available");
|
|
7765
|
+
return;
|
|
7766
|
+
}
|
|
7767
|
+
const cacheKey = `shell|${pathname}|r=${routeName}|t=${ttl}|s=${swr ?? ""}|g=${(tags ?? []).join("+")}|c=${captureTimeout ?? ""}|v=${version}`;
|
|
7768
|
+
for (const [, routerInstance] of registry) {
|
|
7769
|
+
if (typeof routerInstance.match !== "function") continue;
|
|
7770
|
+
const cached = devPrerenderCache.get(routerInstance, cacheKey);
|
|
7771
|
+
if (cached !== void 0) {
|
|
7772
|
+
res.setHeader("content-type", "application/json");
|
|
7773
|
+
res.setHeader("x-rango-shell-dev", "HIT");
|
|
7774
|
+
res.end(cached);
|
|
7775
|
+
return;
|
|
7776
|
+
}
|
|
7777
|
+
}
|
|
7778
|
+
if (s.devServerOrigin) {
|
|
7779
|
+
try {
|
|
7780
|
+
const probe = await fetch(
|
|
7781
|
+
`${s.devServerOrigin}/__rsc_prerender?pathname=${encodeURIComponent(pathname)}&routeName=${encodeURIComponent(routeName)}`,
|
|
7782
|
+
{ signal: AbortSignal.timeout(DEV_SHELL_PROBE_TIMEOUT_MS) }
|
|
7783
|
+
);
|
|
7784
|
+
if (!probe.ok) {
|
|
7785
|
+
res.statusCode = 404;
|
|
7786
|
+
res.end("Route is not prerenderable");
|
|
7787
|
+
return;
|
|
7788
|
+
}
|
|
7789
|
+
} catch {
|
|
7790
|
+
res.statusCode = 404;
|
|
7791
|
+
res.end("Prerender pre-flight failed");
|
|
7792
|
+
return;
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7795
|
+
for (const [, routerInstance] of registry) {
|
|
7796
|
+
if (typeof routerInstance.match !== "function") continue;
|
|
7797
|
+
try {
|
|
7798
|
+
const ssrModule = await ssrRealm.runner.import(ssrEntryId);
|
|
7799
|
+
if (typeof ssrModule?.captureShellHTML !== "function") {
|
|
7800
|
+
res.statusCode = 404;
|
|
7801
|
+
res.end("SSR entry has no captureShellHTML");
|
|
7802
|
+
return;
|
|
7803
|
+
}
|
|
7804
|
+
const captureMod = await rscRealm.runner.import(
|
|
7805
|
+
"@rangojs/router/build/shell-capture"
|
|
7806
|
+
);
|
|
7807
|
+
const result = await captureMod.captureShellForBuild({
|
|
7808
|
+
router: routerInstance,
|
|
7809
|
+
urlPath: pathname,
|
|
7810
|
+
routeName,
|
|
7811
|
+
key: `${pathname}:shell`,
|
|
7812
|
+
ttl,
|
|
7813
|
+
swr,
|
|
7814
|
+
tags,
|
|
7815
|
+
maxSnapshotBytes,
|
|
7816
|
+
captureTimeout,
|
|
7817
|
+
buildEnv: s.resolvedBuildEnv,
|
|
7818
|
+
buildVersion: version,
|
|
7819
|
+
captureShellHTML: ssrModule.captureShellHTML,
|
|
7820
|
+
debug: !!debugDiscovery
|
|
7821
|
+
});
|
|
7822
|
+
if (result.outcome === "route-mismatch") continue;
|
|
7823
|
+
if (result.outcome !== "stored" || !result.entry) {
|
|
7824
|
+
res.statusCode = 404;
|
|
7825
|
+
res.end(`Shell capture ${result.outcome}`);
|
|
7826
|
+
return;
|
|
7827
|
+
}
|
|
7828
|
+
const body = JSON.stringify({
|
|
7829
|
+
entry: result.entry,
|
|
7830
|
+
ttl,
|
|
7831
|
+
swr,
|
|
7832
|
+
tags: result.tags,
|
|
7833
|
+
routeName
|
|
7834
|
+
});
|
|
7835
|
+
devPrerenderCache.set(routerInstance, cacheKey, body);
|
|
7836
|
+
res.setHeader("content-type", "application/json");
|
|
7837
|
+
res.setHeader("x-rango-shell-dev", "MISS");
|
|
7838
|
+
res.end(body);
|
|
7839
|
+
return;
|
|
7840
|
+
} catch (err) {
|
|
7841
|
+
console.warn(
|
|
7842
|
+
`[rango] Dev shell capture error for ${pathname} (route keeps runtime capture): ${err.message}`
|
|
7843
|
+
);
|
|
7844
|
+
res.statusCode = 404;
|
|
7845
|
+
res.end(`Shell capture error: ${err.message}`);
|
|
7846
|
+
return;
|
|
7847
|
+
}
|
|
7848
|
+
}
|
|
7849
|
+
res.statusCode = 404;
|
|
7850
|
+
res.end("No router matched");
|
|
7851
|
+
});
|
|
7304
7852
|
if (opts?.staticRouteTypesGeneration !== false) {
|
|
7305
7853
|
const isGeneratedRouteFile = (filePath) => filePath.endsWith(".gen.ts") && (filePath.includes("named-routes.gen.ts") || filePath.includes("urls.gen.ts"));
|
|
7306
7854
|
const regenerateGeneratedRouteFiles = () => {
|
|
@@ -7470,7 +8018,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
7470
8018
|
}
|
|
7471
8019
|
const inRecoveryMode = !!s.lastDiscoveryError;
|
|
7472
8020
|
try {
|
|
7473
|
-
const source =
|
|
8021
|
+
const source = readFileSync7(filePath, "utf-8");
|
|
7474
8022
|
const trimmed = source.trimStart();
|
|
7475
8023
|
const isUseClient = trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'");
|
|
7476
8024
|
if (!inRecoveryMode && isUseClient) return;
|
|
@@ -7501,7 +8049,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
7501
8049
|
if (hasCreateRouter) {
|
|
7502
8050
|
const nestedRouterConflict = findNestedRouterConflict([
|
|
7503
8051
|
...s.cachedRouterFiles ?? [],
|
|
7504
|
-
|
|
8052
|
+
resolve11(filePath)
|
|
7505
8053
|
]);
|
|
7506
8054
|
if (nestedRouterConflict) {
|
|
7507
8055
|
server.config.logger.error(
|
|
@@ -7551,8 +8099,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
7551
8099
|
const buildStartTime = performance.now();
|
|
7552
8100
|
debugDiscovery?.("build: start (env=%s)", this.environment?.name ?? "?");
|
|
7553
8101
|
resetStagedBuildAssets(s.projectRoot);
|
|
7554
|
-
s
|
|
7555
|
-
s.staticManifestEntries = null;
|
|
8102
|
+
resetPrerenderCollection(s);
|
|
7556
8103
|
await timed(
|
|
7557
8104
|
debugDiscovery,
|
|
7558
8105
|
"build acquireBuildEnv",
|
|
@@ -7607,20 +8154,59 @@ ${details}`,
|
|
|
7607
8154
|
);
|
|
7608
8155
|
} finally {
|
|
7609
8156
|
delete globalThis.__rscRouterDiscoveryActive;
|
|
7610
|
-
if (tempServer) {
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
8157
|
+
if (tempServer && s.shellCandidates?.length) {
|
|
8158
|
+
s.shellPhaseTempServer = tempServer;
|
|
8159
|
+
} else {
|
|
8160
|
+
if (tempServer) {
|
|
8161
|
+
await timed(
|
|
8162
|
+
debugDiscovery,
|
|
8163
|
+
"build tempServer.close",
|
|
8164
|
+
() => tempServer.close()
|
|
8165
|
+
);
|
|
8166
|
+
}
|
|
8167
|
+
await releaseBuildEnv(s);
|
|
7616
8168
|
}
|
|
7617
|
-
await releaseBuildEnv(s);
|
|
7618
8169
|
debugDiscovery?.(
|
|
7619
8170
|
"build discovery done (%sms)",
|
|
7620
8171
|
(performance.now() - buildStartTime).toFixed(1)
|
|
7621
8172
|
);
|
|
7622
8173
|
}
|
|
7623
8174
|
},
|
|
8175
|
+
// Post-build PPR shell capture (producer B, #699): runs after EVERY
|
|
8176
|
+
// environment bundle is written — the shell prelude embeds built client
|
|
8177
|
+
// asset URLs (bootstrap entry), which do not exist at buildStart. The
|
|
8178
|
+
// kept temp server and the buildEnv were deferred AS A PAIR in
|
|
8179
|
+
// buildStart's finally; this finally is the pair's success-path owner
|
|
8180
|
+
// (buildEnd below owns the aborted-build path) — the phase itself is a
|
|
8181
|
+
// pure producer and tears down only the globals it installs.
|
|
8182
|
+
buildApp: {
|
|
8183
|
+
order: "post",
|
|
8184
|
+
async handler(builder) {
|
|
8185
|
+
try {
|
|
8186
|
+
await runShellPrerenderPhase(s, builder);
|
|
8187
|
+
} finally {
|
|
8188
|
+
if (s.isBuildMode) {
|
|
8189
|
+
const tempServer = s.shellPhaseTempServer;
|
|
8190
|
+
s.shellPhaseTempServer = null;
|
|
8191
|
+
if (tempServer) await tempServer.close();
|
|
8192
|
+
await releaseBuildEnv(s);
|
|
8193
|
+
}
|
|
8194
|
+
}
|
|
8195
|
+
}
|
|
8196
|
+
},
|
|
8197
|
+
// An environment build failure aborts the builder before the buildApp
|
|
8198
|
+
// post hook — never leak the kept temp server (open handles hang the CLI)
|
|
8199
|
+
// or the deferred buildEnv (a live miniflare proxy).
|
|
8200
|
+
async buildEnd(error) {
|
|
8201
|
+
if (!error || !s.shellPhaseTempServer) return;
|
|
8202
|
+
const tempServer = s.shellPhaseTempServer;
|
|
8203
|
+
s.shellPhaseTempServer = null;
|
|
8204
|
+
try {
|
|
8205
|
+
await tempServer.close();
|
|
8206
|
+
} finally {
|
|
8207
|
+
await releaseBuildEnv(s);
|
|
8208
|
+
}
|
|
8209
|
+
},
|
|
7624
8210
|
// Suppress vite's HMR cascade for our own gen-file writes.
|
|
7625
8211
|
//
|
|
7626
8212
|
// After every cf HMR cycle, refreshTempRscEnv → writeRouteTypesFiles
|
|
@@ -7785,6 +8371,7 @@ ${details}`,
|
|
|
7785
8371
|
}
|
|
7786
8372
|
|
|
7787
8373
|
// src/vite/rango.ts
|
|
8374
|
+
init_debug();
|
|
7788
8375
|
var debugConfig = createRangoDebugger(NS.config);
|
|
7789
8376
|
async function rango(options) {
|
|
7790
8377
|
const rangoStart = performance.now();
|
|
@@ -7929,14 +8516,14 @@ async function rango(options) {
|
|
|
7929
8516
|
name: "@rangojs/router:auto-discover",
|
|
7930
8517
|
config(userConfig) {
|
|
7931
8518
|
if (routerRef.path) return;
|
|
7932
|
-
const root = userConfig.root ?
|
|
8519
|
+
const root = userConfig.root ? resolve12(process.cwd(), userConfig.root) : process.cwd();
|
|
7933
8520
|
const toRootRelative = (abs) => (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
|
|
7934
8521
|
const bulletList = (files) => files.map((f) => " - " + toRootRelative(f)).join("\n");
|
|
7935
8522
|
if (explicitHostRouter) {
|
|
7936
8523
|
routerRef.path = normalizeHostRouterEntry(
|
|
7937
8524
|
explicitHostRouter,
|
|
7938
8525
|
root,
|
|
7939
|
-
|
|
8526
|
+
existsSync9
|
|
7940
8527
|
);
|
|
7941
8528
|
routerRef.kind = "host";
|
|
7942
8529
|
return;
|
|
@@ -8117,7 +8704,7 @@ If this is a multi-app host router, export a createHostRouter() instance and set
|
|
|
8117
8704
|
if (!file.endsWith(".tsx") && !file.endsWith(".ts") && !file.endsWith(".jsx") && !file.endsWith(".js"))
|
|
8118
8705
|
return;
|
|
8119
8706
|
try {
|
|
8120
|
-
const source =
|
|
8707
|
+
const source = readFileSync8(file, "utf-8");
|
|
8121
8708
|
if (hasUseClientDirective(source)) {
|
|
8122
8709
|
return [];
|
|
8123
8710
|
}
|
|
@@ -8144,7 +8731,8 @@ If this is a multi-app host router, export a createHostRouter() instance and set
|
|
|
8144
8731
|
preset,
|
|
8145
8732
|
prerenderOnError: options?.prerender?.onError,
|
|
8146
8733
|
discovery: options?.discovery,
|
|
8147
|
-
clientChunkCtx
|
|
8734
|
+
clientChunkCtx,
|
|
8735
|
+
headScripts: resolvedOptions.headScripts
|
|
8148
8736
|
})
|
|
8149
8737
|
);
|
|
8150
8738
|
if (preset === "vercel") {
|
|
@@ -8168,7 +8756,7 @@ function poke() {
|
|
|
8168
8756
|
apply: "serve",
|
|
8169
8757
|
configureServer(server) {
|
|
8170
8758
|
const stdin = process.stdin;
|
|
8171
|
-
const
|
|
8759
|
+
const debug12 = process.env.RANGO_POKE_DEBUG === "1";
|
|
8172
8760
|
const triggerReload = (source) => {
|
|
8173
8761
|
server.hot.send({ type: "full-reload", path: "*" });
|
|
8174
8762
|
server.config.logger.info(` browser reload (${source})`, {
|
|
@@ -8201,7 +8789,7 @@ function poke() {
|
|
|
8201
8789
|
lines.pop();
|
|
8202
8790
|
return lines;
|
|
8203
8791
|
};
|
|
8204
|
-
if (
|
|
8792
|
+
if (debug12) {
|
|
8205
8793
|
server.config.logger.info(
|
|
8206
8794
|
` poke debug enabled (isTTY=${stdin.isTTY ? "yes" : "no"}, isRaw=${stdin.isTTY ? stdin.isRaw ? "yes" : "no" : "n/a"})`,
|
|
8207
8795
|
{ timestamp: true }
|
|
@@ -8214,7 +8802,7 @@ function poke() {
|
|
|
8214
8802
|
);
|
|
8215
8803
|
}
|
|
8216
8804
|
const onData = (data) => {
|
|
8217
|
-
if (
|
|
8805
|
+
if (debug12) {
|
|
8218
8806
|
server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
|
|
8219
8807
|
timestamp: true
|
|
8220
8808
|
});
|