@rangojs/router 0.0.0-experimental.146 → 0.0.0-experimental.147
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 +807 -235
- package/package.json +6 -1
- 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 +23 -0
- 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/prerender/build-shell-capture.ts +237 -0
- package/src/prerender/shell-manifest-key.ts +20 -0
- package/src/prerender/store.ts +10 -1
- package/src/router/match-middleware/cache-lookup.ts +12 -1
- package/src/router/prerender-match.ts +21 -0
- package/src/rsc/capture-queue.ts +67 -0
- package/src/rsc/rsc-rendering.ts +82 -23
- package/src/rsc/shell-build-manifest.ts +244 -0
- package/src/rsc/shell-capture.ts +100 -39
- package/src/segment-fragments.ts +124 -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/vite/discovery/discover-routers.ts +27 -0
- package/src/vite/discovery/prerender-collection.ts +16 -0
- package/src/vite/discovery/shell-prerender-phase.ts +395 -0
- package/src/vite/discovery/state.ts +42 -0
- package/src/vite/plugins/version-plugin.ts +8 -0
- package/src/vite/rango.ts +1 -0
- package/src/vite/router-discovery.ts +292 -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.147",
|
|
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,8 +4666,8 @@ 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
|
|
|
@@ -4773,6 +4831,9 @@ function walk(node, visit) {
|
|
|
4773
4831
|
}
|
|
4774
4832
|
}
|
|
4775
4833
|
|
|
4834
|
+
// src/vite/router-discovery.ts
|
|
4835
|
+
init_client_ref_hashing();
|
|
4836
|
+
|
|
4776
4837
|
// src/vite/utils/bundle-analysis.ts
|
|
4777
4838
|
function findMatchingParenInBundle(code, openParenPos) {
|
|
4778
4839
|
let depth = 1;
|
|
@@ -4877,6 +4938,9 @@ function createDiscoveryState(entryPath, opts) {
|
|
|
4877
4938
|
perRouterManifestDataMap: /* @__PURE__ */ new Map(),
|
|
4878
4939
|
prerenderManifestEntries: null,
|
|
4879
4940
|
staticManifestEntries: null,
|
|
4941
|
+
shellCandidates: null,
|
|
4942
|
+
prerenderPayloadValues: null,
|
|
4943
|
+
shellPhaseTempServer: null,
|
|
4880
4944
|
handlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
4881
4945
|
staticHandlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
4882
4946
|
rscEntryFileName: null,
|
|
@@ -5459,18 +5523,24 @@ function getStagedAssetDir(projectRoot) {
|
|
|
5459
5523
|
function resetStagedBuildAssets(projectRoot) {
|
|
5460
5524
|
rmSync(getStagedAssetDir(projectRoot), { recursive: true, force: true });
|
|
5461
5525
|
}
|
|
5462
|
-
function
|
|
5463
|
-
|
|
5464
|
-
mkdirSync(stagedDir, { recursive: true });
|
|
5526
|
+
function writeBuildAssetModule(dir, prefix, exportValue) {
|
|
5527
|
+
mkdirSync(dir, { recursive: true });
|
|
5465
5528
|
const contentHash = createHash4("sha256").update(exportValue).digest("hex").slice(0, 8);
|
|
5466
5529
|
const fileName = `${prefix}-${contentHash}.js`;
|
|
5467
|
-
const filePath = resolve7(
|
|
5530
|
+
const filePath = resolve7(dir, fileName);
|
|
5468
5531
|
if (!existsSync5(filePath)) {
|
|
5469
5532
|
writeFileSync2(filePath, `export default ${exportValue};
|
|
5470
5533
|
`);
|
|
5471
5534
|
}
|
|
5472
5535
|
return fileName;
|
|
5473
5536
|
}
|
|
5537
|
+
function stageBuildAssetModule(projectRoot, prefix, exportValue) {
|
|
5538
|
+
return writeBuildAssetModule(
|
|
5539
|
+
getStagedAssetDir(projectRoot),
|
|
5540
|
+
prefix,
|
|
5541
|
+
exportValue
|
|
5542
|
+
);
|
|
5543
|
+
}
|
|
5474
5544
|
function copyStagedBuildAssets(projectRoot, fileNames) {
|
|
5475
5545
|
const stagedDir = getStagedAssetDir(projectRoot);
|
|
5476
5546
|
const distAssetsDir = resolve7(projectRoot, "dist/rsc/assets");
|
|
@@ -5486,6 +5556,7 @@ function copyStagedBuildAssets(projectRoot, fileNames) {
|
|
|
5486
5556
|
}
|
|
5487
5557
|
|
|
5488
5558
|
// src/vite/discovery/prerender-collection.ts
|
|
5559
|
+
init_debug();
|
|
5489
5560
|
var debug9 = createRangoDebugger(NS.prerender);
|
|
5490
5561
|
async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
5491
5562
|
if (!state.opts?.enableBuildPrerender || !state.isBuildMode) return;
|
|
@@ -5693,6 +5764,18 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
5693
5764
|
"__pr",
|
|
5694
5765
|
mainValue
|
|
5695
5766
|
);
|
|
5767
|
+
if (result.ppr !== void 0 && result.ppr !== false) {
|
|
5768
|
+
(state.shellCandidates ??= []).push({
|
|
5769
|
+
urlPath: entry.urlPath,
|
|
5770
|
+
routeName: result.routeName,
|
|
5771
|
+
paramHash,
|
|
5772
|
+
ppr: result.ppr === true ? true : result.ppr
|
|
5773
|
+
});
|
|
5774
|
+
(state.prerenderPayloadValues ??= /* @__PURE__ */ new Map()).set(
|
|
5775
|
+
mainKey,
|
|
5776
|
+
mainValue
|
|
5777
|
+
);
|
|
5778
|
+
}
|
|
5696
5779
|
if (result.interceptSegments?.length) {
|
|
5697
5780
|
const interceptKey = `${result.routeName}/${paramHash}/i`;
|
|
5698
5781
|
const interceptValue = JSON.stringify({
|
|
@@ -5943,6 +6026,8 @@ function describeDiscoveryFailure(err, opts = {}) {
|
|
|
5943
6026
|
}
|
|
5944
6027
|
|
|
5945
6028
|
// src/vite/discovery/discover-routers.ts
|
|
6029
|
+
init_debug();
|
|
6030
|
+
init_client_ref_hashing();
|
|
5946
6031
|
var debug10 = createRangoDebugger(NS.discovery);
|
|
5947
6032
|
async function discoverRouters(state, rscEnv) {
|
|
5948
6033
|
if (!state.resolvedEntryPath) return;
|
|
@@ -6163,11 +6248,284 @@ async function discoverRouters(state, rscEnv) {
|
|
|
6163
6248
|
state.perRouterPrecomputedMap = newPerRouterPrecomputedMap;
|
|
6164
6249
|
state.perRouterTrieMap = newPerRouterTrieMap;
|
|
6165
6250
|
state.mergedRouteTrie = newMergedRouteTrie;
|
|
6251
|
+
if (serverMod.setRouteTrie && newMergedRouteTrie) {
|
|
6252
|
+
serverMod.setRouteTrie(newMergedRouteTrie);
|
|
6253
|
+
}
|
|
6254
|
+
const perRouterSetters = [
|
|
6255
|
+
[newPerRouterManifestDataMap, "setRouterManifest"],
|
|
6256
|
+
[newPerRouterTrieMap, "setRouterTrie"],
|
|
6257
|
+
[newPerRouterPrecomputedMap, "setRouterPrecomputedEntries"]
|
|
6258
|
+
];
|
|
6259
|
+
for (const [map, fn] of perRouterSetters) {
|
|
6260
|
+
const setter = serverMod[fn];
|
|
6261
|
+
if (typeof setter !== "function") continue;
|
|
6262
|
+
for (const [routerId, value] of map) setter(routerId, value);
|
|
6263
|
+
}
|
|
6166
6264
|
await expandPrerenderRoutes(state, rscEnv, registry, allManifests);
|
|
6167
6265
|
await renderStaticHandlers(state, rscEnv, registry);
|
|
6168
6266
|
return serverMod;
|
|
6169
6267
|
}
|
|
6170
6268
|
|
|
6269
|
+
// src/vite/discovery/shell-prerender-phase.ts
|
|
6270
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
6271
|
+
import { join as join4, resolve as resolve8 } from "node:path";
|
|
6272
|
+
|
|
6273
|
+
// src/prerender/shell-manifest-key.ts
|
|
6274
|
+
function buildShellManifestKey(pathname) {
|
|
6275
|
+
return pathname;
|
|
6276
|
+
}
|
|
6277
|
+
|
|
6278
|
+
// src/vite/discovery/shell-prerender-phase.ts
|
|
6279
|
+
init_debug();
|
|
6280
|
+
var debug11 = createRangoDebugger(NS.prerender);
|
|
6281
|
+
async function runShellPrerenderPhase(s, builder) {
|
|
6282
|
+
const tempServer = s.shellPhaseTempServer;
|
|
6283
|
+
if (!s.isBuildMode || !s.shellCandidates?.length || !tempServer) return;
|
|
6284
|
+
const candidates = s.shellCandidates;
|
|
6285
|
+
const startTotal = performance.now();
|
|
6286
|
+
console.log(`[rango] Shell-prerendering ${candidates.length} URL(s)...`);
|
|
6287
|
+
let restoreClientRequire;
|
|
6288
|
+
try {
|
|
6289
|
+
const rscEnv = tempServer.environments?.rsc;
|
|
6290
|
+
const ssrEnv = tempServer.environments?.ssr;
|
|
6291
|
+
if (!rscEnv?.runner || !ssrEnv?.runner) {
|
|
6292
|
+
console.warn(
|
|
6293
|
+
`[rango] shell prerender: temp server runners unavailable (rsc=${String(!!rscEnv?.runner)}, ssr=${String(!!ssrEnv?.runner)}); skipping \u2014 routes keep runtime shell capture.`
|
|
6294
|
+
);
|
|
6295
|
+
return;
|
|
6296
|
+
}
|
|
6297
|
+
const versionPlugin = (builder?.config?.plugins ?? []).find(
|
|
6298
|
+
(p) => p?.name === "@rangojs/router:version"
|
|
6299
|
+
);
|
|
6300
|
+
const buildVersion = versionPlugin?.api?.getBuildVersion?.();
|
|
6301
|
+
if (!buildVersion) {
|
|
6302
|
+
console.warn(
|
|
6303
|
+
"[rango] shell prerender: main build version unavailable; skipping \u2014 routes keep runtime shell capture."
|
|
6304
|
+
);
|
|
6305
|
+
return;
|
|
6306
|
+
}
|
|
6307
|
+
const payloads = s.prerenderPayloadValues ?? /* @__PURE__ */ new Map();
|
|
6308
|
+
const fetchedKeys = /* @__PURE__ */ new Set();
|
|
6309
|
+
globalThis.__loadPrerenderManifestModule = async () => ({
|
|
6310
|
+
default: Object.fromEntries([...payloads.keys()].map((k) => [k, k])),
|
|
6311
|
+
loadPrerenderAsset: async (spec) => {
|
|
6312
|
+
fetchedKeys.add(spec);
|
|
6313
|
+
return { default: JSON.parse(payloads.get(spec)) };
|
|
6314
|
+
}
|
|
6315
|
+
});
|
|
6316
|
+
const ssrRunner = ssrEnv.runner;
|
|
6317
|
+
const ssrPkg = await ssrRunner.import("@rangojs/router/ssr");
|
|
6318
|
+
const ssrDeps = await ssrRunner.import("@rangojs/router/internal/deps/ssr");
|
|
6319
|
+
const reactDomServer = await ssrRunner.import("react-dom/server.edge");
|
|
6320
|
+
const reactDomStatic = await ssrRunner.import("react-dom/static.edge");
|
|
6321
|
+
const htmlStream = await ssrRunner.import(
|
|
6322
|
+
"@rangojs/router/internal/deps/html-stream-server"
|
|
6323
|
+
);
|
|
6324
|
+
const clientOutDir = builder?.environments?.client?.config?.build?.outDir ?? resolve8(s.projectRoot, "dist/client");
|
|
6325
|
+
const clientAssetsDir = join4(clientOutDir, "assets");
|
|
6326
|
+
const entryFile = existsSync6(clientAssetsDir) ? readdirSync2(clientAssetsDir).find((f) => /^index-.*\.js$/.test(f)) : void 0;
|
|
6327
|
+
if (!entryFile) {
|
|
6328
|
+
console.warn(
|
|
6329
|
+
`[rango] shell prerender: built client entry not found under ${clientAssetsDir}; skipping \u2014 routes keep runtime shell capture.`
|
|
6330
|
+
);
|
|
6331
|
+
return;
|
|
6332
|
+
}
|
|
6333
|
+
const base = builder?.config?.base ?? "/";
|
|
6334
|
+
const normalizedBase = base.endsWith("/") ? base : `${base}/`;
|
|
6335
|
+
const bootstrapContent = `import("${normalizedBase}assets/${entryFile}")`;
|
|
6336
|
+
debug11?.("shell prerender bootstrap: %s", bootstrapContent);
|
|
6337
|
+
const minimalPlugin = (tempServer.config?.plugins ?? []).find(
|
|
6338
|
+
(p) => p?.name === "rsc:minimal"
|
|
6339
|
+
);
|
|
6340
|
+
const rscManager = minimalPlugin?.api?.manager;
|
|
6341
|
+
const { computeProductionHash: computeProductionHash2 } = await Promise.resolve().then(() => (init_client_ref_hashing(), client_ref_hashing_exports));
|
|
6342
|
+
let hashToDevKey = /* @__PURE__ */ new Map();
|
|
6343
|
+
const rebuildHashMap = () => {
|
|
6344
|
+
hashToDevKey = /* @__PURE__ */ new Map();
|
|
6345
|
+
const metaMap = rscManager?.clientReferenceMetaMap ?? {};
|
|
6346
|
+
for (const meta of Object.values(metaMap)) {
|
|
6347
|
+
hashToDevKey.set(
|
|
6348
|
+
computeProductionHash2(s.projectRoot, meta.referenceKey),
|
|
6349
|
+
meta.referenceKey
|
|
6350
|
+
);
|
|
6351
|
+
}
|
|
6352
|
+
};
|
|
6353
|
+
const origClientRequire = globalThis.__vite_rsc_client_require__;
|
|
6354
|
+
if (typeof origClientRequire === "function") {
|
|
6355
|
+
restoreClientRequire = () => {
|
|
6356
|
+
globalThis.__vite_rsc_client_require__ = origClientRequire;
|
|
6357
|
+
};
|
|
6358
|
+
globalThis.__vite_rsc_client_require__ = (id) => {
|
|
6359
|
+
const base2 = id.split("$$cache=")[0];
|
|
6360
|
+
let mapped = hashToDevKey.get(base2);
|
|
6361
|
+
if (mapped === void 0) {
|
|
6362
|
+
rebuildHashMap();
|
|
6363
|
+
mapped = hashToDevKey.get(base2);
|
|
6364
|
+
}
|
|
6365
|
+
return origClientRequire(mapped ?? id);
|
|
6366
|
+
};
|
|
6367
|
+
}
|
|
6368
|
+
const captureShellHTML = ssrPkg.createShellCaptureHandler({
|
|
6369
|
+
createFromReadableStream: ssrDeps.createFromReadableStream,
|
|
6370
|
+
renderToReadableStream: reactDomServer.renderToReadableStream ?? reactDomServer.default?.renderToReadableStream,
|
|
6371
|
+
resume: reactDomServer.resume ?? reactDomServer.default?.resume,
|
|
6372
|
+
prerender: reactDomStatic.prerender ?? reactDomStatic.default?.prerender,
|
|
6373
|
+
injectRSCPayload: htmlStream.injectRSCPayload,
|
|
6374
|
+
headScripts: "preinit",
|
|
6375
|
+
loadBootstrapScriptContent: async () => bootstrapContent
|
|
6376
|
+
});
|
|
6377
|
+
const rscRunner = rscEnv.runner;
|
|
6378
|
+
const captureMod = await rscRunner.import(
|
|
6379
|
+
"@rangojs/router/build/shell-capture"
|
|
6380
|
+
);
|
|
6381
|
+
const serverMod = await rscRunner.import("@rangojs/router/server");
|
|
6382
|
+
const registry = serverMod.RouterRegistry;
|
|
6383
|
+
const staged = [];
|
|
6384
|
+
let skipCount = 0;
|
|
6385
|
+
const pathCounts = /* @__PURE__ */ new Map();
|
|
6386
|
+
for (const cand of candidates) {
|
|
6387
|
+
pathCounts.set(cand.urlPath, (pathCounts.get(cand.urlPath) ?? 0) + 1);
|
|
6388
|
+
}
|
|
6389
|
+
for (const cand of candidates) {
|
|
6390
|
+
if ((pathCounts.get(cand.urlPath) ?? 0) > 1) {
|
|
6391
|
+
console.warn(
|
|
6392
|
+
`[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} - pathname claimed by multiple prerender routes; routes keep runtime capture`
|
|
6393
|
+
);
|
|
6394
|
+
skipCount++;
|
|
6395
|
+
continue;
|
|
6396
|
+
}
|
|
6397
|
+
const startUrl = performance.now();
|
|
6398
|
+
const policy = captureMod.resolveBuildPprConfig(cand.ppr);
|
|
6399
|
+
const mainKey = `${cand.routeName}/${cand.paramHash}`;
|
|
6400
|
+
let handled = false;
|
|
6401
|
+
const mismatches = [];
|
|
6402
|
+
for (const [, routerInstance] of registry) {
|
|
6403
|
+
if (typeof routerInstance.match !== "function") continue;
|
|
6404
|
+
try {
|
|
6405
|
+
const res = await captureMod.captureShellForBuild({
|
|
6406
|
+
router: routerInstance,
|
|
6407
|
+
urlPath: cand.urlPath,
|
|
6408
|
+
routeName: cand.routeName,
|
|
6409
|
+
key: `${cand.urlPath}:shell`,
|
|
6410
|
+
ttl: policy.ttl,
|
|
6411
|
+
swr: policy.swr,
|
|
6412
|
+
tags: policy.tags,
|
|
6413
|
+
buildEnv: s.resolvedBuildEnv,
|
|
6414
|
+
buildVersion,
|
|
6415
|
+
captureShellHTML,
|
|
6416
|
+
debug: !!debug11
|
|
6417
|
+
});
|
|
6418
|
+
if (res.outcome === "route-mismatch") {
|
|
6419
|
+
mismatches.push(res.matchedRouteName ?? "(no match)");
|
|
6420
|
+
continue;
|
|
6421
|
+
}
|
|
6422
|
+
handled = true;
|
|
6423
|
+
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
6424
|
+
if (res.outcome !== "stored" || !res.entry) {
|
|
6425
|
+
console.warn(
|
|
6426
|
+
`[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} (${elapsed}ms) - capture ${res.outcome}; route keeps runtime capture`
|
|
6427
|
+
);
|
|
6428
|
+
skipCount++;
|
|
6429
|
+
break;
|
|
6430
|
+
}
|
|
6431
|
+
if (!fetchedKeys.has(mainKey)) {
|
|
6432
|
+
console.warn(
|
|
6433
|
+
`[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} (${elapsed}ms) - capture did not replay the prerender store; route keeps runtime capture`
|
|
6434
|
+
);
|
|
6435
|
+
skipCount++;
|
|
6436
|
+
break;
|
|
6437
|
+
}
|
|
6438
|
+
const value = {
|
|
6439
|
+
entry: res.entry,
|
|
6440
|
+
ttl: policy.ttl,
|
|
6441
|
+
swr: policy.swr,
|
|
6442
|
+
tags: res.tags,
|
|
6443
|
+
routeName: cand.routeName
|
|
6444
|
+
};
|
|
6445
|
+
staged.push({
|
|
6446
|
+
key: buildShellManifestKey(cand.urlPath),
|
|
6447
|
+
value: JSON.stringify(value)
|
|
6448
|
+
});
|
|
6449
|
+
console.log(
|
|
6450
|
+
`[rango] SHELL OK ${cand.urlPath.padEnd(34)} (${elapsed}ms)`
|
|
6451
|
+
);
|
|
6452
|
+
break;
|
|
6453
|
+
} catch (err) {
|
|
6454
|
+
handled = true;
|
|
6455
|
+
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
6456
|
+
console.warn(
|
|
6457
|
+
`[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} (${elapsed}ms) - ${err?.message ?? err}; route keeps runtime capture`
|
|
6458
|
+
);
|
|
6459
|
+
skipCount++;
|
|
6460
|
+
break;
|
|
6461
|
+
}
|
|
6462
|
+
}
|
|
6463
|
+
if (!handled) {
|
|
6464
|
+
console.warn(
|
|
6465
|
+
`[rango] SHELL SKIP ${cand.urlPath.padEnd(34)} - no router matched "${cand.routeName}"` + (mismatches.length > 0 ? ` (matched: ${mismatches.join(", ")})` : "") + "; route keeps runtime capture"
|
|
6466
|
+
);
|
|
6467
|
+
skipCount++;
|
|
6468
|
+
}
|
|
6469
|
+
}
|
|
6470
|
+
if (staged.length > 0) {
|
|
6471
|
+
const rscOutDir = builder?.environments?.rsc?.config?.build?.outDir ?? resolve8(s.projectRoot, "dist/rsc");
|
|
6472
|
+
writeShellManifest(s, rscOutDir, staged);
|
|
6473
|
+
}
|
|
6474
|
+
const totalElapsed = (performance.now() - startTotal).toFixed(0);
|
|
6475
|
+
const parts = [`${staged.length} done`];
|
|
6476
|
+
if (skipCount > 0) parts.push(`${skipCount} skipped`);
|
|
6477
|
+
console.log(
|
|
6478
|
+
`[rango] Shell prerender complete: ${parts.join(", ")} (${totalElapsed}ms total)`
|
|
6479
|
+
);
|
|
6480
|
+
} catch (err) {
|
|
6481
|
+
console.warn(
|
|
6482
|
+
`[rango] shell prerender phase failed: ${err?.message ?? err}; routes keep runtime shell capture.`
|
|
6483
|
+
);
|
|
6484
|
+
} finally {
|
|
6485
|
+
delete globalThis.__loadPrerenderManifestModule;
|
|
6486
|
+
restoreClientRequire?.();
|
|
6487
|
+
}
|
|
6488
|
+
}
|
|
6489
|
+
function writeShellManifest(s, rscOutDir, staged) {
|
|
6490
|
+
const rscEntryPath = resolve8(rscOutDir, s.rscEntryFileName ?? "index.js");
|
|
6491
|
+
if (!existsSync6(rscEntryPath)) {
|
|
6492
|
+
console.warn(
|
|
6493
|
+
`[rango] shell prerender: RSC entry not found at ${rscEntryPath}; entries not persisted \u2014 routes keep runtime capture.`
|
|
6494
|
+
);
|
|
6495
|
+
return;
|
|
6496
|
+
}
|
|
6497
|
+
const assetsDir = resolve8(rscOutDir, "assets");
|
|
6498
|
+
let totalBytes = 0;
|
|
6499
|
+
const manifestMap = {};
|
|
6500
|
+
const countedFiles = /* @__PURE__ */ new Set();
|
|
6501
|
+
for (const { key, value } of staged) {
|
|
6502
|
+
const fileName = writeBuildAssetModule(assetsDir, "__ps", value);
|
|
6503
|
+
if (!countedFiles.has(fileName)) {
|
|
6504
|
+
countedFiles.add(fileName);
|
|
6505
|
+
totalBytes += Buffer.byteLength(value) + "export default ;\n".length;
|
|
6506
|
+
}
|
|
6507
|
+
manifestMap[key] = `./assets/${fileName}`;
|
|
6508
|
+
}
|
|
6509
|
+
const manifestCode = [
|
|
6510
|
+
`const m=${jsonParseExpression(manifestMap)};`,
|
|
6511
|
+
`export function loadShellAsset(s){return import(s)}`,
|
|
6512
|
+
`export default m;`,
|
|
6513
|
+
""
|
|
6514
|
+
].join("\n");
|
|
6515
|
+
writeFileSync3(resolve8(rscOutDir, "__shell-manifest.js"), manifestCode);
|
|
6516
|
+
totalBytes += Buffer.byteLength(manifestCode);
|
|
6517
|
+
const rscCode = readFileSync4(rscEntryPath, "utf-8");
|
|
6518
|
+
if (!rscCode.includes("__shell-manifest.js")) {
|
|
6519
|
+
const injection = `globalThis.__loadShellManifestModule = () => import("./__shell-manifest.js");
|
|
6520
|
+
`;
|
|
6521
|
+
writeFileSync3(rscEntryPath, injection + rscCode);
|
|
6522
|
+
}
|
|
6523
|
+
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
6524
|
+
console.log(
|
|
6525
|
+
`[rango] Wrote shell assets (${totalKB} KB total, ${staged.length} entries)`
|
|
6526
|
+
);
|
|
6527
|
+
}
|
|
6528
|
+
|
|
6171
6529
|
// src/vite/discovery/dev-prerender-cache.ts
|
|
6172
6530
|
function payloadBodiesFromResult(result) {
|
|
6173
6531
|
const main = JSON.stringify({
|
|
@@ -6206,8 +6564,8 @@ function createDevPrerenderCache(maxEntriesPerRouter = MAX_ENTRIES_PER_ROUTER) {
|
|
|
6206
6564
|
}
|
|
6207
6565
|
|
|
6208
6566
|
// src/vite/discovery/route-types-writer.ts
|
|
6209
|
-
import { dirname as dirname3, join as
|
|
6210
|
-
import { readFileSync as
|
|
6567
|
+
import { dirname as dirname3, join as join5, resolve as resolve9 } from "node:path";
|
|
6568
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync7, unlinkSync as unlinkSync2 } from "node:fs";
|
|
6211
6569
|
function filterUserNamedRoutes(manifest) {
|
|
6212
6570
|
const filtered = {};
|
|
6213
6571
|
for (const [name, pattern] of Object.entries(manifest)) {
|
|
@@ -6218,10 +6576,10 @@ function filterUserNamedRoutes(manifest) {
|
|
|
6218
6576
|
return filtered;
|
|
6219
6577
|
}
|
|
6220
6578
|
function writeGenFileIfChanged(state, outPath, source, opts) {
|
|
6221
|
-
const existing =
|
|
6579
|
+
const existing = existsSync7(outPath) ? readFileSync5(outPath, "utf-8") : null;
|
|
6222
6580
|
if (existing === source) return;
|
|
6223
6581
|
markSelfGenWrite(state, outPath, source);
|
|
6224
|
-
|
|
6582
|
+
writeFileSync4(outPath, source);
|
|
6225
6583
|
if (opts?.log) console.log(`[rango] Generated route types -> ${outPath}`);
|
|
6226
6584
|
}
|
|
6227
6585
|
function writeCombinedRouteTypesWithTracking(state, opts) {
|
|
@@ -6236,10 +6594,10 @@ function writeRouteTypesFiles(state) {
|
|
|
6236
6594
|
if (state.perRouterManifests.length === 0) return;
|
|
6237
6595
|
try {
|
|
6238
6596
|
const entryDir = dirname3(
|
|
6239
|
-
|
|
6597
|
+
resolve9(state.projectRoot, state.resolvedEntryPath)
|
|
6240
6598
|
);
|
|
6241
|
-
const oldCombinedPath =
|
|
6242
|
-
if (
|
|
6599
|
+
const oldCombinedPath = join5(entryDir, "named-routes.gen.ts");
|
|
6600
|
+
if (existsSync7(oldCombinedPath)) {
|
|
6243
6601
|
unlinkSync2(oldCombinedPath);
|
|
6244
6602
|
console.log(
|
|
6245
6603
|
`[rango] Removed stale combined route types: ${oldCombinedPath}`
|
|
@@ -6320,7 +6678,7 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
6320
6678
|
}
|
|
6321
6679
|
|
|
6322
6680
|
// src/vite/discovery/virtual-module-codegen.ts
|
|
6323
|
-
import { dirname as dirname4, basename, join as
|
|
6681
|
+
import { dirname as dirname4, basename, join as join6 } from "node:path";
|
|
6324
6682
|
function generateRoutesManifestModule(state) {
|
|
6325
6683
|
const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
|
|
6326
6684
|
if (hasManifest) {
|
|
@@ -6335,7 +6693,7 @@ function generateRoutesManifestModule(state) {
|
|
|
6335
6693
|
/\.(tsx?|jsx?)$/,
|
|
6336
6694
|
""
|
|
6337
6695
|
);
|
|
6338
|
-
const genPath =
|
|
6696
|
+
const genPath = join6(
|
|
6339
6697
|
routerDir,
|
|
6340
6698
|
`${routerBasename}.named-routes.gen.js`
|
|
6341
6699
|
).replaceAll("\\", "/");
|
|
@@ -6420,7 +6778,7 @@ function generatePerRouterModule(state, routerId) {
|
|
|
6420
6778
|
/\.(tsx?|jsx?)$/,
|
|
6421
6779
|
""
|
|
6422
6780
|
);
|
|
6423
|
-
const genPath =
|
|
6781
|
+
const genPath = join6(
|
|
6424
6782
|
routerDir,
|
|
6425
6783
|
`${routerBasename}.named-routes.gen.js`
|
|
6426
6784
|
).replaceAll("\\", "/");
|
|
@@ -6447,13 +6805,13 @@ function generatePerRouterModule(state, routerId) {
|
|
|
6447
6805
|
}
|
|
6448
6806
|
|
|
6449
6807
|
// src/vite/discovery/bundle-postprocess.ts
|
|
6450
|
-
import { resolve as
|
|
6451
|
-
import { readFileSync as
|
|
6808
|
+
import { resolve as resolve10 } from "node:path";
|
|
6809
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync8 } from "node:fs";
|
|
6452
6810
|
function postprocessBundle(state) {
|
|
6453
6811
|
const hasPrerenderData = state.prerenderManifestEntries && Object.keys(state.prerenderManifestEntries).length > 0;
|
|
6454
6812
|
const hasStaticData = state.staticManifestEntries && Object.keys(state.staticManifestEntries).length > 0;
|
|
6455
6813
|
if (!hasPrerenderData && !hasStaticData) return;
|
|
6456
|
-
const rscEntryPath =
|
|
6814
|
+
const rscEntryPath = resolve10(
|
|
6457
6815
|
state.projectRoot,
|
|
6458
6816
|
"dist/rsc",
|
|
6459
6817
|
state.rscEntryFileName ?? "index.js"
|
|
@@ -6474,9 +6832,9 @@ function postprocessBundle(state) {
|
|
|
6474
6832
|
];
|
|
6475
6833
|
for (const target of evictionTargets) {
|
|
6476
6834
|
for (const info of target.infos) {
|
|
6477
|
-
const chunkPath =
|
|
6835
|
+
const chunkPath = resolve10(state.projectRoot, "dist/rsc", info.fileName);
|
|
6478
6836
|
try {
|
|
6479
|
-
const code =
|
|
6837
|
+
const code = readFileSync6(chunkPath, "utf-8");
|
|
6480
6838
|
const result = evictHandlerCode(
|
|
6481
6839
|
code,
|
|
6482
6840
|
info.exports,
|
|
@@ -6484,7 +6842,7 @@ function postprocessBundle(state) {
|
|
|
6484
6842
|
target.brand
|
|
6485
6843
|
);
|
|
6486
6844
|
if (result) {
|
|
6487
|
-
|
|
6845
|
+
writeFileSync5(chunkPath, result.code);
|
|
6488
6846
|
const savedKB = (result.savedBytes / 1024).toFixed(1);
|
|
6489
6847
|
console.log(
|
|
6490
6848
|
`[rango] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
|
|
@@ -6499,8 +6857,8 @@ function postprocessBundle(state) {
|
|
|
6499
6857
|
}
|
|
6500
6858
|
state.handlerChunkInfoMap.clear();
|
|
6501
6859
|
state.staticHandlerChunkInfoMap.clear();
|
|
6502
|
-
if (hasPrerenderData &&
|
|
6503
|
-
const rscCode =
|
|
6860
|
+
if (hasPrerenderData && existsSync8(rscEntryPath)) {
|
|
6861
|
+
const rscCode = readFileSync6(rscEntryPath, "utf-8");
|
|
6504
6862
|
if (!rscCode.includes("__prerender-manifest.js")) {
|
|
6505
6863
|
try {
|
|
6506
6864
|
let totalBytes = copyStagedBuildAssets(
|
|
@@ -6519,15 +6877,15 @@ function postprocessBundle(state) {
|
|
|
6519
6877
|
`export default m;`,
|
|
6520
6878
|
""
|
|
6521
6879
|
].join("\n");
|
|
6522
|
-
const manifestPath =
|
|
6880
|
+
const manifestPath = resolve10(
|
|
6523
6881
|
state.projectRoot,
|
|
6524
6882
|
"dist/rsc/__prerender-manifest.js"
|
|
6525
6883
|
);
|
|
6526
|
-
|
|
6884
|
+
writeFileSync5(manifestPath, manifestCode);
|
|
6527
6885
|
totalBytes += Buffer.byteLength(manifestCode);
|
|
6528
6886
|
const injection = `globalThis.__loadPrerenderManifestModule = () => import("./__prerender-manifest.js");
|
|
6529
6887
|
`;
|
|
6530
|
-
|
|
6888
|
+
writeFileSync5(rscEntryPath, injection + rscCode);
|
|
6531
6889
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
6532
6890
|
console.log(
|
|
6533
6891
|
`[rango] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.prerenderManifestEntries).length} entries)`
|
|
@@ -6539,8 +6897,8 @@ function postprocessBundle(state) {
|
|
|
6539
6897
|
}
|
|
6540
6898
|
}
|
|
6541
6899
|
}
|
|
6542
|
-
if (hasStaticData &&
|
|
6543
|
-
const rscCode =
|
|
6900
|
+
if (hasStaticData && existsSync8(rscEntryPath)) {
|
|
6901
|
+
const rscCode = readFileSync6(rscEntryPath, "utf-8");
|
|
6544
6902
|
if (!rscCode.includes("__static-manifest.js")) {
|
|
6545
6903
|
try {
|
|
6546
6904
|
const manifestEntries = [];
|
|
@@ -6557,15 +6915,15 @@ function postprocessBundle(state) {
|
|
|
6557
6915
|
}
|
|
6558
6916
|
const manifestCode = `const m={${manifestEntries.join(",")}};globalThis.__STATIC_MANIFEST=m;export default m;
|
|
6559
6917
|
`;
|
|
6560
|
-
const manifestPath =
|
|
6918
|
+
const manifestPath = resolve10(
|
|
6561
6919
|
state.projectRoot,
|
|
6562
6920
|
"dist/rsc/__static-manifest.js"
|
|
6563
6921
|
);
|
|
6564
|
-
|
|
6922
|
+
writeFileSync5(manifestPath, manifestCode);
|
|
6565
6923
|
totalBytes += Buffer.byteLength(manifestCode);
|
|
6566
6924
|
const injection = `import "./__static-manifest.js";
|
|
6567
6925
|
`;
|
|
6568
|
-
|
|
6926
|
+
writeFileSync5(rscEntryPath, injection + rscCode);
|
|
6569
6927
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
6570
6928
|
console.log(
|
|
6571
6929
|
`[rango] Wrote static assets (${totalKB} KB total, ${Object.keys(state.staticManifestEntries).length} entries)`
|
|
@@ -6580,7 +6938,7 @@ function postprocessBundle(state) {
|
|
|
6580
6938
|
}
|
|
6581
6939
|
|
|
6582
6940
|
// src/vite/discovery/gate-state.ts
|
|
6583
|
-
function createDiscoveryGate(s,
|
|
6941
|
+
function createDiscoveryGate(s, debug12) {
|
|
6584
6942
|
let gatePending = false;
|
|
6585
6943
|
let gateResolver = () => {
|
|
6586
6944
|
};
|
|
@@ -6589,15 +6947,15 @@ function createDiscoveryGate(s, debug11) {
|
|
|
6589
6947
|
let pendingEvents = false;
|
|
6590
6948
|
const beginGate = () => {
|
|
6591
6949
|
if (gatePending) return;
|
|
6592
|
-
s.discoveryDone = new Promise((
|
|
6593
|
-
gateResolver =
|
|
6950
|
+
s.discoveryDone = new Promise((resolve13) => {
|
|
6951
|
+
gateResolver = resolve13;
|
|
6594
6952
|
});
|
|
6595
6953
|
gatePending = true;
|
|
6596
6954
|
};
|
|
6597
6955
|
const resolveGate = () => {
|
|
6598
6956
|
if (!gatePending) return;
|
|
6599
6957
|
if (inProgress || queued || pendingEvents) {
|
|
6600
|
-
|
|
6958
|
+
debug12?.(
|
|
6601
6959
|
"hmr: resolveGate deferred \u2014 work in flight (inProgress=%s queued=%s pendingEvents=%s)",
|
|
6602
6960
|
inProgress,
|
|
6603
6961
|
queued,
|
|
@@ -6606,7 +6964,7 @@ function createDiscoveryGate(s, debug11) {
|
|
|
6606
6964
|
return;
|
|
6607
6965
|
}
|
|
6608
6966
|
gatePending = false;
|
|
6609
|
-
|
|
6967
|
+
debug12?.("hmr: discoveryDone resolved");
|
|
6610
6968
|
gateResolver();
|
|
6611
6969
|
};
|
|
6612
6970
|
const noteRouteEvent = () => {
|
|
@@ -6616,7 +6974,7 @@ function createDiscoveryGate(s, debug11) {
|
|
|
6616
6974
|
const runRefreshCycle = async (work) => {
|
|
6617
6975
|
if (inProgress) {
|
|
6618
6976
|
queued = true;
|
|
6619
|
-
|
|
6977
|
+
debug12?.("hmr: rediscovery in flight \u2014 queued for a follow-up cycle");
|
|
6620
6978
|
return;
|
|
6621
6979
|
}
|
|
6622
6980
|
pendingEvents = false;
|
|
@@ -6627,16 +6985,16 @@ function createDiscoveryGate(s, debug11) {
|
|
|
6627
6985
|
inProgress = false;
|
|
6628
6986
|
if (queued) {
|
|
6629
6987
|
queued = false;
|
|
6630
|
-
|
|
6988
|
+
debug12?.("hmr: consuming queued rediscovery");
|
|
6631
6989
|
runRefreshCycle(work).catch((err) => {
|
|
6632
|
-
|
|
6990
|
+
debug12?.(
|
|
6633
6991
|
"hmr: queued cycle rejected \u2014 releasing gate (%s)",
|
|
6634
6992
|
err instanceof Error ? err.message : String(err)
|
|
6635
6993
|
);
|
|
6636
6994
|
resolveGate();
|
|
6637
6995
|
});
|
|
6638
6996
|
} else if (pendingEvents) {
|
|
6639
|
-
|
|
6997
|
+
debug12?.(
|
|
6640
6998
|
"hmr: holding gate for pending events (debounce not yet fired)"
|
|
6641
6999
|
);
|
|
6642
7000
|
} else {
|
|
@@ -6682,15 +7040,15 @@ function selectForwardableResolvePlugins(plugins) {
|
|
|
6682
7040
|
}
|
|
6683
7041
|
function pickForwardedRunnerConfig(config) {
|
|
6684
7042
|
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)
|
|
7043
|
+
const resolve13 = {};
|
|
7044
|
+
if (r.alias !== void 0) resolve13.alias = r.alias;
|
|
7045
|
+
if (r.dedupe !== void 0) resolve13.dedupe = r.dedupe;
|
|
7046
|
+
if (r.conditions !== void 0) resolve13.conditions = r.conditions;
|
|
7047
|
+
if (r.mainFields !== void 0) resolve13.mainFields = r.mainFields;
|
|
7048
|
+
if (r.extensions !== void 0) resolve13.extensions = r.extensions;
|
|
6691
7049
|
if (r.preserveSymlinks !== void 0)
|
|
6692
|
-
|
|
6693
|
-
if (r.tsconfigPaths !== void 0)
|
|
7050
|
+
resolve13.preserveSymlinks = r.preserveSymlinks;
|
|
7051
|
+
if (r.tsconfigPaths !== void 0) resolve13.tsconfigPaths = r.tsconfigPaths;
|
|
6694
7052
|
const userOxc = config.oxc;
|
|
6695
7053
|
const userJsx = userOxc && typeof userOxc === "object" && typeof userOxc.jsx === "object" && userOxc.jsx !== null ? userOxc.jsx : {};
|
|
6696
7054
|
const oxc = userOxc && typeof userOxc === "object" ? {
|
|
@@ -6698,13 +7056,14 @@ function pickForwardedRunnerConfig(config) {
|
|
|
6698
7056
|
jsx: { ...userJsx, runtime: "automatic", importSource: "react" }
|
|
6699
7057
|
} : { jsx: { runtime: "automatic", importSource: "react" } };
|
|
6700
7058
|
return {
|
|
6701
|
-
resolve:
|
|
7059
|
+
resolve: resolve13,
|
|
6702
7060
|
define: config.define,
|
|
6703
7061
|
oxc
|
|
6704
7062
|
};
|
|
6705
7063
|
}
|
|
6706
7064
|
|
|
6707
7065
|
// src/vite/router-discovery.ts
|
|
7066
|
+
init_debug();
|
|
6708
7067
|
var debugDiscovery = createRangoDebugger(NS.discovery);
|
|
6709
7068
|
var debugRoutes = createRangoDebugger(NS.routes);
|
|
6710
7069
|
var debugBuild = createRangoDebugger(NS.build);
|
|
@@ -6754,6 +7113,20 @@ async function createTempRscServer(state, options = {}) {
|
|
|
6754
7113
|
// hashClientRefs only in build mode — production bundles need hashed refs
|
|
6755
7114
|
...options.forceBuild ? [hashClientRefs(state.projectRoot)] : [],
|
|
6756
7115
|
createVersionPlugin(),
|
|
7116
|
+
// Before the stub plugin, so "virtual:entry-ssr" resolves to the real
|
|
7117
|
+
// SSR entry when the shell endpoint needs it (see the option doc).
|
|
7118
|
+
...options.realSsrEntry ? [
|
|
7119
|
+
{
|
|
7120
|
+
name: "@rangojs/router:temp-real-ssr-entry",
|
|
7121
|
+
enforce: "pre",
|
|
7122
|
+
resolveId(id) {
|
|
7123
|
+
return id === "virtual:entry-ssr" ? "\0rango-temp-real-ssr-entry" : null;
|
|
7124
|
+
},
|
|
7125
|
+
load(id) {
|
|
7126
|
+
return id === "\0rango-temp-real-ssr-entry" ? getVirtualEntrySSR(state.opts?.headScripts) : null;
|
|
7127
|
+
}
|
|
7128
|
+
}
|
|
7129
|
+
] : [],
|
|
6757
7130
|
createVirtualStubPlugin(),
|
|
6758
7131
|
createCloudflareProtocolStubPlugin(),
|
|
6759
7132
|
// Dev prerender must use dev-mode IDs (path-based) to match the workerd
|
|
@@ -6777,7 +7150,7 @@ async function resolveBuildEnv(option, factoryCtx) {
|
|
|
6777
7150
|
}
|
|
6778
7151
|
try {
|
|
6779
7152
|
const userRequire = createRequire3(
|
|
6780
|
-
|
|
7153
|
+
resolve11(factoryCtx.root, "package.json")
|
|
6781
7154
|
);
|
|
6782
7155
|
const wranglerPath = userRequire.resolve("wrangler");
|
|
6783
7156
|
const { getPlatformProxy } = await import(pathToFileURL2(wranglerPath).href);
|
|
@@ -6814,6 +7187,12 @@ async function acquireBuildEnv(s, command, mode) {
|
|
|
6814
7187
|
globalThis[BUILD_ENV_GLOBAL_KEY] = result.env;
|
|
6815
7188
|
return true;
|
|
6816
7189
|
}
|
|
7190
|
+
function resetPrerenderCollection(s) {
|
|
7191
|
+
s.prerenderManifestEntries = null;
|
|
7192
|
+
s.staticManifestEntries = null;
|
|
7193
|
+
s.shellCandidates = null;
|
|
7194
|
+
s.prerenderPayloadValues = null;
|
|
7195
|
+
}
|
|
6817
7196
|
async function releaseBuildEnv(s) {
|
|
6818
7197
|
if (s.buildEnvDispose) {
|
|
6819
7198
|
try {
|
|
@@ -6878,8 +7257,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
6878
7257
|
s.devServer = server;
|
|
6879
7258
|
server.middlewares.use(internalDebugNoCacheMiddleware());
|
|
6880
7259
|
let resolveDiscovery;
|
|
6881
|
-
const discoveryPromise = new Promise((
|
|
6882
|
-
resolveDiscovery =
|
|
7260
|
+
const discoveryPromise = new Promise((resolve13) => {
|
|
7261
|
+
resolveDiscovery = resolve13;
|
|
6883
7262
|
});
|
|
6884
7263
|
const gate = createDiscoveryGate(s, debugDiscovery);
|
|
6885
7264
|
const beginDiscoveryGate = gate.beginGate;
|
|
@@ -6969,7 +7348,11 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
6969
7348
|
);
|
|
6970
7349
|
try {
|
|
6971
7350
|
prerenderTempServer = await createTempRscServer(s, {
|
|
6972
|
-
cacheDir: "node_modules/.vite_prerender"
|
|
7351
|
+
cacheDir: "node_modules/.vite_prerender",
|
|
7352
|
+
// The dev /__rsc_shell endpoint drives captureShellHTML in this
|
|
7353
|
+
// server's SSR realm; the entry is only imported when a shell
|
|
7354
|
+
// capture runs, so discovery cost is unchanged.
|
|
7355
|
+
realSsrEntry: true
|
|
6973
7356
|
});
|
|
6974
7357
|
const tempRscEnv = prerenderTempServer.environments?.rsc;
|
|
6975
7358
|
if (tempRscEnv?.runner) {
|
|
@@ -7301,6 +7684,155 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
7301
7684
|
res.end("No prerender match");
|
|
7302
7685
|
logResult(404, "no match");
|
|
7303
7686
|
});
|
|
7687
|
+
server.middlewares.use("/__rsc_shell", async (req, res) => {
|
|
7688
|
+
await s.discoveryDone;
|
|
7689
|
+
const url = new URL(req.url ?? "", "http://localhost");
|
|
7690
|
+
const pathname = url.searchParams.get("pathname");
|
|
7691
|
+
const routeName = url.searchParams.get("routeName");
|
|
7692
|
+
const version = url.searchParams.get("version");
|
|
7693
|
+
const ttlRaw = url.searchParams.get("ttl");
|
|
7694
|
+
if (!pathname || !routeName || !version || !ttlRaw) {
|
|
7695
|
+
res.statusCode = 400;
|
|
7696
|
+
res.end("Missing pathname/routeName/version/ttl");
|
|
7697
|
+
return;
|
|
7698
|
+
}
|
|
7699
|
+
const ttl = Number(ttlRaw);
|
|
7700
|
+
const swrRaw = url.searchParams.get("swr");
|
|
7701
|
+
const swr = swrRaw === null ? void 0 : Number(swrRaw);
|
|
7702
|
+
const tagsRaw = url.searchParams.get("tags");
|
|
7703
|
+
const tags = tagsRaw ? tagsRaw.split(",") : void 0;
|
|
7704
|
+
const rscEnvMain = server.environments?.rsc;
|
|
7705
|
+
let rscRealm = null;
|
|
7706
|
+
let ssrRealm = null;
|
|
7707
|
+
let ssrEntryId;
|
|
7708
|
+
if (rscEnvMain?.runner && s.resolvedEntryPath) {
|
|
7709
|
+
try {
|
|
7710
|
+
await rscEnvMain.runner.import(s.resolvedEntryPath);
|
|
7711
|
+
} catch (err) {
|
|
7712
|
+
res.statusCode = 500;
|
|
7713
|
+
res.end(`Shell capture module refresh failed: ${err.message}`);
|
|
7714
|
+
return;
|
|
7715
|
+
}
|
|
7716
|
+
rscRealm = rscEnvMain;
|
|
7717
|
+
ssrRealm = server.environments?.ssr;
|
|
7718
|
+
ssrEntryId = server.environments?.ssr?.config?.build?.rollupOptions?.input?.index ?? VIRTUAL_IDS.ssr;
|
|
7719
|
+
} else {
|
|
7720
|
+
const tempRscEnv = await getOrCreateTempServer();
|
|
7721
|
+
if (tempRscEnv) {
|
|
7722
|
+
try {
|
|
7723
|
+
await importEntryAndRegistry(tempRscEnv);
|
|
7724
|
+
} catch (err) {
|
|
7725
|
+
res.statusCode = 500;
|
|
7726
|
+
res.end(`Shell capture module refresh failed: ${err.message}`);
|
|
7727
|
+
return;
|
|
7728
|
+
}
|
|
7729
|
+
}
|
|
7730
|
+
rscRealm = tempRscEnv;
|
|
7731
|
+
ssrRealm = prerenderTempServer?.environments?.ssr;
|
|
7732
|
+
ssrEntryId = "virtual:entry-ssr";
|
|
7733
|
+
}
|
|
7734
|
+
if (!rscRealm?.runner || !ssrRealm?.runner) {
|
|
7735
|
+
res.statusCode = 503;
|
|
7736
|
+
res.end("Shell capture runners not available");
|
|
7737
|
+
return;
|
|
7738
|
+
}
|
|
7739
|
+
let registry = null;
|
|
7740
|
+
try {
|
|
7741
|
+
const serverMod = await rscRealm.runner.import(
|
|
7742
|
+
"@rangojs/router/server"
|
|
7743
|
+
);
|
|
7744
|
+
registry = serverMod.RouterRegistry ?? null;
|
|
7745
|
+
} catch {
|
|
7746
|
+
registry = null;
|
|
7747
|
+
}
|
|
7748
|
+
if (!registry || registry.size === 0) {
|
|
7749
|
+
res.statusCode = 503;
|
|
7750
|
+
res.end("Shell capture registry not available");
|
|
7751
|
+
return;
|
|
7752
|
+
}
|
|
7753
|
+
const cacheKey = `shell|${pathname}|r=${routeName}|t=${ttl}|s=${swr ?? ""}|g=${(tags ?? []).join("+")}|v=${version}`;
|
|
7754
|
+
for (const [, routerInstance] of registry) {
|
|
7755
|
+
if (typeof routerInstance.match !== "function") continue;
|
|
7756
|
+
const cached = devPrerenderCache.get(routerInstance, cacheKey);
|
|
7757
|
+
if (cached !== void 0) {
|
|
7758
|
+
res.setHeader("content-type", "application/json");
|
|
7759
|
+
res.setHeader("x-rango-shell-dev", "HIT");
|
|
7760
|
+
res.end(cached);
|
|
7761
|
+
return;
|
|
7762
|
+
}
|
|
7763
|
+
}
|
|
7764
|
+
if (s.devServerOrigin) {
|
|
7765
|
+
try {
|
|
7766
|
+
const probe = await fetch(
|
|
7767
|
+
`${s.devServerOrigin}/__rsc_prerender?pathname=${encodeURIComponent(pathname)}&routeName=${encodeURIComponent(routeName)}`,
|
|
7768
|
+
{ signal: AbortSignal.timeout(1e4) }
|
|
7769
|
+
);
|
|
7770
|
+
if (!probe.ok) {
|
|
7771
|
+
res.statusCode = 404;
|
|
7772
|
+
res.end("Route is not prerenderable");
|
|
7773
|
+
return;
|
|
7774
|
+
}
|
|
7775
|
+
} catch {
|
|
7776
|
+
res.statusCode = 404;
|
|
7777
|
+
res.end("Prerender pre-flight failed");
|
|
7778
|
+
return;
|
|
7779
|
+
}
|
|
7780
|
+
}
|
|
7781
|
+
for (const [, routerInstance] of registry) {
|
|
7782
|
+
if (typeof routerInstance.match !== "function") continue;
|
|
7783
|
+
try {
|
|
7784
|
+
const ssrModule = await ssrRealm.runner.import(ssrEntryId);
|
|
7785
|
+
if (typeof ssrModule?.captureShellHTML !== "function") {
|
|
7786
|
+
res.statusCode = 404;
|
|
7787
|
+
res.end("SSR entry has no captureShellHTML");
|
|
7788
|
+
return;
|
|
7789
|
+
}
|
|
7790
|
+
const captureMod = await rscRealm.runner.import(
|
|
7791
|
+
"@rangojs/router/build/shell-capture"
|
|
7792
|
+
);
|
|
7793
|
+
const result = await captureMod.captureShellForBuild({
|
|
7794
|
+
router: routerInstance,
|
|
7795
|
+
urlPath: pathname,
|
|
7796
|
+
routeName,
|
|
7797
|
+
key: `${pathname}:shell`,
|
|
7798
|
+
ttl,
|
|
7799
|
+
swr,
|
|
7800
|
+
tags,
|
|
7801
|
+
buildEnv: s.resolvedBuildEnv,
|
|
7802
|
+
buildVersion: version,
|
|
7803
|
+
captureShellHTML: ssrModule.captureShellHTML,
|
|
7804
|
+
debug: !!debugDiscovery
|
|
7805
|
+
});
|
|
7806
|
+
if (result.outcome === "route-mismatch") continue;
|
|
7807
|
+
if (result.outcome !== "stored" || !result.entry) {
|
|
7808
|
+
res.statusCode = 404;
|
|
7809
|
+
res.end(`Shell capture ${result.outcome}`);
|
|
7810
|
+
return;
|
|
7811
|
+
}
|
|
7812
|
+
const body = JSON.stringify({
|
|
7813
|
+
entry: result.entry,
|
|
7814
|
+
ttl,
|
|
7815
|
+
swr,
|
|
7816
|
+
tags: result.tags,
|
|
7817
|
+
routeName
|
|
7818
|
+
});
|
|
7819
|
+
devPrerenderCache.set(routerInstance, cacheKey, body);
|
|
7820
|
+
res.setHeader("content-type", "application/json");
|
|
7821
|
+
res.setHeader("x-rango-shell-dev", "MISS");
|
|
7822
|
+
res.end(body);
|
|
7823
|
+
return;
|
|
7824
|
+
} catch (err) {
|
|
7825
|
+
console.warn(
|
|
7826
|
+
`[rango] Dev shell capture error for ${pathname} (route keeps runtime capture): ${err.message}`
|
|
7827
|
+
);
|
|
7828
|
+
res.statusCode = 404;
|
|
7829
|
+
res.end(`Shell capture error: ${err.message}`);
|
|
7830
|
+
return;
|
|
7831
|
+
}
|
|
7832
|
+
}
|
|
7833
|
+
res.statusCode = 404;
|
|
7834
|
+
res.end("No router matched");
|
|
7835
|
+
});
|
|
7304
7836
|
if (opts?.staticRouteTypesGeneration !== false) {
|
|
7305
7837
|
const isGeneratedRouteFile = (filePath) => filePath.endsWith(".gen.ts") && (filePath.includes("named-routes.gen.ts") || filePath.includes("urls.gen.ts"));
|
|
7306
7838
|
const regenerateGeneratedRouteFiles = () => {
|
|
@@ -7470,7 +8002,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
7470
8002
|
}
|
|
7471
8003
|
const inRecoveryMode = !!s.lastDiscoveryError;
|
|
7472
8004
|
try {
|
|
7473
|
-
const source =
|
|
8005
|
+
const source = readFileSync7(filePath, "utf-8");
|
|
7474
8006
|
const trimmed = source.trimStart();
|
|
7475
8007
|
const isUseClient = trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'");
|
|
7476
8008
|
if (!inRecoveryMode && isUseClient) return;
|
|
@@ -7501,7 +8033,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
7501
8033
|
if (hasCreateRouter) {
|
|
7502
8034
|
const nestedRouterConflict = findNestedRouterConflict([
|
|
7503
8035
|
...s.cachedRouterFiles ?? [],
|
|
7504
|
-
|
|
8036
|
+
resolve11(filePath)
|
|
7505
8037
|
]);
|
|
7506
8038
|
if (nestedRouterConflict) {
|
|
7507
8039
|
server.config.logger.error(
|
|
@@ -7551,8 +8083,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
7551
8083
|
const buildStartTime = performance.now();
|
|
7552
8084
|
debugDiscovery?.("build: start (env=%s)", this.environment?.name ?? "?");
|
|
7553
8085
|
resetStagedBuildAssets(s.projectRoot);
|
|
7554
|
-
s
|
|
7555
|
-
s.staticManifestEntries = null;
|
|
8086
|
+
resetPrerenderCollection(s);
|
|
7556
8087
|
await timed(
|
|
7557
8088
|
debugDiscovery,
|
|
7558
8089
|
"build acquireBuildEnv",
|
|
@@ -7607,20 +8138,59 @@ ${details}`,
|
|
|
7607
8138
|
);
|
|
7608
8139
|
} finally {
|
|
7609
8140
|
delete globalThis.__rscRouterDiscoveryActive;
|
|
7610
|
-
if (tempServer) {
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
8141
|
+
if (tempServer && s.shellCandidates?.length) {
|
|
8142
|
+
s.shellPhaseTempServer = tempServer;
|
|
8143
|
+
} else {
|
|
8144
|
+
if (tempServer) {
|
|
8145
|
+
await timed(
|
|
8146
|
+
debugDiscovery,
|
|
8147
|
+
"build tempServer.close",
|
|
8148
|
+
() => tempServer.close()
|
|
8149
|
+
);
|
|
8150
|
+
}
|
|
8151
|
+
await releaseBuildEnv(s);
|
|
7616
8152
|
}
|
|
7617
|
-
await releaseBuildEnv(s);
|
|
7618
8153
|
debugDiscovery?.(
|
|
7619
8154
|
"build discovery done (%sms)",
|
|
7620
8155
|
(performance.now() - buildStartTime).toFixed(1)
|
|
7621
8156
|
);
|
|
7622
8157
|
}
|
|
7623
8158
|
},
|
|
8159
|
+
// Post-build PPR shell capture (producer B, #699): runs after EVERY
|
|
8160
|
+
// environment bundle is written — the shell prelude embeds built client
|
|
8161
|
+
// asset URLs (bootstrap entry), which do not exist at buildStart. The
|
|
8162
|
+
// kept temp server and the buildEnv were deferred AS A PAIR in
|
|
8163
|
+
// buildStart's finally; this finally is the pair's success-path owner
|
|
8164
|
+
// (buildEnd below owns the aborted-build path) — the phase itself is a
|
|
8165
|
+
// pure producer and tears down only the globals it installs.
|
|
8166
|
+
buildApp: {
|
|
8167
|
+
order: "post",
|
|
8168
|
+
async handler(builder) {
|
|
8169
|
+
try {
|
|
8170
|
+
await runShellPrerenderPhase(s, builder);
|
|
8171
|
+
} finally {
|
|
8172
|
+
if (s.isBuildMode) {
|
|
8173
|
+
const tempServer = s.shellPhaseTempServer;
|
|
8174
|
+
s.shellPhaseTempServer = null;
|
|
8175
|
+
if (tempServer) await tempServer.close();
|
|
8176
|
+
await releaseBuildEnv(s);
|
|
8177
|
+
}
|
|
8178
|
+
}
|
|
8179
|
+
}
|
|
8180
|
+
},
|
|
8181
|
+
// An environment build failure aborts the builder before the buildApp
|
|
8182
|
+
// post hook — never leak the kept temp server (open handles hang the CLI)
|
|
8183
|
+
// or the deferred buildEnv (a live miniflare proxy).
|
|
8184
|
+
async buildEnd(error) {
|
|
8185
|
+
if (!error || !s.shellPhaseTempServer) return;
|
|
8186
|
+
const tempServer = s.shellPhaseTempServer;
|
|
8187
|
+
s.shellPhaseTempServer = null;
|
|
8188
|
+
try {
|
|
8189
|
+
await tempServer.close();
|
|
8190
|
+
} finally {
|
|
8191
|
+
await releaseBuildEnv(s);
|
|
8192
|
+
}
|
|
8193
|
+
},
|
|
7624
8194
|
// Suppress vite's HMR cascade for our own gen-file writes.
|
|
7625
8195
|
//
|
|
7626
8196
|
// After every cf HMR cycle, refreshTempRscEnv → writeRouteTypesFiles
|
|
@@ -7785,6 +8355,7 @@ ${details}`,
|
|
|
7785
8355
|
}
|
|
7786
8356
|
|
|
7787
8357
|
// src/vite/rango.ts
|
|
8358
|
+
init_debug();
|
|
7788
8359
|
var debugConfig = createRangoDebugger(NS.config);
|
|
7789
8360
|
async function rango(options) {
|
|
7790
8361
|
const rangoStart = performance.now();
|
|
@@ -7929,14 +8500,14 @@ async function rango(options) {
|
|
|
7929
8500
|
name: "@rangojs/router:auto-discover",
|
|
7930
8501
|
config(userConfig) {
|
|
7931
8502
|
if (routerRef.path) return;
|
|
7932
|
-
const root = userConfig.root ?
|
|
8503
|
+
const root = userConfig.root ? resolve12(process.cwd(), userConfig.root) : process.cwd();
|
|
7933
8504
|
const toRootRelative = (abs) => (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
|
|
7934
8505
|
const bulletList = (files) => files.map((f) => " - " + toRootRelative(f)).join("\n");
|
|
7935
8506
|
if (explicitHostRouter) {
|
|
7936
8507
|
routerRef.path = normalizeHostRouterEntry(
|
|
7937
8508
|
explicitHostRouter,
|
|
7938
8509
|
root,
|
|
7939
|
-
|
|
8510
|
+
existsSync9
|
|
7940
8511
|
);
|
|
7941
8512
|
routerRef.kind = "host";
|
|
7942
8513
|
return;
|
|
@@ -8117,7 +8688,7 @@ If this is a multi-app host router, export a createHostRouter() instance and set
|
|
|
8117
8688
|
if (!file.endsWith(".tsx") && !file.endsWith(".ts") && !file.endsWith(".jsx") && !file.endsWith(".js"))
|
|
8118
8689
|
return;
|
|
8119
8690
|
try {
|
|
8120
|
-
const source =
|
|
8691
|
+
const source = readFileSync8(file, "utf-8");
|
|
8121
8692
|
if (hasUseClientDirective(source)) {
|
|
8122
8693
|
return [];
|
|
8123
8694
|
}
|
|
@@ -8144,7 +8715,8 @@ If this is a multi-app host router, export a createHostRouter() instance and set
|
|
|
8144
8715
|
preset,
|
|
8145
8716
|
prerenderOnError: options?.prerender?.onError,
|
|
8146
8717
|
discovery: options?.discovery,
|
|
8147
|
-
clientChunkCtx
|
|
8718
|
+
clientChunkCtx,
|
|
8719
|
+
headScripts: resolvedOptions.headScripts
|
|
8148
8720
|
})
|
|
8149
8721
|
);
|
|
8150
8722
|
if (preset === "vercel") {
|
|
@@ -8168,7 +8740,7 @@ function poke() {
|
|
|
8168
8740
|
apply: "serve",
|
|
8169
8741
|
configureServer(server) {
|
|
8170
8742
|
const stdin = process.stdin;
|
|
8171
|
-
const
|
|
8743
|
+
const debug12 = process.env.RANGO_POKE_DEBUG === "1";
|
|
8172
8744
|
const triggerReload = (source) => {
|
|
8173
8745
|
server.hot.send({ type: "full-reload", path: "*" });
|
|
8174
8746
|
server.config.logger.info(` browser reload (${source})`, {
|
|
@@ -8201,7 +8773,7 @@ function poke() {
|
|
|
8201
8773
|
lines.pop();
|
|
8202
8774
|
return lines;
|
|
8203
8775
|
};
|
|
8204
|
-
if (
|
|
8776
|
+
if (debug12) {
|
|
8205
8777
|
server.config.logger.info(
|
|
8206
8778
|
` poke debug enabled (isTTY=${stdin.isTTY ? "yes" : "no"}, isRaw=${stdin.isTTY ? stdin.isRaw ? "yes" : "no" : "n/a"})`,
|
|
8207
8779
|
{ timestamp: true }
|
|
@@ -8214,7 +8786,7 @@ function poke() {
|
|
|
8214
8786
|
);
|
|
8215
8787
|
}
|
|
8216
8788
|
const onData = (data) => {
|
|
8217
|
-
if (
|
|
8789
|
+
if (debug12) {
|
|
8218
8790
|
server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
|
|
8219
8791
|
timestamp: true
|
|
8220
8792
|
});
|