@rangojs/router 0.0.0-experimental.77 → 0.0.0-experimental.77ed8945
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/README.md +120 -25
- package/dist/bin/rango.js +147 -57
- package/dist/vite/index.js +2103 -861
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +13 -8
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +3 -1
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +220 -30
- package/skills/caching/SKILL.md +116 -8
- package/skills/composability/SKILL.md +27 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +3 -1
- package/skills/hooks/SKILL.md +229 -20
- package/skills/host-router/SKILL.md +66 -20
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +26 -4
- package/skills/layout/SKILL.md +6 -7
- package/skills/links/SKILL.md +247 -17
- package/skills/loader/SKILL.md +219 -9
- package/skills/middleware/SKILL.md +47 -12
- package/skills/migrate-nextjs/SKILL.md +562 -0
- package/skills/migrate-react-router/SKILL.md +769 -0
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +12 -6
- package/skills/prerender/SKILL.md +14 -33
- package/skills/rango/SKILL.md +238 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +122 -47
- package/skills/route/SKILL.md +33 -4
- package/skills/router-setup/SKILL.md +3 -3
- package/skills/server-actions/SKILL.md +751 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/typesafety/SKILL.md +319 -27
- package/skills/use-cache/SKILL.md +34 -5
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/event-controller.ts +86 -70
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/navigation-bridge.ts +29 -9
- package/src/browser/navigation-client.ts +99 -77
- package/src/browser/navigation-store.ts +7 -8
- package/src/browser/navigation-transaction.ts +10 -28
- package/src/browser/partial-update.ts +60 -40
- package/src/browser/prefetch/cache.ts +196 -49
- package/src/browser/prefetch/fetch.ts +203 -59
- package/src/browser/prefetch/queue.ts +36 -5
- package/src/browser/rango-state.ts +37 -13
- package/src/browser/react/Link.tsx +18 -13
- package/src/browser/react/NavigationProvider.tsx +75 -31
- package/src/browser/react/filter-segment-order.ts +51 -7
- package/src/browser/react/index.ts +3 -0
- package/src/browser/react/location-state-shared.ts +175 -4
- package/src/browser/react/location-state.ts +39 -13
- package/src/browser/react/use-handle.ts +17 -9
- package/src/browser/react/use-navigation.ts +22 -2
- package/src/browser/react/use-params.ts +20 -8
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +23 -2
- package/src/browser/react/use-segments.ts +11 -8
- package/src/browser/response-adapter.ts +52 -1
- package/src/browser/rsc-router.tsx +71 -22
- package/src/browser/scroll-restoration.ts +22 -14
- package/src/browser/segment-reconciler.ts +10 -14
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +44 -30
- package/src/browser/types.ts +12 -2
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +60 -35
- package/src/build/generate-route-types.ts +2 -0
- package/src/build/index.ts +8 -1
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +45 -1
- package/src/build/route-types/codegen.ts +4 -4
- package/src/build/route-types/include-resolution.ts +1 -1
- package/src/build/route-types/per-module-writer.ts +7 -4
- package/src/build/route-types/router-processing.ts +55 -14
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-runtime.ts +17 -5
- package/src/cache/cache-scope.ts +51 -49
- package/src/cache/cf/cf-cache-store.ts +502 -32
- package/src/cache/cf/index.ts +3 -0
- package/src/cache/handle-snapshot.ts +103 -0
- package/src/cache/index.ts +3 -0
- package/src/cache/memory-segment-store.ts +3 -2
- package/src/cache/types.ts +10 -6
- package/src/client.rsc.tsx +3 -0
- package/src/client.tsx +96 -205
- package/src/context-var.ts +5 -5
- package/src/decode-loader-results.ts +36 -0
- package/src/errors.ts +30 -4
- package/src/handle.ts +4 -6
- package/src/host/index.ts +2 -2
- package/src/host/router.ts +129 -57
- package/src/host/types.ts +31 -2
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +140 -21
- package/src/index.rsc.ts +10 -6
- package/src/index.ts +17 -8
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +2 -5
- package/src/loader.ts +3 -10
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/prerender/store.ts +9 -7
- package/src/prerender.ts +4 -4
- package/src/response-utils.ts +37 -0
- package/src/reverse.ts +65 -39
- package/src/route-content-wrapper.tsx +6 -28
- package/src/route-definition/dsl-helpers.ts +253 -265
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +43 -15
- package/src/route-definition/resolve-handler-use.ts +6 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-types.ts +26 -41
- package/src/router/content-negotiation.ts +15 -2
- package/src/router/error-handling.ts +1 -1
- package/src/router/find-match.ts +54 -6
- package/src/router/handler-context.ts +21 -41
- package/src/router/intercept-resolution.ts +4 -18
- package/src/router/lazy-includes.ts +41 -22
- package/src/router/loader-resolution.ts +82 -36
- package/src/router/manifest.ts +41 -19
- package/src/router/match-api.ts +4 -3
- package/src/router/match-handlers.ts +1 -0
- package/src/router/match-middleware/cache-lookup.ts +57 -95
- package/src/router/match-middleware/cache-store.ts +3 -2
- package/src/router/match-result.ts +53 -32
- package/src/router/metrics.ts +1 -1
- package/src/router/middleware-types.ts +15 -26
- package/src/router/middleware.ts +99 -84
- package/src/router/pattern-matching.ts +116 -19
- package/src/router/prerender-match.ts +40 -15
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +40 -37
- package/src/router/revalidation.ts +58 -2
- package/src/router/router-interfaces.ts +51 -35
- package/src/router/router-options.ts +25 -1
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +27 -6
- package/src/router/segment-resolution/revalidation.ts +147 -106
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/trie-matching.ts +40 -16
- package/src/router/types.ts +8 -0
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +37 -25
- package/src/rsc/handler-context.ts +2 -2
- package/src/rsc/handler.ts +58 -77
- package/src/rsc/helpers.ts +72 -43
- package/src/rsc/index.ts +1 -1
- package/src/rsc/manifest-init.ts +28 -41
- package/src/rsc/origin-guard.ts +30 -10
- package/src/rsc/progressive-enhancement.ts +4 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +76 -61
- package/src/rsc/rsc-rendering.ts +45 -51
- package/src/rsc/runtime-warnings.ts +9 -10
- package/src/rsc/server-action.ts +33 -39
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/types.ts +8 -2
- package/src/search-params.ts +4 -4
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +132 -116
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +175 -53
- package/src/server/cookie-store.ts +28 -4
- package/src/server/request-context.ts +57 -51
- package/src/ssr/index.tsx +5 -1
- package/src/static-handler.ts +1 -1
- package/src/types/global-namespace.ts +39 -26
- package/src/types/handler-context.ts +68 -50
- package/src/types/index.ts +1 -0
- package/src/types/loader-types.ts +11 -9
- package/src/types/request-scope.ts +126 -0
- package/src/types/route-entry.ts +11 -0
- package/src/types/segments.ts +35 -2
- package/src/urls/include-helper.ts +34 -67
- package/src/urls/index.ts +1 -5
- package/src/urls/path-helper-types.ts +17 -3
- package/src/urls/path-helper.ts +17 -52
- package/src/urls/pattern-types.ts +36 -19
- package/src/urls/response-types.ts +22 -29
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -5
- package/src/use-loader.tsx +413 -42
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +6 -6
- package/src/vite/discovery/discover-routers.ts +106 -75
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +72 -31
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +33 -0
- package/src/vite/discovery/virtual-module-codegen.ts +13 -23
- package/src/vite/index.ts +2 -0
- package/src/vite/plugin-types.ts +67 -0
- package/src/vite/plugins/cjs-to-esm.ts +8 -7
- package/src/vite/plugins/client-ref-dedup.ts +16 -0
- package/src/vite/plugins/client-ref-hashing.ts +28 -5
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
- package/src/vite/plugins/expose-action-id.ts +54 -30
- package/src/vite/plugins/expose-id-utils.ts +12 -8
- package/src/vite/plugins/expose-ids/export-analysis.ts +100 -20
- package/src/vite/plugins/expose-ids/handler-transform.ts +8 -61
- package/src/vite/plugins/expose-ids/loader-transform.ts +3 -5
- package/src/vite/plugins/expose-ids/router-transform.ts +20 -3
- package/src/vite/plugins/expose-internal-ids.ts +496 -486
- package/src/vite/plugins/performance-tracks.ts +29 -25
- package/src/vite/plugins/use-cache-transform.ts +65 -50
- package/src/vite/plugins/version-injector.ts +39 -23
- package/src/vite/plugins/version-plugin.ts +59 -2
- package/src/vite/plugins/virtual-entries.ts +2 -2
- package/src/vite/rango.ts +116 -29
- package/src/vite/router-discovery.ts +753 -104
- package/src/vite/utils/ast-handler-extract.ts +15 -15
- package/src/vite/utils/banner.ts +1 -1
- package/src/vite/utils/bundle-analysis.ts +4 -2
- package/src/vite/utils/client-chunks.ts +190 -0
- package/src/vite/utils/forward-user-plugins.ts +193 -0
- package/src/vite/utils/manifest-utils.ts +8 -59
- package/src/vite/utils/package-resolution.ts +41 -1
- package/src/vite/utils/prerender-utils.ts +5 -4
- package/src/vite/utils/shared-utils.ts +107 -26
- package/src/browser/action-response-classifier.ts +0 -99
package/dist/vite/index.js
CHANGED
|
@@ -21,8 +21,8 @@ function hashId(filePath, exportName) {
|
|
|
21
21
|
function makeStubId(filePath, exportName, isBuild) {
|
|
22
22
|
return isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
|
|
23
23
|
}
|
|
24
|
-
function hashInlineId(filePath,
|
|
25
|
-
const input =
|
|
24
|
+
function hashInlineId(filePath, fnName, index) {
|
|
25
|
+
const input = `${filePath}:${fnName}:${index}`;
|
|
26
26
|
return crypto.createHash("sha256").update(input).digest("hex").slice(0, 8);
|
|
27
27
|
}
|
|
28
28
|
function buildExportMap(program) {
|
|
@@ -191,7 +191,100 @@ function escapeRegExp(input) {
|
|
|
191
191
|
return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
// src/vite/debug.ts
|
|
195
|
+
import debugFactory from "debug";
|
|
196
|
+
var NS = {
|
|
197
|
+
config: "rango:config",
|
|
198
|
+
discovery: "rango:discovery",
|
|
199
|
+
routes: "rango:routes",
|
|
200
|
+
prerender: "rango:prerender",
|
|
201
|
+
build: "rango:build",
|
|
202
|
+
dev: "rango:dev",
|
|
203
|
+
transform: "rango:transform",
|
|
204
|
+
chunks: "rango:chunks"
|
|
205
|
+
};
|
|
206
|
+
if (process.env.INTERNAL_RANGO_DEBUG) {
|
|
207
|
+
const existing = debugFactory.disable();
|
|
208
|
+
debugFactory.enable(existing ? `${existing},rango:*` : "rango:*");
|
|
209
|
+
}
|
|
210
|
+
function createRangoDebugger(namespace) {
|
|
211
|
+
const primary = debugFactory(namespace);
|
|
212
|
+
const shadow = debugFactory(`vite:${namespace}`);
|
|
213
|
+
if (primary.enabled) return primary;
|
|
214
|
+
if (shadow.enabled) return shadow;
|
|
215
|
+
return void 0;
|
|
216
|
+
}
|
|
217
|
+
async function timed(debug11, label, fn) {
|
|
218
|
+
if (!debug11) return await fn();
|
|
219
|
+
const start = performance.now();
|
|
220
|
+
try {
|
|
221
|
+
return await fn();
|
|
222
|
+
} finally {
|
|
223
|
+
debug11("%s (%sms)", label, (performance.now() - start).toFixed(1));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function timedSync(debug11, label, fn) {
|
|
227
|
+
if (!debug11) return fn();
|
|
228
|
+
const start = performance.now();
|
|
229
|
+
try {
|
|
230
|
+
return fn();
|
|
231
|
+
} finally {
|
|
232
|
+
debug11("%s (%sms)", label, (performance.now() - start).toFixed(1));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function createCounter(debug11, label) {
|
|
236
|
+
if (!debug11) return void 0;
|
|
237
|
+
let n = 0;
|
|
238
|
+
let totalMs = 0;
|
|
239
|
+
let slowestMs = 0;
|
|
240
|
+
let slowestFile = "";
|
|
241
|
+
const record = (file, ms) => {
|
|
242
|
+
n++;
|
|
243
|
+
totalMs += ms;
|
|
244
|
+
if (ms > slowestMs) {
|
|
245
|
+
slowestMs = ms;
|
|
246
|
+
slowestFile = file;
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
return {
|
|
250
|
+
record,
|
|
251
|
+
time(file, fn) {
|
|
252
|
+
const start = performance.now();
|
|
253
|
+
let out;
|
|
254
|
+
try {
|
|
255
|
+
out = fn();
|
|
256
|
+
} catch (err) {
|
|
257
|
+
record(file, performance.now() - start);
|
|
258
|
+
throw err;
|
|
259
|
+
}
|
|
260
|
+
if (out && typeof out.then === "function") {
|
|
261
|
+
return out.finally(
|
|
262
|
+
() => record(file, performance.now() - start)
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
record(file, performance.now() - start);
|
|
266
|
+
return out;
|
|
267
|
+
},
|
|
268
|
+
flush() {
|
|
269
|
+
if (n === 0) return;
|
|
270
|
+
debug11(
|
|
271
|
+
"%s: %d files, %sms total, slowest %sms %s",
|
|
272
|
+
label,
|
|
273
|
+
n,
|
|
274
|
+
totalMs.toFixed(1),
|
|
275
|
+
slowestMs.toFixed(1),
|
|
276
|
+
slowestFile
|
|
277
|
+
);
|
|
278
|
+
n = 0;
|
|
279
|
+
totalMs = 0;
|
|
280
|
+
slowestMs = 0;
|
|
281
|
+
slowestFile = "";
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
194
286
|
// src/vite/plugins/expose-action-id.ts
|
|
287
|
+
var debug = createRangoDebugger(NS.transform);
|
|
195
288
|
function getRscPluginApi(config) {
|
|
196
289
|
let plugin = config.plugins.find((p) => p.name === "rsc:minimal");
|
|
197
290
|
if (!plugin) {
|
|
@@ -200,7 +293,7 @@ function getRscPluginApi(config) {
|
|
|
200
293
|
);
|
|
201
294
|
if (plugin) {
|
|
202
295
|
console.warn(
|
|
203
|
-
`[
|
|
296
|
+
`[rango:expose-action-id] RSC plugin found by API structure (name: "${plugin.name}"). Consider updating the name lookup if the plugin was renamed.`
|
|
204
297
|
);
|
|
205
298
|
}
|
|
206
299
|
}
|
|
@@ -280,6 +373,8 @@ function exposeActionId() {
|
|
|
280
373
|
let isBuild = false;
|
|
281
374
|
let hashToFileMap;
|
|
282
375
|
let rscPluginApi;
|
|
376
|
+
const counterTransform = createCounter(debug, "expose-action-id transform");
|
|
377
|
+
const counterRender = createCounter(debug, "expose-action-id renderChunk");
|
|
283
378
|
return {
|
|
284
379
|
name: "@rangojs/router:expose-action-id",
|
|
285
380
|
// Run after all other plugins (including RSC plugin's transforms)
|
|
@@ -289,13 +384,17 @@ function exposeActionId() {
|
|
|
289
384
|
isBuild = config.command === "build";
|
|
290
385
|
rscPluginApi = getRscPluginApi(config);
|
|
291
386
|
},
|
|
387
|
+
buildEnd() {
|
|
388
|
+
counterTransform?.flush();
|
|
389
|
+
counterRender?.flush();
|
|
390
|
+
},
|
|
292
391
|
buildStart() {
|
|
293
392
|
if (!rscPluginApi) {
|
|
294
393
|
rscPluginApi = getRscPluginApi(config);
|
|
295
394
|
}
|
|
296
395
|
if (!rscPluginApi) {
|
|
297
396
|
throw new Error(
|
|
298
|
-
"[
|
|
397
|
+
"[rango] Could not find @vitejs/plugin-rsc. @rangojs/router requires the Vite RSC plugin, which is included automatically by rango()."
|
|
299
398
|
);
|
|
300
399
|
}
|
|
301
400
|
if (!isBuild) return;
|
|
@@ -325,35 +424,49 @@ function exposeActionId() {
|
|
|
325
424
|
if (id.includes("/node_modules/")) {
|
|
326
425
|
return;
|
|
327
426
|
}
|
|
328
|
-
|
|
427
|
+
const start = counterTransform ? performance.now() : 0;
|
|
428
|
+
try {
|
|
429
|
+
return transformServerReferences(code, id);
|
|
430
|
+
} finally {
|
|
431
|
+
counterTransform?.record(id, performance.now() - start);
|
|
432
|
+
}
|
|
329
433
|
},
|
|
330
434
|
// Build mode: renderChunk runs after all transforms and bundling complete
|
|
331
435
|
renderChunk(code, chunk) {
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
code
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
436
|
+
const start = counterRender ? performance.now() : 0;
|
|
437
|
+
try {
|
|
438
|
+
const isRscEnv = this.environment?.name === "rsc";
|
|
439
|
+
const effectiveMap = isRscEnv ? hashToFileMap : void 0;
|
|
440
|
+
if (isRscEnv && hashToFileMap) {
|
|
441
|
+
const s = new MagicString(code);
|
|
442
|
+
const changed1 = applyServerReferenceWrapping(code, s, effectiveMap);
|
|
443
|
+
const changed2 = applyRegisterReferenceWrapping(
|
|
444
|
+
code,
|
|
445
|
+
s,
|
|
446
|
+
hashToFileMap
|
|
447
|
+
);
|
|
448
|
+
if (changed1 || changed2) {
|
|
449
|
+
return {
|
|
450
|
+
code: s.toString(),
|
|
451
|
+
map: s.generateMap({
|
|
452
|
+
source: chunk.fileName,
|
|
453
|
+
includeContent: true
|
|
454
|
+
})
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
return null;
|
|
346
458
|
}
|
|
347
|
-
return
|
|
459
|
+
return transformServerReferences(code, chunk.fileName, effectiveMap);
|
|
460
|
+
} finally {
|
|
461
|
+
counterRender?.record(chunk.fileName, performance.now() - start);
|
|
348
462
|
}
|
|
349
|
-
return transformServerReferences(code, chunk.fileName, effectiveMap);
|
|
350
463
|
}
|
|
351
464
|
};
|
|
352
465
|
}
|
|
353
466
|
|
|
354
467
|
// src/vite/plugins/expose-internal-ids.ts
|
|
355
468
|
import { parseAst as parseAst2 } from "vite";
|
|
356
|
-
import
|
|
469
|
+
import MagicString3 from "magic-string";
|
|
357
470
|
import path4 from "node:path";
|
|
358
471
|
|
|
359
472
|
// src/vite/utils/ast-handler-extract.ts
|
|
@@ -363,7 +476,7 @@ function isDirectivePrologueStatement(node) {
|
|
|
363
476
|
function findImportInsertionPos(code, parseAst4) {
|
|
364
477
|
let program;
|
|
365
478
|
try {
|
|
366
|
-
program = parseAst4(code, {
|
|
479
|
+
program = parseAst4(code, { lang: "tsx" });
|
|
367
480
|
} catch {
|
|
368
481
|
return 0;
|
|
369
482
|
}
|
|
@@ -403,7 +516,7 @@ function walkNode(node, parent, ancestors, enter) {
|
|
|
403
516
|
function findHandlerCalls(code, fnName, parseAst4) {
|
|
404
517
|
let program;
|
|
405
518
|
try {
|
|
406
|
-
program = parseAst4(code, {
|
|
519
|
+
program = parseAst4(code, { lang: "tsx" });
|
|
407
520
|
} catch {
|
|
408
521
|
return [];
|
|
409
522
|
}
|
|
@@ -477,7 +590,7 @@ function getImportedLocalNamesFromProgram(program, importedName) {
|
|
|
477
590
|
}
|
|
478
591
|
function getImportedLocalNames(code, importedName, parseAst4) {
|
|
479
592
|
try {
|
|
480
|
-
const program = parseAst4(code, {
|
|
593
|
+
const program = parseAst4(code, { lang: "tsx" });
|
|
481
594
|
return getImportedLocalNamesFromProgram(program, importedName);
|
|
482
595
|
} catch {
|
|
483
596
|
return /* @__PURE__ */ new Set();
|
|
@@ -486,7 +599,7 @@ function getImportedLocalNames(code, importedName, parseAst4) {
|
|
|
486
599
|
function extractImportDeclarations(code, parseAst4) {
|
|
487
600
|
let program;
|
|
488
601
|
try {
|
|
489
|
-
program = parseAst4(code, {
|
|
602
|
+
program = parseAst4(code, { lang: "tsx" });
|
|
490
603
|
} catch {
|
|
491
604
|
return [];
|
|
492
605
|
}
|
|
@@ -541,7 +654,7 @@ function isSafeVariableDeclaration(node, handlerNames) {
|
|
|
541
654
|
function extractModuleLevelDeclarations(code, parseAst4, handlerNames) {
|
|
542
655
|
let program;
|
|
543
656
|
try {
|
|
544
|
-
program = parseAst4(code, {
|
|
657
|
+
program = parseAst4(code, { lang: "tsx" });
|
|
545
658
|
} catch {
|
|
546
659
|
return [];
|
|
547
660
|
}
|
|
@@ -585,14 +698,12 @@ function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtu
|
|
|
585
698
|
parseAst4,
|
|
586
699
|
handlerNames
|
|
587
700
|
);
|
|
588
|
-
const lineCounts = /* @__PURE__ */ new Map();
|
|
589
701
|
const importStatements = [];
|
|
590
|
-
for (const site of inlineSites) {
|
|
591
|
-
const
|
|
592
|
-
lineCounts.set(site.lineNumber, lineCount + 1);
|
|
593
|
-
const hash = hashInlineId(filePath, site.lineNumber, lineCount);
|
|
702
|
+
for (const [siteIndex, site] of inlineSites.entries()) {
|
|
703
|
+
const hash = hashInlineId(filePath, fnName, siteIndex);
|
|
594
704
|
const exportName = `__sh_${hash}`;
|
|
595
|
-
const
|
|
705
|
+
const idSuffix = `${filePath}:${fnName}:${siteIndex}`;
|
|
706
|
+
const virtualId = `\0${virtualPrefix}${idSuffix}`;
|
|
596
707
|
const handlerCode = code.slice(site.callStart, site.callEnd);
|
|
597
708
|
virtualRegistry.set(virtualId, {
|
|
598
709
|
originalModuleId: moduleId,
|
|
@@ -602,7 +713,7 @@ function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtu
|
|
|
602
713
|
exportName
|
|
603
714
|
});
|
|
604
715
|
s.overwrite(site.callStart, site.callEnd, exportName);
|
|
605
|
-
const importId = `${virtualPrefix}${
|
|
716
|
+
const importId = `${virtualPrefix}${idSuffix}`;
|
|
606
717
|
importStatements.push(`import { ${exportName} } from "${importId}";`);
|
|
607
718
|
}
|
|
608
719
|
if (importStatements.length > 0) {
|
|
@@ -634,6 +745,83 @@ var STRICT_CREATE_CONFIGS = [
|
|
|
634
745
|
|
|
635
746
|
// src/vite/plugins/expose-ids/export-analysis.ts
|
|
636
747
|
import { parseAst } from "vite";
|
|
748
|
+
|
|
749
|
+
// src/build/route-types/source-scan.ts
|
|
750
|
+
function isLineTerminator(ch) {
|
|
751
|
+
const c = ch.charCodeAt(0);
|
|
752
|
+
return c === 10 || c === 13 || c === 8232 || c === 8233;
|
|
753
|
+
}
|
|
754
|
+
function makeCodeClassifier(code) {
|
|
755
|
+
const n = code.length;
|
|
756
|
+
let i = 0;
|
|
757
|
+
let skipStart = -1;
|
|
758
|
+
let skipEnd = -1;
|
|
759
|
+
return (q) => {
|
|
760
|
+
if (q >= skipStart && q < skipEnd) return false;
|
|
761
|
+
while (i < n && i <= q) {
|
|
762
|
+
const c = code[i];
|
|
763
|
+
const d = i + 1 < n ? code[i + 1] : "";
|
|
764
|
+
let end = -1;
|
|
765
|
+
if (c === "/" && d === "/") {
|
|
766
|
+
let j = i + 2;
|
|
767
|
+
while (j < n && !isLineTerminator(code[j])) j++;
|
|
768
|
+
end = j;
|
|
769
|
+
} else if (c === "/" && d === "*") {
|
|
770
|
+
let j = i + 2;
|
|
771
|
+
while (j < n && !(code[j] === "*" && code[j + 1] === "/")) j++;
|
|
772
|
+
end = Math.min(n, j + 2);
|
|
773
|
+
} else if (c === '"' || c === "'" || c === "`") {
|
|
774
|
+
let j = i + 1;
|
|
775
|
+
while (j < n) {
|
|
776
|
+
if (code[j] === "\\") {
|
|
777
|
+
j += 2;
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
if (code[j] === c) {
|
|
781
|
+
j++;
|
|
782
|
+
break;
|
|
783
|
+
}
|
|
784
|
+
j++;
|
|
785
|
+
}
|
|
786
|
+
end = j;
|
|
787
|
+
}
|
|
788
|
+
if (end >= 0) {
|
|
789
|
+
if (q < end) {
|
|
790
|
+
skipStart = i;
|
|
791
|
+
skipEnd = end;
|
|
792
|
+
return false;
|
|
793
|
+
}
|
|
794
|
+
i = end;
|
|
795
|
+
} else {
|
|
796
|
+
i++;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
return true;
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
function firstCodeMatchIndex(code, pattern) {
|
|
803
|
+
const inCode = makeCodeClassifier(code);
|
|
804
|
+
pattern.lastIndex = 0;
|
|
805
|
+
let m;
|
|
806
|
+
while ((m = pattern.exec(code)) !== null) {
|
|
807
|
+
if (inCode(m.index)) return m.index;
|
|
808
|
+
if (pattern.lastIndex <= m.index) pattern.lastIndex = m.index + 1;
|
|
809
|
+
}
|
|
810
|
+
return -1;
|
|
811
|
+
}
|
|
812
|
+
function codeMatchIndices(code, pattern) {
|
|
813
|
+
const inCode = makeCodeClassifier(code);
|
|
814
|
+
const indices = [];
|
|
815
|
+
pattern.lastIndex = 0;
|
|
816
|
+
let m;
|
|
817
|
+
while ((m = pattern.exec(code)) !== null) {
|
|
818
|
+
if (inCode(m.index)) indices.push(m.index);
|
|
819
|
+
if (pattern.lastIndex <= m.index) pattern.lastIndex = m.index + 1;
|
|
820
|
+
}
|
|
821
|
+
return indices;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// src/vite/plugins/expose-ids/export-analysis.ts
|
|
637
825
|
function isExportOnlyFile(code, bindings) {
|
|
638
826
|
if (bindings.length === 0) return false;
|
|
639
827
|
const knownLocals = /* @__PURE__ */ new Set();
|
|
@@ -662,12 +850,30 @@ function isExportOnlyFile(code, bindings) {
|
|
|
662
850
|
}
|
|
663
851
|
return true;
|
|
664
852
|
}
|
|
665
|
-
function
|
|
666
|
-
|
|
853
|
+
function createCallPattern(fnNames) {
|
|
854
|
+
return new RegExp(
|
|
667
855
|
`\\b(?:${fnNames.map(escapeRegExp).join("|")})\\s*(?:<[^>]*>\\s*)?\\(`,
|
|
668
856
|
"g"
|
|
669
857
|
);
|
|
670
|
-
|
|
858
|
+
}
|
|
859
|
+
function countCreateCallsForNames(code, fnNames) {
|
|
860
|
+
return codeMatchIndices(code, createCallPattern(fnNames)).length;
|
|
861
|
+
}
|
|
862
|
+
function offsetToLineColumn(code, index) {
|
|
863
|
+
let line = 1;
|
|
864
|
+
let lineStart = 0;
|
|
865
|
+
const end = Math.min(index, code.length);
|
|
866
|
+
for (let i = 0; i < end; i++) {
|
|
867
|
+
if (code[i] === "\n") {
|
|
868
|
+
line++;
|
|
869
|
+
lineStart = i + 1;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
return { line, column: index - lineStart + 1 };
|
|
873
|
+
}
|
|
874
|
+
function findUnsupportedCreateCallSites(code, fnNames, supportedBindings) {
|
|
875
|
+
const supported = new Set(supportedBindings.map((b) => b.callExprStart));
|
|
876
|
+
return codeMatchIndices(code, createCallPattern(fnNames)).filter((index) => !supported.has(index)).map((index) => offsetToLineColumn(code, index));
|
|
671
877
|
}
|
|
672
878
|
function getImportedFnNames(code, importedName) {
|
|
673
879
|
const importPattern = /import\s*\{([^}]*)\}\s*from\s*["']@rangojs\/router(?:\/[^"']*)?["']/g;
|
|
@@ -698,6 +904,17 @@ function getCalledIdentifierFromCall(callExpr) {
|
|
|
698
904
|
}
|
|
699
905
|
return null;
|
|
700
906
|
}
|
|
907
|
+
function unwrapSignatureWrappedCall(init, fnNameSet) {
|
|
908
|
+
if (init?.type !== "CallExpression") return init;
|
|
909
|
+
const directId = getCalledIdentifierFromCall(init);
|
|
910
|
+
if (directId && fnNameSet.has(directId)) return init;
|
|
911
|
+
const firstArg = init.arguments?.[0];
|
|
912
|
+
if (firstArg?.type === "CallExpression") {
|
|
913
|
+
const innerId = getCalledIdentifierFromCall(firstArg);
|
|
914
|
+
if (innerId && fnNameSet.has(innerId)) return firstArg;
|
|
915
|
+
}
|
|
916
|
+
return init;
|
|
917
|
+
}
|
|
701
918
|
function collectCreateExportBindingsFallback(code, fnNames) {
|
|
702
919
|
const alternation = fnNames.map(escapeRegExp).join("|");
|
|
703
920
|
const exportConstPattern = new RegExp(
|
|
@@ -757,7 +974,7 @@ function collectCreateExportBindingsFallback(code, fnNames) {
|
|
|
757
974
|
function collectCreateExportBindings(code, fnNames, program) {
|
|
758
975
|
if (!program) {
|
|
759
976
|
try {
|
|
760
|
-
program = parseAst(code, {
|
|
977
|
+
program = parseAst(code, { lang: "tsx" });
|
|
761
978
|
} catch {
|
|
762
979
|
return collectCreateExportBindingsFallback(code, fnNames);
|
|
763
980
|
}
|
|
@@ -770,16 +987,16 @@ function collectCreateExportBindings(code, fnNames, program) {
|
|
|
770
987
|
return;
|
|
771
988
|
}
|
|
772
989
|
for (const decl of varDecl.declarations ?? []) {
|
|
773
|
-
const
|
|
774
|
-
|
|
990
|
+
const callExpr = unwrapSignatureWrappedCall(decl?.init, fnNameSet);
|
|
991
|
+
const calledIdentifier = getCalledIdentifierFromCall(callExpr);
|
|
992
|
+
if (decl?.id?.type !== "Identifier" || callExpr?.type !== "CallExpression" || !calledIdentifier || !fnNameSet.has(calledIdentifier)) {
|
|
775
993
|
continue;
|
|
776
994
|
}
|
|
777
995
|
const localName = decl.id.name;
|
|
778
996
|
const exportNames = exportMap.get(localName) ?? [];
|
|
779
997
|
if (exportNames.length === 0) continue;
|
|
780
|
-
const
|
|
781
|
-
const
|
|
782
|
-
const calleeEnd = decl.init.callee.end;
|
|
998
|
+
const callEnd = callExpr.end;
|
|
999
|
+
const calleeEnd = callExpr.callee.end;
|
|
783
1000
|
let openParenPos = -1;
|
|
784
1001
|
for (let i = calleeEnd; i < callEnd; i++) {
|
|
785
1002
|
if (code[i] === "(") {
|
|
@@ -793,10 +1010,10 @@ function collectCreateExportBindings(code, fnNames, program) {
|
|
|
793
1010
|
bindings.push({
|
|
794
1011
|
localName,
|
|
795
1012
|
exportNames,
|
|
796
|
-
callExprStart:
|
|
1013
|
+
callExprStart: callExpr.start,
|
|
797
1014
|
callOpenParenPos: openParenPos,
|
|
798
1015
|
callCloseParenPos: closeParenPos,
|
|
799
|
-
argCount:
|
|
1016
|
+
argCount: callExpr.arguments?.length ?? 0,
|
|
800
1017
|
statementEnd
|
|
801
1018
|
});
|
|
802
1019
|
}
|
|
@@ -815,9 +1032,20 @@ function collectCreateExportBindings(code, fnNames, program) {
|
|
|
815
1032
|
}
|
|
816
1033
|
return bindings;
|
|
817
1034
|
}
|
|
818
|
-
function buildUnsupportedShapeWarning(filePath, fnName) {
|
|
819
|
-
|
|
820
|
-
|
|
1035
|
+
function buildUnsupportedShapeWarning(filePath, fnName, sites = []) {
|
|
1036
|
+
const lines = [`[rango] Unsupported ${fnName} shape in "${filePath}".`];
|
|
1037
|
+
if (sites.length === 1) {
|
|
1038
|
+
const s = sites[0];
|
|
1039
|
+
lines.push(
|
|
1040
|
+
`The ${fnName}(...) call at ${filePath}:${s.line}:${s.column} has no stable $$id injected \u2014 it is not in a supported shape.`
|
|
1041
|
+
);
|
|
1042
|
+
} else if (sites.length > 1) {
|
|
1043
|
+
lines.push(
|
|
1044
|
+
`These ${fnName}(...) calls have no stable $$id injected \u2014 they are not in a supported shape:`
|
|
1045
|
+
);
|
|
1046
|
+
for (const s of sites) lines.push(` - ${filePath}:${s.line}:${s.column}`);
|
|
1047
|
+
}
|
|
1048
|
+
lines.push(
|
|
821
1049
|
`Supported shapes are:`,
|
|
822
1050
|
` - export const X = ${fnName}(...)`,
|
|
823
1051
|
` - const X = ${fnName}(...); export { X }`,
|
|
@@ -825,7 +1053,8 @@ function buildUnsupportedShapeWarning(filePath, fnName) {
|
|
|
825
1053
|
`Potentially unsupported forms include:`,
|
|
826
1054
|
` - export let/var X = ${fnName}(...)`,
|
|
827
1055
|
` - inline ${fnName}(...) calls`
|
|
828
|
-
|
|
1056
|
+
);
|
|
1057
|
+
return lines.join("\n");
|
|
829
1058
|
}
|
|
830
1059
|
|
|
831
1060
|
// src/vite/plugins/expose-ids/loader-transform.ts
|
|
@@ -839,7 +1068,7 @@ function generateClientLoaderStubs(bindings, code, filePath, isBuild) {
|
|
|
839
1068
|
const lines = [];
|
|
840
1069
|
for (const binding of bindings) {
|
|
841
1070
|
for (const name of binding.exportNames) {
|
|
842
|
-
const loaderId =
|
|
1071
|
+
const loaderId = makeStubId(filePath, name, isBuild);
|
|
843
1072
|
lines.push(
|
|
844
1073
|
`export const ${name} = { __brand: "loader", $$id: "${loaderId}" };`
|
|
845
1074
|
);
|
|
@@ -851,7 +1080,7 @@ function transformLoaders(bindings, s, filePath, isBuild) {
|
|
|
851
1080
|
let hasChanges = false;
|
|
852
1081
|
for (const binding of bindings) {
|
|
853
1082
|
const exportName = binding.exportNames[0];
|
|
854
|
-
const loaderId =
|
|
1083
|
+
const loaderId = makeStubId(filePath, exportName, isBuild);
|
|
855
1084
|
const paramInjection = binding.argCount === 1 ? `, undefined, "${loaderId}"` : `, "${loaderId}"`;
|
|
856
1085
|
s.appendLeft(binding.callCloseParenPos, paramInjection);
|
|
857
1086
|
const propInjection = `
|
|
@@ -863,7 +1092,6 @@ ${binding.localName}.$$id = "${loaderId}";`;
|
|
|
863
1092
|
}
|
|
864
1093
|
|
|
865
1094
|
// src/vite/plugins/expose-ids/handler-transform.ts
|
|
866
|
-
import MagicString2 from "magic-string";
|
|
867
1095
|
function analyzeCreateHandleArgs(code, startPos, endPos) {
|
|
868
1096
|
const content = code.slice(startPos, endPos).trim();
|
|
869
1097
|
return { hasArgs: content.length > 0 };
|
|
@@ -877,7 +1105,7 @@ function transformHandles(bindings, s, code, filePath, isBuild) {
|
|
|
877
1105
|
binding.callOpenParenPos + 1,
|
|
878
1106
|
binding.callCloseParenPos
|
|
879
1107
|
);
|
|
880
|
-
const handleId =
|
|
1108
|
+
const handleId = makeStubId(filePath, exportName, isBuild);
|
|
881
1109
|
let paramInjection;
|
|
882
1110
|
if (!args.hasArgs) {
|
|
883
1111
|
paramInjection = `undefined, "${handleId}"`;
|
|
@@ -896,7 +1124,7 @@ function transformLocationState(bindings, s, filePath, isBuild) {
|
|
|
896
1124
|
let hasChanges = false;
|
|
897
1125
|
for (const binding of bindings) {
|
|
898
1126
|
const exportName = binding.exportNames[0];
|
|
899
|
-
const stateKey =
|
|
1127
|
+
const stateKey = makeStubId(filePath, exportName, isBuild);
|
|
900
1128
|
const propInjection = `
|
|
901
1129
|
${binding.localName}.__rsc_ls_key = "__rsc_ls_${stateKey}";`;
|
|
902
1130
|
s.appendRight(binding.statementEnd, propInjection);
|
|
@@ -908,7 +1136,7 @@ function generateWholeFileStubs(cfg, bindings, code, filePath, isBuild) {
|
|
|
908
1136
|
if (!isExportOnlyFile(code, bindings)) return null;
|
|
909
1137
|
const exportNames = bindings.flatMap((b) => b.exportNames);
|
|
910
1138
|
const stubs = exportNames.map((name) => {
|
|
911
|
-
const handlerId =
|
|
1139
|
+
const handlerId = makeStubId(filePath, name, isBuild);
|
|
912
1140
|
return `export const ${name} = { __brand: "${cfg.brand}", $$id: "${handlerId}" };`;
|
|
913
1141
|
});
|
|
914
1142
|
return { code: stubs.join("\n") + "\n", map: null };
|
|
@@ -917,7 +1145,7 @@ function stubHandlerExprs(cfg, bindings, s, filePath, isBuild) {
|
|
|
917
1145
|
let hasChanges = false;
|
|
918
1146
|
for (const binding of bindings) {
|
|
919
1147
|
const exportName = binding.exportNames[0];
|
|
920
|
-
const handlerId =
|
|
1148
|
+
const handlerId = makeStubId(filePath, exportName, isBuild);
|
|
921
1149
|
s.overwrite(
|
|
922
1150
|
binding.callExprStart,
|
|
923
1151
|
binding.callCloseParenPos + 1,
|
|
@@ -931,7 +1159,7 @@ function transformHandlerIds(cfg, bindings, s, filePath, isBuild) {
|
|
|
931
1159
|
let hasChanges = false;
|
|
932
1160
|
for (const binding of bindings) {
|
|
933
1161
|
const exportName = binding.exportNames[0];
|
|
934
|
-
const handlerId =
|
|
1162
|
+
const handlerId = makeStubId(filePath, exportName, isBuild);
|
|
935
1163
|
let paramInjection;
|
|
936
1164
|
if (binding.argCount === 0) {
|
|
937
1165
|
paramInjection = `undefined, "${handlerId}"`;
|
|
@@ -950,19 +1178,20 @@ ${binding.localName}.$$id = "${handlerId}";`;
|
|
|
950
1178
|
}
|
|
951
1179
|
|
|
952
1180
|
// src/vite/plugins/expose-ids/router-transform.ts
|
|
953
|
-
import
|
|
1181
|
+
import MagicString2 from "magic-string";
|
|
954
1182
|
import path3 from "node:path";
|
|
955
1183
|
import { createHash } from "node:crypto";
|
|
1184
|
+
var debug2 = createRangoDebugger(NS.transform);
|
|
956
1185
|
function transformRouter(code, filePath, routerFnNames, absolutePath) {
|
|
957
1186
|
const pat = new RegExp(
|
|
958
1187
|
`\\b(?:${routerFnNames.map((n) => n.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\s*(?:<[^>]*>)?\\s*\\(`,
|
|
959
1188
|
"g"
|
|
960
1189
|
);
|
|
961
1190
|
let match;
|
|
962
|
-
const s = new
|
|
1191
|
+
const s = new MagicString2(code);
|
|
963
1192
|
let changed = false;
|
|
964
|
-
const
|
|
965
|
-
const routeNamesImport = `./${
|
|
1193
|
+
const basename2 = path3.basename(filePath).replace(/\.(tsx?|jsx?)$/, "");
|
|
1194
|
+
const routeNamesImport = `./${basename2}.named-routes.gen.js`;
|
|
966
1195
|
const routeNamesVar = `__rsc_rn`;
|
|
967
1196
|
while ((match = pat.exec(code)) !== null) {
|
|
968
1197
|
const callStart = match.index;
|
|
@@ -995,11 +1224,15 @@ function transformRouter(code, filePath, routerFnNames, absolutePath) {
|
|
|
995
1224
|
}
|
|
996
1225
|
function exposeRouterId() {
|
|
997
1226
|
let projectRoot = "";
|
|
1227
|
+
const counter = createCounter(debug2, "expose-router-id");
|
|
998
1228
|
return {
|
|
999
1229
|
name: "@rangojs/router:expose-router-id",
|
|
1000
1230
|
configResolved(config) {
|
|
1001
1231
|
projectRoot = config.root;
|
|
1002
1232
|
},
|
|
1233
|
+
buildEnd() {
|
|
1234
|
+
counter?.flush();
|
|
1235
|
+
},
|
|
1003
1236
|
transform(code, id) {
|
|
1004
1237
|
if (!code.includes("createRouter")) return null;
|
|
1005
1238
|
if (!/import\s*\{[^}]*\bcreateRouter\b[^}]*\}\s*from\s*["']@rangojs\/router(?:\/server)?["']/.test(
|
|
@@ -1008,14 +1241,25 @@ function exposeRouterId() {
|
|
|
1008
1241
|
return null;
|
|
1009
1242
|
}
|
|
1010
1243
|
if (id.includes("node_modules")) return null;
|
|
1011
|
-
const
|
|
1012
|
-
|
|
1013
|
-
|
|
1244
|
+
const start = counter ? performance.now() : 0;
|
|
1245
|
+
try {
|
|
1246
|
+
const filePath = normalizePath(path3.relative(projectRoot, id));
|
|
1247
|
+
const routerFnNames = getImportedFnNames(code, "createRouter");
|
|
1248
|
+
return transformRouter(
|
|
1249
|
+
code,
|
|
1250
|
+
filePath,
|
|
1251
|
+
routerFnNames,
|
|
1252
|
+
normalizePath(id)
|
|
1253
|
+
);
|
|
1254
|
+
} finally {
|
|
1255
|
+
counter?.record(id, performance.now() - start);
|
|
1256
|
+
}
|
|
1014
1257
|
}
|
|
1015
1258
|
};
|
|
1016
1259
|
}
|
|
1017
1260
|
|
|
1018
1261
|
// src/vite/plugins/expose-internal-ids.ts
|
|
1262
|
+
var debug3 = createRangoDebugger(NS.transform);
|
|
1019
1263
|
var VIRTUAL_LOADER_MANIFEST = "virtual:rsc-router/loader-manifest";
|
|
1020
1264
|
var RESOLVED_VIRTUAL_LOADER_MANIFEST = "\0" + VIRTUAL_LOADER_MANIFEST;
|
|
1021
1265
|
var VIRTUAL_HANDLER_PREFIX = "virtual:handler-extract:";
|
|
@@ -1028,9 +1272,13 @@ function exposeInternalIds(options) {
|
|
|
1028
1272
|
const staticHandlerModules = /* @__PURE__ */ new Map();
|
|
1029
1273
|
const virtualHandlers = /* @__PURE__ */ new Map();
|
|
1030
1274
|
const unsupportedShapeWarnings = /* @__PURE__ */ new Set();
|
|
1275
|
+
const counter = createCounter(debug3, "expose-internal-ids");
|
|
1031
1276
|
return {
|
|
1032
1277
|
name: "@rangojs/router:expose-internal-ids",
|
|
1033
1278
|
enforce: "post",
|
|
1279
|
+
buildEnd() {
|
|
1280
|
+
counter?.flush();
|
|
1281
|
+
},
|
|
1034
1282
|
api: {
|
|
1035
1283
|
prerenderHandlerModules,
|
|
1036
1284
|
staticHandlerModules
|
|
@@ -1144,11 +1392,13 @@ ${lazyImports.join(",\n")}
|
|
|
1144
1392
|
// --------------- Unified transform ---------------
|
|
1145
1393
|
transform(code, id) {
|
|
1146
1394
|
if (id.includes("/node_modules/")) return;
|
|
1147
|
-
const
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
this.
|
|
1151
|
-
|
|
1395
|
+
const __t0 = counter ? performance.now() : 0;
|
|
1396
|
+
try {
|
|
1397
|
+
const filePath = normalizePath(path4.relative(projectRoot, id));
|
|
1398
|
+
const isRscEnv = this.environment?.name === "rsc";
|
|
1399
|
+
if (id.includes(".named-routes.gen.") && !isRscEnv && this.environment?.name === "client") {
|
|
1400
|
+
this.warn(
|
|
1401
|
+
`
|
|
1152
1402
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
1153
1403
|
!! !!
|
|
1154
1404
|
!! WARNING: NamedRoutes imported in a CLIENT component! !!
|
|
@@ -1168,367 +1418,363 @@ ${lazyImports.join(",\n")}
|
|
|
1168
1418
|
!! !!
|
|
1169
1419
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
1170
1420
|
`
|
|
1171
|
-
|
|
1172
|
-
}
|
|
1173
|
-
if (!code.includes("@rangojs/router")) return;
|
|
1174
|
-
const has = detectImports(code);
|
|
1175
|
-
const hasLoaderCode = has.loader && code.includes("createLoader");
|
|
1176
|
-
const hasHandleCode = has.handle && code.includes("createHandle");
|
|
1177
|
-
const hasLocationStateCode = has.locationState && code.includes("createLocationState");
|
|
1178
|
-
const hasPrerenderHandlerCode = has.prerenderHandler && code.includes("Prerender");
|
|
1179
|
-
const hasStaticHandlerCode = has.staticHandler && code.includes("Static");
|
|
1180
|
-
if (!hasLoaderCode && !hasHandleCode && !hasLocationStateCode && !hasPrerenderHandlerCode && !hasStaticHandlerCode) {
|
|
1181
|
-
return;
|
|
1182
|
-
}
|
|
1183
|
-
const _fnNamesCache = /* @__PURE__ */ new Map();
|
|
1184
|
-
const _bindingsCache = /* @__PURE__ */ new Map();
|
|
1185
|
-
let _cachedAst;
|
|
1186
|
-
let _astParseFailed = false;
|
|
1187
|
-
let _astCodeRef = code;
|
|
1188
|
-
const getFnNames = (canonicalName) => {
|
|
1189
|
-
let result = _fnNamesCache.get(canonicalName);
|
|
1190
|
-
if (!result) {
|
|
1191
|
-
result = getImportedFnNames(code, canonicalName);
|
|
1192
|
-
_fnNamesCache.set(canonicalName, result);
|
|
1421
|
+
);
|
|
1193
1422
|
}
|
|
1194
|
-
return
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1423
|
+
if (!code.includes("@rangojs/router")) return;
|
|
1424
|
+
const has = detectImports(code);
|
|
1425
|
+
const hasLoaderCode = has.loader && code.includes("createLoader");
|
|
1426
|
+
const hasHandleCode = has.handle && code.includes("createHandle");
|
|
1427
|
+
const hasLocationStateCode = has.locationState && code.includes("createLocationState");
|
|
1428
|
+
const hasPrerenderHandlerCode = has.prerenderHandler && code.includes("Prerender");
|
|
1429
|
+
const hasStaticHandlerCode = has.staticHandler && code.includes("Static");
|
|
1430
|
+
if (!hasLoaderCode && !hasHandleCode && !hasLocationStateCode && !hasPrerenderHandlerCode && !hasStaticHandlerCode) {
|
|
1431
|
+
return;
|
|
1201
1432
|
}
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1433
|
+
const _fnNamesCache = /* @__PURE__ */ new Map();
|
|
1434
|
+
const _bindingsCache = /* @__PURE__ */ new Map();
|
|
1435
|
+
let _cachedAst;
|
|
1436
|
+
let _astParseFailed = false;
|
|
1437
|
+
let _astCodeRef = code;
|
|
1438
|
+
const getFnNames = (canonicalName) => {
|
|
1439
|
+
let result = _fnNamesCache.get(canonicalName);
|
|
1440
|
+
if (!result) {
|
|
1441
|
+
result = getImportedFnNames(code, canonicalName);
|
|
1442
|
+
_fnNamesCache.set(canonicalName, result);
|
|
1443
|
+
}
|
|
1444
|
+
return result;
|
|
1445
|
+
};
|
|
1446
|
+
const lazyAst = () => {
|
|
1447
|
+
if (code !== _astCodeRef) {
|
|
1448
|
+
_cachedAst = void 0;
|
|
1449
|
+
_astParseFailed = false;
|
|
1450
|
+
_astCodeRef = code;
|
|
1451
|
+
}
|
|
1452
|
+
if (_cachedAst !== void 0 || _astParseFailed) return _cachedAst;
|
|
1453
|
+
try {
|
|
1454
|
+
_cachedAst = parseAst2(code, { lang: "tsx" });
|
|
1455
|
+
} catch {
|
|
1456
|
+
_astParseFailed = true;
|
|
1457
|
+
}
|
|
1458
|
+
return _cachedAst;
|
|
1459
|
+
};
|
|
1460
|
+
const getBindings = (currentCode, fnNames) => {
|
|
1461
|
+
const key = fnNames.join("\0");
|
|
1462
|
+
let result = _bindingsCache.get(key);
|
|
1463
|
+
if (!result) {
|
|
1464
|
+
result = collectCreateExportBindings(
|
|
1465
|
+
currentCode,
|
|
1466
|
+
fnNames,
|
|
1467
|
+
lazyAst()
|
|
1468
|
+
);
|
|
1469
|
+
_bindingsCache.set(key, result);
|
|
1470
|
+
}
|
|
1471
|
+
return result;
|
|
1472
|
+
};
|
|
1473
|
+
for (const cfg of STRICT_CREATE_CONFIGS) {
|
|
1474
|
+
const hasCode = cfg.fnName === "createLoader" ? hasLoaderCode : cfg.fnName === "createHandle" ? hasHandleCode : hasLocationStateCode;
|
|
1475
|
+
if (!hasCode) continue;
|
|
1476
|
+
const fnNames = getFnNames(cfg.fnName);
|
|
1477
|
+
const sites = findUnsupportedCreateCallSites(
|
|
1478
|
+
code,
|
|
1479
|
+
fnNames,
|
|
1480
|
+
getBindings(code, fnNames)
|
|
1481
|
+
);
|
|
1482
|
+
if (sites.length === 0) continue;
|
|
1483
|
+
const warnKey = `${id}::${cfg.fnName}`;
|
|
1484
|
+
if (unsupportedShapeWarnings.has(warnKey)) continue;
|
|
1485
|
+
unsupportedShapeWarnings.add(warnKey);
|
|
1486
|
+
this.warn(buildUnsupportedShapeWarning(filePath, cfg.fnName, sites));
|
|
1207
1487
|
}
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1488
|
+
if (hasLoaderCode && isRscEnv) {
|
|
1489
|
+
const fnNames = getFnNames("createLoader");
|
|
1490
|
+
const bindings = getBindings(code, fnNames);
|
|
1491
|
+
for (const binding of bindings) {
|
|
1492
|
+
const exportName = binding.exportNames[0];
|
|
1493
|
+
const hashedId = hashId(filePath, exportName);
|
|
1494
|
+
loaderRegistry.set(hashedId, {
|
|
1495
|
+
filePath,
|
|
1496
|
+
exportName
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1216
1499
|
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
const totalCalls = countCreateCallsForNames(code, fnNames);
|
|
1224
|
-
const supportedBindings = getBindings(code, fnNames).length;
|
|
1225
|
-
if (totalCalls <= supportedBindings) continue;
|
|
1226
|
-
const warnKey = `${id}::${cfg.fnName}`;
|
|
1227
|
-
if (unsupportedShapeWarnings.has(warnKey)) continue;
|
|
1228
|
-
unsupportedShapeWarnings.add(warnKey);
|
|
1229
|
-
this.warn(buildUnsupportedShapeWarning(filePath, cfg.fnName));
|
|
1230
|
-
}
|
|
1231
|
-
if (hasLoaderCode && isRscEnv) {
|
|
1232
|
-
const fnNames = getFnNames("createLoader");
|
|
1233
|
-
const bindings = getBindings(code, fnNames);
|
|
1234
|
-
for (const binding of bindings) {
|
|
1235
|
-
const exportName = binding.exportNames[0];
|
|
1236
|
-
const hashedId = hashId(filePath, exportName);
|
|
1237
|
-
loaderRegistry.set(hashedId, {
|
|
1500
|
+
if (hasLoaderCode && !isRscEnv) {
|
|
1501
|
+
const fnNames = getFnNames("createLoader");
|
|
1502
|
+
const bindings = getBindings(code, fnNames);
|
|
1503
|
+
const stubResult = generateClientLoaderStubs(
|
|
1504
|
+
bindings,
|
|
1505
|
+
code,
|
|
1238
1506
|
filePath,
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
}
|
|
1243
|
-
if (hasLoaderCode && !isRscEnv) {
|
|
1244
|
-
const fnNames = getFnNames("createLoader");
|
|
1245
|
-
const bindings = getBindings(code, fnNames);
|
|
1246
|
-
const stubResult = generateClientLoaderStubs(
|
|
1247
|
-
bindings,
|
|
1248
|
-
code,
|
|
1249
|
-
filePath,
|
|
1250
|
-
isBuild
|
|
1251
|
-
);
|
|
1252
|
-
if (stubResult) return stubResult;
|
|
1253
|
-
}
|
|
1254
|
-
if (hasPrerenderHandlerCode && !isRscEnv) {
|
|
1255
|
-
const fnNames = getFnNames(PRERENDER_CONFIG.fnName);
|
|
1256
|
-
const bindings = getBindings(code, fnNames);
|
|
1257
|
-
const wholeFile = generateWholeFileStubs(
|
|
1258
|
-
PRERENDER_CONFIG,
|
|
1259
|
-
bindings,
|
|
1260
|
-
code,
|
|
1261
|
-
filePath,
|
|
1262
|
-
isBuild
|
|
1263
|
-
);
|
|
1264
|
-
if (wholeFile) return wholeFile;
|
|
1265
|
-
}
|
|
1266
|
-
if (hasPrerenderHandlerCode && isRscEnv && isBuild) {
|
|
1267
|
-
const fnNames = getFnNames(PRERENDER_CONFIG.fnName);
|
|
1268
|
-
const exportNames = getBindings(code, fnNames).map(
|
|
1269
|
-
(b) => b.exportNames[0]
|
|
1270
|
-
);
|
|
1271
|
-
if (exportNames.length > 0) {
|
|
1272
|
-
prerenderHandlerModules.set(id, exportNames);
|
|
1507
|
+
isBuild
|
|
1508
|
+
);
|
|
1509
|
+
if (stubResult) return stubResult;
|
|
1273
1510
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
const fnNames = getFnNames(cfg.fnName);
|
|
1281
|
-
return { cfg, fnNames };
|
|
1282
|
-
});
|
|
1283
|
-
for (const { cfg, fnNames } of handlerConfigs) {
|
|
1284
|
-
const totalCalls = countCreateCallsForNames(code, fnNames);
|
|
1285
|
-
const supportedBindings = getBindings(code, fnNames).length;
|
|
1286
|
-
if (totalCalls > supportedBindings) {
|
|
1287
|
-
const iterS = new MagicString4(code);
|
|
1288
|
-
const result = transformInlineHandlers(
|
|
1289
|
-
cfg.fnName,
|
|
1290
|
-
VIRTUAL_HANDLER_PREFIX,
|
|
1291
|
-
iterS,
|
|
1511
|
+
if (hasPrerenderHandlerCode && !isRscEnv) {
|
|
1512
|
+
const fnNames = getFnNames(PRERENDER_CONFIG.fnName);
|
|
1513
|
+
const bindings = getBindings(code, fnNames);
|
|
1514
|
+
const wholeFile = generateWholeFileStubs(
|
|
1515
|
+
PRERENDER_CONFIG,
|
|
1516
|
+
bindings,
|
|
1292
1517
|
code,
|
|
1293
1518
|
filePath,
|
|
1294
|
-
|
|
1295
|
-
id,
|
|
1296
|
-
parseAst2
|
|
1519
|
+
isBuild
|
|
1297
1520
|
);
|
|
1298
|
-
if (
|
|
1299
|
-
changed = true;
|
|
1300
|
-
code = iterS.toString();
|
|
1301
|
-
_bindingsCache.clear();
|
|
1302
|
-
}
|
|
1521
|
+
if (wholeFile) return wholeFile;
|
|
1303
1522
|
}
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
allBindings.push(...getBindings(code, fnNames));
|
|
1523
|
+
let changed = false;
|
|
1524
|
+
const handlerConfigs = [
|
|
1525
|
+
hasStaticHandlerCode && STATIC_CONFIG,
|
|
1526
|
+
hasPrerenderHandlerCode && PRERENDER_CONFIG
|
|
1527
|
+
].filter((c) => !!c).map((cfg) => {
|
|
1528
|
+
const fnNames = getFnNames(cfg.fnName);
|
|
1529
|
+
return { cfg, fnNames };
|
|
1530
|
+
});
|
|
1531
|
+
for (const { cfg, fnNames } of handlerConfigs) {
|
|
1532
|
+
const totalCalls = countCreateCallsForNames(code, fnNames);
|
|
1533
|
+
const supportedBindings = getBindings(code, fnNames).length;
|
|
1534
|
+
if (totalCalls > supportedBindings) {
|
|
1535
|
+
const iterS = new MagicString3(code);
|
|
1536
|
+
const result = transformInlineHandlers(
|
|
1537
|
+
cfg.fnName,
|
|
1538
|
+
VIRTUAL_HANDLER_PREFIX,
|
|
1539
|
+
iterS,
|
|
1540
|
+
code,
|
|
1541
|
+
filePath,
|
|
1542
|
+
virtualHandlers,
|
|
1543
|
+
id,
|
|
1544
|
+
parseAst2
|
|
1545
|
+
);
|
|
1546
|
+
if (result) {
|
|
1547
|
+
changed = true;
|
|
1548
|
+
code = iterS.toString();
|
|
1549
|
+
_bindingsCache.clear();
|
|
1550
|
+
}
|
|
1333
1551
|
}
|
|
1334
1552
|
}
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
const
|
|
1338
|
-
const
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1553
|
+
if (hasStaticHandlerCode && !isRscEnv) {
|
|
1554
|
+
const fnNames = getFnNames(STATIC_CONFIG.fnName);
|
|
1555
|
+
const bindings = getBindings(code, fnNames);
|
|
1556
|
+
const wholeFile = generateWholeFileStubs(
|
|
1557
|
+
STATIC_CONFIG,
|
|
1558
|
+
bindings,
|
|
1559
|
+
code,
|
|
1560
|
+
filePath,
|
|
1561
|
+
isBuild
|
|
1562
|
+
);
|
|
1563
|
+
if (wholeFile) return wholeFile;
|
|
1564
|
+
}
|
|
1565
|
+
if (!isRscEnv && (hasPrerenderHandlerCode || hasStaticHandlerCode)) {
|
|
1566
|
+
const prerenderFnNames = hasPrerenderHandlerCode ? getFnNames(PRERENDER_CONFIG.fnName) : [];
|
|
1567
|
+
const staticFnNames = hasStaticHandlerCode ? getFnNames(STATIC_CONFIG.fnName) : [];
|
|
1568
|
+
const loaderFnNames = hasLoaderCode ? getFnNames("createLoader") : [];
|
|
1569
|
+
const handleFnNames = hasHandleCode ? getFnNames("createHandle") : [];
|
|
1570
|
+
const lsFnNames = hasLocationStateCode ? getFnNames("createLocationState") : [];
|
|
1571
|
+
const allBindings = [];
|
|
1572
|
+
for (const fnNames of [
|
|
1573
|
+
prerenderFnNames,
|
|
1574
|
+
staticFnNames,
|
|
1575
|
+
loaderFnNames,
|
|
1576
|
+
handleFnNames,
|
|
1577
|
+
lsFnNames
|
|
1578
|
+
]) {
|
|
1579
|
+
if (fnNames.length > 0) {
|
|
1580
|
+
allBindings.push(...getBindings(code, fnNames));
|
|
1345
1581
|
}
|
|
1346
1582
|
}
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1583
|
+
let canStubWholeFile = allBindings.length > 0 && isExportOnlyFile(code, allBindings);
|
|
1584
|
+
if (canStubWholeFile && (handleFnNames.length > 0 || lsFnNames.length > 0)) {
|
|
1585
|
+
const exportedLocals = new Set(allBindings.map((b) => b.localName));
|
|
1586
|
+
const strippedBindings = [];
|
|
1587
|
+
const localDeclPattern = /(?:^|;|\n)\s*(?:const|let|var|function)\s+(\w+)/g;
|
|
1588
|
+
let declMatch;
|
|
1589
|
+
while ((declMatch = localDeclPattern.exec(code)) !== null) {
|
|
1590
|
+
const name = declMatch[1];
|
|
1591
|
+
if (!exportedLocals.has(name) && !/^_c\d*$/.test(name)) {
|
|
1592
|
+
strippedBindings.push(name);
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
const importPattern = /import\s*\{([^}]*)\}\s*from\s*["'](?!@rangojs\/router)[^"']*["']/g;
|
|
1596
|
+
let importMatch;
|
|
1597
|
+
while ((importMatch = importPattern.exec(code)) !== null) {
|
|
1598
|
+
for (const spec of importMatch[1].split(",")) {
|
|
1599
|
+
const m = spec.trim().match(/^[A-Za-z_$][\w$]*(?:\s+as\s+([A-Za-z_$][\w$]*))?$/);
|
|
1600
|
+
if (m)
|
|
1601
|
+
strippedBindings.push(m[1] || m[0].trim().split(/\s/)[0]);
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
const defaultImportPattern = /import\s+([A-Za-z_$][\w$]*)\s+from\s*["'](?!@rangojs\/router)[^"']*["']/g;
|
|
1605
|
+
while ((importMatch = defaultImportPattern.exec(code)) !== null) {
|
|
1606
|
+
strippedBindings.push(importMatch[1]);
|
|
1607
|
+
}
|
|
1608
|
+
const nsImportPattern = /import\s+\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\s*["'](?!@rangojs\/router)[^"']*["']/g;
|
|
1609
|
+
while ((importMatch = nsImportPattern.exec(code)) !== null) {
|
|
1610
|
+
strippedBindings.push(importMatch[1]);
|
|
1611
|
+
}
|
|
1612
|
+
if (strippedBindings.length > 0) {
|
|
1613
|
+
const preservedBindings = allBindings.filter((b) => {
|
|
1614
|
+
const fc = code.slice(b.callExprStart, b.callOpenParenPos + 1);
|
|
1615
|
+
return handleFnNames.some((n) => fc.includes(n)) || lsFnNames.some((n) => fc.includes(n));
|
|
1616
|
+
});
|
|
1617
|
+
const strippedRe = new RegExp(
|
|
1618
|
+
`\\b(?:${strippedBindings.join("|")})\\b`
|
|
1619
|
+
);
|
|
1620
|
+
canStubWholeFile = !preservedBindings.some((b) => {
|
|
1621
|
+
const expr = code.slice(
|
|
1622
|
+
b.callExprStart,
|
|
1623
|
+
b.callCloseParenPos + 1
|
|
1624
|
+
);
|
|
1625
|
+
return strippedRe.test(expr);
|
|
1626
|
+
});
|
|
1353
1627
|
}
|
|
1354
1628
|
}
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
});
|
|
1368
|
-
const strippedRe = new RegExp(
|
|
1369
|
-
`\\b(?:${strippedBindings.join("|")})\\b`
|
|
1370
|
-
);
|
|
1371
|
-
canStubWholeFile = !preservedBindings.some((b) => {
|
|
1372
|
-
const expr = code.slice(b.callExprStart, b.callCloseParenPos + 1);
|
|
1373
|
-
return strippedRe.test(expr);
|
|
1374
|
-
});
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
if (canStubWholeFile) {
|
|
1378
|
-
const lines = [];
|
|
1379
|
-
const neededImports = [];
|
|
1380
|
-
if (handleFnNames.length > 0) neededImports.push("createHandle");
|
|
1381
|
-
if (lsFnNames.length > 0) neededImports.push("createLocationState");
|
|
1382
|
-
if (neededImports.length > 0) {
|
|
1383
|
-
lines.push(
|
|
1384
|
-
`import { ${neededImports.join(", ")} } from "@rangojs/router";`
|
|
1385
|
-
);
|
|
1386
|
-
}
|
|
1387
|
-
for (const binding of allBindings) {
|
|
1388
|
-
const fnCall = code.slice(
|
|
1389
|
-
binding.callExprStart,
|
|
1390
|
-
binding.callOpenParenPos + 1
|
|
1391
|
-
);
|
|
1392
|
-
const isHandle = handleFnNames.some((n) => fnCall.includes(n));
|
|
1393
|
-
const isLocationState = lsFnNames.some((n) => fnCall.includes(n));
|
|
1394
|
-
const primaryName = binding.exportNames[0];
|
|
1395
|
-
const stubId = makeStubId(filePath, primaryName, isBuild);
|
|
1396
|
-
if (isHandle || isLocationState) {
|
|
1397
|
-
const rawArgs = code.slice(binding.callOpenParenPos + 1, binding.callCloseParenPos).replace(/\b_c\d*\s*=\s*/g, "");
|
|
1398
|
-
const canonicalName = isHandle ? "createHandle" : "createLocationState";
|
|
1399
|
-
const activeFnNames = isHandle ? handleFnNames : lsFnNames;
|
|
1400
|
-
let rawCallee = code.slice(
|
|
1629
|
+
if (canStubWholeFile) {
|
|
1630
|
+
const lines = [];
|
|
1631
|
+
const neededImports = [];
|
|
1632
|
+
if (handleFnNames.length > 0) neededImports.push("createHandle");
|
|
1633
|
+
if (lsFnNames.length > 0) neededImports.push("createLocationState");
|
|
1634
|
+
if (neededImports.length > 0) {
|
|
1635
|
+
lines.push(
|
|
1636
|
+
`import { ${neededImports.join(", ")} } from "@rangojs/router";`
|
|
1637
|
+
);
|
|
1638
|
+
}
|
|
1639
|
+
for (const binding of allBindings) {
|
|
1640
|
+
const fnCall = code.slice(
|
|
1401
1641
|
binding.callExprStart,
|
|
1402
|
-
binding.callOpenParenPos
|
|
1642
|
+
binding.callOpenParenPos + 1
|
|
1403
1643
|
);
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1644
|
+
const isHandle = handleFnNames.some((n) => fnCall.includes(n));
|
|
1645
|
+
const isLocationState = lsFnNames.some((n) => fnCall.includes(n));
|
|
1646
|
+
const primaryName = binding.exportNames[0];
|
|
1647
|
+
const stubId = makeStubId(filePath, primaryName, isBuild);
|
|
1648
|
+
if (isHandle || isLocationState) {
|
|
1649
|
+
const rawArgs = code.slice(
|
|
1650
|
+
binding.callOpenParenPos + 1,
|
|
1651
|
+
binding.callCloseParenPos
|
|
1652
|
+
).replace(/\b_c\d*\s*=\s*/g, "");
|
|
1653
|
+
const canonicalName = isHandle ? "createHandle" : "createLocationState";
|
|
1654
|
+
const activeFnNames = isHandle ? handleFnNames : lsFnNames;
|
|
1655
|
+
let rawCallee = code.slice(
|
|
1656
|
+
binding.callExprStart,
|
|
1657
|
+
binding.callOpenParenPos
|
|
1414
1658
|
);
|
|
1415
|
-
|
|
1659
|
+
for (const alias of activeFnNames) {
|
|
1660
|
+
if (alias !== canonicalName && rawCallee.startsWith(alias)) {
|
|
1661
|
+
rawCallee = canonicalName + rawCallee.slice(alias.length);
|
|
1662
|
+
break;
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
if (isHandle) {
|
|
1666
|
+
const idParam = binding.argCount === 0 ? `undefined, "${stubId}"` : `, "${stubId}"`;
|
|
1667
|
+
lines.push(
|
|
1668
|
+
`export const ${primaryName} = ${rawCallee}(${rawArgs}${idParam});`
|
|
1669
|
+
);
|
|
1670
|
+
lines.push(`${primaryName}.$$id = "${stubId}";`);
|
|
1671
|
+
} else {
|
|
1672
|
+
lines.push(
|
|
1673
|
+
`export const ${primaryName} = ${rawCallee}(${rawArgs});`
|
|
1674
|
+
);
|
|
1675
|
+
lines.push(
|
|
1676
|
+
`${primaryName}.__rsc_ls_key = "__rsc_ls_${stubId}";`
|
|
1677
|
+
);
|
|
1678
|
+
}
|
|
1679
|
+
for (const name of binding.exportNames.slice(1)) {
|
|
1680
|
+
lines.push(`export const ${name} = ${primaryName};`);
|
|
1681
|
+
}
|
|
1416
1682
|
} else {
|
|
1683
|
+
let brand = "loader";
|
|
1684
|
+
if (prerenderFnNames.some((n) => fnCall.includes(n))) {
|
|
1685
|
+
brand = PRERENDER_CONFIG.brand;
|
|
1686
|
+
} else if (staticFnNames.some((n) => fnCall.includes(n))) {
|
|
1687
|
+
brand = STATIC_CONFIG.brand;
|
|
1688
|
+
}
|
|
1417
1689
|
lines.push(
|
|
1418
|
-
`export const ${primaryName} = ${
|
|
1419
|
-
);
|
|
1420
|
-
lines.push(
|
|
1421
|
-
`${primaryName}.__rsc_ls_key = "__rsc_ls_${stubId}";`
|
|
1690
|
+
`export const ${primaryName} = { __brand: "${brand}", $$id: "${stubId}" };`
|
|
1422
1691
|
);
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
}
|
|
1427
|
-
} else {
|
|
1428
|
-
let brand = "loader";
|
|
1429
|
-
if (prerenderFnNames.some((n) => fnCall.includes(n))) {
|
|
1430
|
-
brand = PRERENDER_CONFIG.brand;
|
|
1431
|
-
} else if (staticFnNames.some((n) => fnCall.includes(n))) {
|
|
1432
|
-
brand = STATIC_CONFIG.brand;
|
|
1433
|
-
}
|
|
1434
|
-
lines.push(
|
|
1435
|
-
`export const ${primaryName} = { __brand: "${brand}", $$id: "${stubId}" };`
|
|
1436
|
-
);
|
|
1437
|
-
for (const name of binding.exportNames.slice(1)) {
|
|
1438
|
-
lines.push(`export const ${name} = ${primaryName};`);
|
|
1692
|
+
for (const name of binding.exportNames.slice(1)) {
|
|
1693
|
+
lines.push(`export const ${name} = ${primaryName};`);
|
|
1694
|
+
}
|
|
1439
1695
|
}
|
|
1440
1696
|
}
|
|
1697
|
+
return { code: lines.join("\n") + "\n", map: null };
|
|
1441
1698
|
}
|
|
1442
|
-
return { code: lines.join("\n") + "\n", map: null };
|
|
1443
1699
|
}
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1700
|
+
if (isRscEnv && isBuild) {
|
|
1701
|
+
const trackTypes = [
|
|
1702
|
+
[
|
|
1703
|
+
hasPrerenderHandlerCode,
|
|
1704
|
+
PRERENDER_CONFIG,
|
|
1705
|
+
prerenderHandlerModules
|
|
1706
|
+
],
|
|
1707
|
+
[hasStaticHandlerCode, STATIC_CONFIG, staticHandlerModules]
|
|
1708
|
+
];
|
|
1709
|
+
for (const [has2, cfg, trackMap] of trackTypes) {
|
|
1710
|
+
if (!has2) continue;
|
|
1711
|
+
const exportNames = getBindings(code, getFnNames(cfg.fnName)).map(
|
|
1712
|
+
(b) => b.exportNames[0]
|
|
1713
|
+
);
|
|
1714
|
+
if (exportNames.length > 0) trackMap.set(id, exportNames);
|
|
1715
|
+
}
|
|
1452
1716
|
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
}
|
|
1459
|
-
if (hasHandleCode) {
|
|
1460
|
-
const fnNames = getFnNames("createHandle");
|
|
1461
|
-
changed = transformHandles(
|
|
1462
|
-
getBindings(code, fnNames),
|
|
1463
|
-
s,
|
|
1464
|
-
code,
|
|
1465
|
-
filePath,
|
|
1466
|
-
isBuild
|
|
1467
|
-
) || changed;
|
|
1468
|
-
}
|
|
1469
|
-
if (hasLocationStateCode) {
|
|
1470
|
-
const fnNames = getFnNames("createLocationState");
|
|
1471
|
-
changed = transformLocationState(
|
|
1472
|
-
getBindings(code, fnNames),
|
|
1473
|
-
s,
|
|
1474
|
-
filePath,
|
|
1475
|
-
isBuild
|
|
1476
|
-
) || changed;
|
|
1477
|
-
}
|
|
1478
|
-
if (hasPrerenderHandlerCode) {
|
|
1479
|
-
const fnNames = getFnNames(PRERENDER_CONFIG.fnName);
|
|
1480
|
-
const bindings = getBindings(code, fnNames);
|
|
1481
|
-
if (isRscEnv) {
|
|
1482
|
-
changed = transformHandlerIds(
|
|
1483
|
-
PRERENDER_CONFIG,
|
|
1484
|
-
bindings,
|
|
1717
|
+
const s = new MagicString3(code);
|
|
1718
|
+
if (hasLoaderCode) {
|
|
1719
|
+
const fnNames = getFnNames("createLoader");
|
|
1720
|
+
changed = transformLoaders(
|
|
1721
|
+
getBindings(code, fnNames),
|
|
1485
1722
|
s,
|
|
1486
1723
|
filePath,
|
|
1487
1724
|
isBuild
|
|
1488
1725
|
) || changed;
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1726
|
+
}
|
|
1727
|
+
if (hasHandleCode) {
|
|
1728
|
+
const fnNames = getFnNames("createHandle");
|
|
1729
|
+
changed = transformHandles(
|
|
1730
|
+
getBindings(code, fnNames),
|
|
1493
1731
|
s,
|
|
1732
|
+
code,
|
|
1494
1733
|
filePath,
|
|
1495
1734
|
isBuild
|
|
1496
1735
|
) || changed;
|
|
1497
1736
|
}
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
if (isRscEnv) {
|
|
1503
|
-
changed = transformHandlerIds(
|
|
1504
|
-
STATIC_CONFIG,
|
|
1505
|
-
bindings,
|
|
1737
|
+
if (hasLocationStateCode) {
|
|
1738
|
+
const fnNames = getFnNames("createLocationState");
|
|
1739
|
+
changed = transformLocationState(
|
|
1740
|
+
getBindings(code, fnNames),
|
|
1506
1741
|
s,
|
|
1507
1742
|
filePath,
|
|
1508
1743
|
isBuild
|
|
1509
1744
|
) || changed;
|
|
1510
|
-
} else {
|
|
1511
|
-
changed = stubHandlerExprs(STATIC_CONFIG, bindings, s, filePath, isBuild) || changed;
|
|
1512
1745
|
}
|
|
1746
|
+
const finalHandlerConfigs = [
|
|
1747
|
+
hasPrerenderHandlerCode && PRERENDER_CONFIG,
|
|
1748
|
+
hasStaticHandlerCode && STATIC_CONFIG
|
|
1749
|
+
].filter((c) => !!c);
|
|
1750
|
+
for (const cfg of finalHandlerConfigs) {
|
|
1751
|
+
const bindings = getBindings(code, getFnNames(cfg.fnName));
|
|
1752
|
+
changed = (isRscEnv ? transformHandlerIds(cfg, bindings, s, filePath, isBuild) : stubHandlerExprs(cfg, bindings, s, filePath, isBuild)) || changed;
|
|
1753
|
+
}
|
|
1754
|
+
if (!changed) return;
|
|
1755
|
+
return {
|
|
1756
|
+
code: s.toString(),
|
|
1757
|
+
map: s.generateMap({ source: id, includeContent: true })
|
|
1758
|
+
};
|
|
1759
|
+
} finally {
|
|
1760
|
+
counter?.record(id, performance.now() - __t0);
|
|
1513
1761
|
}
|
|
1514
|
-
if (!changed) return;
|
|
1515
|
-
return {
|
|
1516
|
-
code: s.toString(),
|
|
1517
|
-
map: s.generateMap({ source: id, includeContent: true })
|
|
1518
|
-
};
|
|
1519
1762
|
}
|
|
1520
1763
|
};
|
|
1521
1764
|
}
|
|
1522
1765
|
|
|
1523
1766
|
// src/vite/plugins/use-cache-transform.ts
|
|
1524
1767
|
import path5 from "node:path";
|
|
1525
|
-
import
|
|
1768
|
+
import MagicString4 from "magic-string";
|
|
1769
|
+
var debug4 = createRangoDebugger(NS.transform);
|
|
1526
1770
|
var CACHE_RUNTIME_IMPORT = "@rangojs/router/cache-runtime";
|
|
1527
1771
|
var LAYOUT_TEMPLATE_PATTERN = /\/(layout|template)\.(tsx?|jsx?)$/;
|
|
1772
|
+
var USE_CACHE_DIRECTIVE_RE = /^use cache(:\s*[\w-]+)?$/;
|
|
1528
1773
|
function useCacheTransform() {
|
|
1529
1774
|
let projectRoot = "";
|
|
1530
1775
|
let isBuild = false;
|
|
1531
1776
|
let rscTransforms = null;
|
|
1777
|
+
const counter = createCounter(debug4, "use-cache");
|
|
1532
1778
|
return {
|
|
1533
1779
|
name: "@rangojs/router:use-cache",
|
|
1534
1780
|
enforce: "post",
|
|
@@ -1536,53 +1782,61 @@ function useCacheTransform() {
|
|
|
1536
1782
|
projectRoot = config.root;
|
|
1537
1783
|
isBuild = config.command === "build";
|
|
1538
1784
|
},
|
|
1785
|
+
buildEnd() {
|
|
1786
|
+
counter?.flush();
|
|
1787
|
+
},
|
|
1539
1788
|
async transform(code, id) {
|
|
1540
1789
|
if (this.environment?.name !== "rsc") return;
|
|
1541
1790
|
if (!code.includes("use cache")) return;
|
|
1542
1791
|
if (id.includes("/node_modules/") || id.startsWith("\0")) return;
|
|
1543
1792
|
if (!/\.(tsx?|jsx?|mjs)$/.test(id)) return;
|
|
1544
|
-
|
|
1793
|
+
const start = counter ? performance.now() : 0;
|
|
1794
|
+
try {
|
|
1795
|
+
if (!rscTransforms) {
|
|
1796
|
+
try {
|
|
1797
|
+
rscTransforms = await import("@vitejs/plugin-rsc/transforms");
|
|
1798
|
+
} catch {
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
const {
|
|
1803
|
+
hasDirective,
|
|
1804
|
+
transformWrapExport,
|
|
1805
|
+
transformHoistInlineDirective
|
|
1806
|
+
} = rscTransforms;
|
|
1807
|
+
let ast;
|
|
1545
1808
|
try {
|
|
1546
|
-
|
|
1809
|
+
const { parseAst: parseAst4 } = await import("vite");
|
|
1810
|
+
ast = parseAst4(code, { lang: "tsx" });
|
|
1547
1811
|
} catch {
|
|
1548
1812
|
return;
|
|
1549
1813
|
}
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
hasDirective,
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
const isLayoutOrTemplate = LAYOUT_TEMPLATE_PATTERN.test(id);
|
|
1565
|
-
if (hasDirective(ast.body, "use cache")) {
|
|
1566
|
-
return transformFileLevelUseCache(
|
|
1814
|
+
const filePath = normalizePath(path5.relative(projectRoot, id));
|
|
1815
|
+
const isLayoutOrTemplate = LAYOUT_TEMPLATE_PATTERN.test(id);
|
|
1816
|
+
if (hasDirective(ast.body, "use cache")) {
|
|
1817
|
+
return transformFileLevelUseCache(
|
|
1818
|
+
code,
|
|
1819
|
+
ast,
|
|
1820
|
+
filePath,
|
|
1821
|
+
id,
|
|
1822
|
+
isBuild,
|
|
1823
|
+
isLayoutOrTemplate,
|
|
1824
|
+
transformWrapExport
|
|
1825
|
+
);
|
|
1826
|
+
}
|
|
1827
|
+
const functionResult = transformFunctionLevelUseCache(
|
|
1567
1828
|
code,
|
|
1568
1829
|
ast,
|
|
1569
1830
|
filePath,
|
|
1570
1831
|
id,
|
|
1571
1832
|
isBuild,
|
|
1572
|
-
|
|
1573
|
-
transformWrapExport
|
|
1833
|
+
transformHoistInlineDirective
|
|
1574
1834
|
);
|
|
1835
|
+
warnOnNearMissDirectives(ast, id, this.warn.bind(this));
|
|
1836
|
+
if (functionResult) return functionResult;
|
|
1837
|
+
} finally {
|
|
1838
|
+
counter?.record(id, performance.now() - start);
|
|
1575
1839
|
}
|
|
1576
|
-
const functionResult = transformFunctionLevelUseCache(
|
|
1577
|
-
code,
|
|
1578
|
-
ast,
|
|
1579
|
-
filePath,
|
|
1580
|
-
id,
|
|
1581
|
-
isBuild,
|
|
1582
|
-
transformHoistInlineDirective
|
|
1583
|
-
);
|
|
1584
|
-
warnOnNearMissDirectives(ast, id, this.warn.bind(this));
|
|
1585
|
-
if (functionResult) return functionResult;
|
|
1586
1840
|
}
|
|
1587
1841
|
};
|
|
1588
1842
|
}
|
|
@@ -1609,7 +1863,7 @@ function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLa
|
|
|
1609
1863
|
);
|
|
1610
1864
|
}
|
|
1611
1865
|
if (exportNames.length === 0) {
|
|
1612
|
-
const s = new
|
|
1866
|
+
const s = new MagicString4(code);
|
|
1613
1867
|
const directive2 = findFileLevelDirective(ast);
|
|
1614
1868
|
if (directive2) {
|
|
1615
1869
|
s.overwrite(
|
|
@@ -1644,7 +1898,7 @@ function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLa
|
|
|
1644
1898
|
function transformFunctionLevelUseCache(code, ast, filePath, sourceId, isBuild, transformHoistInlineDirective) {
|
|
1645
1899
|
try {
|
|
1646
1900
|
const { output, names } = transformHoistInlineDirective(code, ast, {
|
|
1647
|
-
directive:
|
|
1901
|
+
directive: USE_CACHE_DIRECTIVE_RE,
|
|
1648
1902
|
runtime: (value, name, meta) => {
|
|
1649
1903
|
const funcId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
|
|
1650
1904
|
const profileMatch = meta.directiveMatch[1];
|
|
@@ -1674,14 +1928,13 @@ function findFileLevelDirective(ast) {
|
|
|
1674
1928
|
}
|
|
1675
1929
|
return null;
|
|
1676
1930
|
}
|
|
1677
|
-
var VALID_DIRECTIVE_RE = /^use cache(:\s*[\w-]+)?$/;
|
|
1678
1931
|
var NEAR_MISS_RE = /^use cache:\s*.+$/;
|
|
1679
1932
|
function warnOnNearMissDirectives(ast, fileId, warn) {
|
|
1680
1933
|
const visit = (node) => {
|
|
1681
1934
|
if (!node || typeof node !== "object") return;
|
|
1682
1935
|
if (node.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
|
|
1683
1936
|
const value = node.expression.value;
|
|
1684
|
-
if (value.startsWith("use cache") && NEAR_MISS_RE.test(value) && !
|
|
1937
|
+
if (value.startsWith("use cache") && NEAR_MISS_RE.test(value) && !USE_CACHE_DIRECTIVE_RE.test(value)) {
|
|
1685
1938
|
const profilePart = value.slice("use cache:".length).trim();
|
|
1686
1939
|
warn(
|
|
1687
1940
|
`[rango:use-cache] "${value}" in ${fileId} has an invalid profile name "${profilePart}". Profile names must match [a-zA-Z0-9_-]+. This directive will be ignored.`
|
|
@@ -1705,6 +1958,7 @@ function warnOnNearMissDirectives(ast, fileId, warn) {
|
|
|
1705
1958
|
}
|
|
1706
1959
|
|
|
1707
1960
|
// src/vite/plugins/client-ref-dedup.ts
|
|
1961
|
+
var debug5 = createRangoDebugger(NS.transform);
|
|
1708
1962
|
var CLIENT_IN_SERVER_PROXY_PREFIX = "virtual:vite-rsc/client-in-server-package-proxy/";
|
|
1709
1963
|
function extractPackageName(absolutePath) {
|
|
1710
1964
|
const marker = "/node_modules/";
|
|
@@ -1721,6 +1975,7 @@ function extractPackageName(absolutePath) {
|
|
|
1721
1975
|
}
|
|
1722
1976
|
function clientRefDedup() {
|
|
1723
1977
|
let clientExclude = [];
|
|
1978
|
+
const dedupedPackages = /* @__PURE__ */ new Set();
|
|
1724
1979
|
return {
|
|
1725
1980
|
name: "@rangojs/router:client-ref-dedup",
|
|
1726
1981
|
enforce: "pre",
|
|
@@ -1729,6 +1984,15 @@ function clientRefDedup() {
|
|
|
1729
1984
|
const clientEnv = config.environments?.["client"];
|
|
1730
1985
|
clientExclude = clientEnv?.optimizeDeps?.exclude ?? config.optimizeDeps?.exclude ?? [];
|
|
1731
1986
|
},
|
|
1987
|
+
buildEnd() {
|
|
1988
|
+
if (debug5 && dedupedPackages.size > 0) {
|
|
1989
|
+
debug5(
|
|
1990
|
+
"client-ref-dedup: redirected %d package(s) (%s)",
|
|
1991
|
+
dedupedPackages.size,
|
|
1992
|
+
[...dedupedPackages].join(",")
|
|
1993
|
+
);
|
|
1994
|
+
}
|
|
1995
|
+
},
|
|
1732
1996
|
resolveId(source, importer, options) {
|
|
1733
1997
|
if (this.environment?.name !== "client") return;
|
|
1734
1998
|
if (!importer?.includes(CLIENT_IN_SERVER_PROXY_PREFIX)) return;
|
|
@@ -1737,6 +2001,7 @@ function clientRefDedup() {
|
|
|
1737
2001
|
const packageName = extractPackageName(source);
|
|
1738
2002
|
if (!packageName) return;
|
|
1739
2003
|
if (clientExclude.includes(packageName)) return;
|
|
2004
|
+
if (debug5) dedupedPackages.add(packageName);
|
|
1740
2005
|
return `\0rango:dedup/${packageName}`;
|
|
1741
2006
|
},
|
|
1742
2007
|
load(id) {
|
|
@@ -1763,7 +2028,7 @@ import {
|
|
|
1763
2028
|
import { createElement, StrictMode } from "react";
|
|
1764
2029
|
import { hydrateRoot } from "react-dom/client";
|
|
1765
2030
|
import { rscStream } from "@rangojs/router/internal/deps/html-stream-client";
|
|
1766
|
-
import { initBrowserApp,
|
|
2031
|
+
import { initBrowserApp, Rango } from "@rangojs/router/browser";
|
|
1767
2032
|
|
|
1768
2033
|
async function initializeApp() {
|
|
1769
2034
|
const deps = {
|
|
@@ -1778,7 +2043,7 @@ async function initializeApp() {
|
|
|
1778
2043
|
|
|
1779
2044
|
hydrateRoot(
|
|
1780
2045
|
document,
|
|
1781
|
-
createElement(StrictMode, null, createElement(
|
|
2046
|
+
createElement(StrictMode, null, createElement(Rango))
|
|
1782
2047
|
);
|
|
1783
2048
|
}
|
|
1784
2049
|
|
|
@@ -1859,12 +2124,13 @@ function getVirtualVersionContent(version) {
|
|
|
1859
2124
|
|
|
1860
2125
|
// src/vite/utils/package-resolution.ts
|
|
1861
2126
|
import { existsSync } from "node:fs";
|
|
2127
|
+
import { createRequire } from "node:module";
|
|
1862
2128
|
import { resolve } from "node:path";
|
|
1863
2129
|
|
|
1864
2130
|
// package.json
|
|
1865
2131
|
var package_default = {
|
|
1866
2132
|
name: "@rangojs/router",
|
|
1867
|
-
version: "0.0.0-experimental.
|
|
2133
|
+
version: "0.0.0-experimental.77ed8945",
|
|
1868
2134
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
1869
2135
|
keywords: [
|
|
1870
2136
|
"react",
|
|
@@ -1997,22 +2263,26 @@ var package_default = {
|
|
|
1997
2263
|
tag: "experimental"
|
|
1998
2264
|
},
|
|
1999
2265
|
scripts: {
|
|
2000
|
-
build: "pnpm dlx esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && pnpm dlx esbuild src/bin/rango.ts --bundle --format=esm --outfile=dist/bin/rango.js --platform=node --packages=external --banner:js='#!/usr/bin/env node' && chmod +x dist/bin/rango.js",
|
|
2266
|
+
build: "pnpm dlx esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && mkdir -p dist/vite/plugins && cp src/vite/plugins/cloudflare-protocol-loader-hook.mjs dist/vite/plugins/cloudflare-protocol-loader-hook.mjs && pnpm dlx esbuild src/bin/rango.ts --bundle --format=esm --outfile=dist/bin/rango.js --platform=node --packages=external --banner:js='#!/usr/bin/env node' && chmod +x dist/bin/rango.js",
|
|
2001
2267
|
prepublishOnly: "pnpm build",
|
|
2002
|
-
typecheck: "tsc --noEmit",
|
|
2268
|
+
typecheck: "tsc --noEmit && tsc -p tsconfig.strict-check.json --noEmit && tsc -p tsconfig.augment-check.json --noEmit",
|
|
2003
2269
|
test: "playwright test",
|
|
2004
2270
|
"test:ui": "playwright test --ui",
|
|
2271
|
+
"test:hmr-local": "playwright test --project=dev-warmup --project=hmr-routes --project=hmr-basename --project=hmr-prerender --no-deps --workers=1",
|
|
2005
2272
|
"test:unit": "vitest run",
|
|
2006
2273
|
"test:unit:watch": "vitest"
|
|
2007
2274
|
},
|
|
2008
2275
|
dependencies: {
|
|
2009
|
-
"@
|
|
2276
|
+
"@types/debug": "^4.1.12",
|
|
2277
|
+
"@vitejs/plugin-rsc": "^0.5.26",
|
|
2278
|
+
debug: "^4.4.1",
|
|
2010
2279
|
"magic-string": "^0.30.17",
|
|
2011
2280
|
picomatch: "^4.0.3",
|
|
2012
2281
|
"rsc-html-stream": "^0.0.7"
|
|
2013
2282
|
},
|
|
2014
2283
|
devDependencies: {
|
|
2015
2284
|
"@playwright/test": "^1.49.1",
|
|
2285
|
+
"@shared/e2e": "workspace:*",
|
|
2016
2286
|
"@types/node": "^24.10.1",
|
|
2017
2287
|
"@types/react": "catalog:",
|
|
2018
2288
|
"@types/react-dom": "catalog:",
|
|
@@ -2025,10 +2295,11 @@ var package_default = {
|
|
|
2025
2295
|
vitest: "^4.0.0"
|
|
2026
2296
|
},
|
|
2027
2297
|
peerDependencies: {
|
|
2028
|
-
"@cloudflare/vite-plugin": "^1.
|
|
2029
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
2030
|
-
react: "
|
|
2031
|
-
|
|
2298
|
+
"@cloudflare/vite-plugin": "^1.38.0",
|
|
2299
|
+
"@vitejs/plugin-rsc": "^0.5.26",
|
|
2300
|
+
react: ">=19.2.6 <20",
|
|
2301
|
+
"react-dom": ">=19.2.6 <20",
|
|
2302
|
+
vite: "^8.0.0"
|
|
2032
2303
|
},
|
|
2033
2304
|
peerDependenciesMeta: {
|
|
2034
2305
|
"@cloudflare/vite-plugin": {
|
|
@@ -2041,6 +2312,7 @@ var package_default = {
|
|
|
2041
2312
|
};
|
|
2042
2313
|
|
|
2043
2314
|
// src/vite/utils/package-resolution.ts
|
|
2315
|
+
var require2 = createRequire(import.meta.url);
|
|
2044
2316
|
var VIRTUAL_PACKAGE_NAME = "@rangojs/router";
|
|
2045
2317
|
function getPublishedPackageName() {
|
|
2046
2318
|
return package_default.name;
|
|
@@ -2081,6 +2353,20 @@ function getPackageAliases() {
|
|
|
2081
2353
|
}
|
|
2082
2354
|
return aliases;
|
|
2083
2355
|
}
|
|
2356
|
+
function getVendorAliases() {
|
|
2357
|
+
const specs = [
|
|
2358
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
|
|
2359
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
2360
|
+
];
|
|
2361
|
+
const aliases = {};
|
|
2362
|
+
for (const spec of specs) {
|
|
2363
|
+
try {
|
|
2364
|
+
aliases[spec] = require2.resolve(spec);
|
|
2365
|
+
} catch {
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
return aliases;
|
|
2369
|
+
}
|
|
2084
2370
|
|
|
2085
2371
|
// src/build/route-types/param-extraction.ts
|
|
2086
2372
|
function extractParamsFromPattern(pattern) {
|
|
@@ -2206,7 +2492,7 @@ ${objectBody}
|
|
|
2206
2492
|
} as const;
|
|
2207
2493
|
|
|
2208
2494
|
declare global {
|
|
2209
|
-
namespace
|
|
2495
|
+
namespace Rango {
|
|
2210
2496
|
interface GeneratedRouteMap extends Readonly<typeof NamedRoutes> {}
|
|
2211
2497
|
}
|
|
2212
2498
|
}
|
|
@@ -2441,7 +2727,7 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
|
|
|
2441
2727
|
const realPath = resolve2(filePath);
|
|
2442
2728
|
const key = variableName ? `${realPath}:${variableName}` : realPath;
|
|
2443
2729
|
if (visited.has(key)) {
|
|
2444
|
-
console.warn(`[
|
|
2730
|
+
console.warn(`[rango] Circular include detected, skipping: ${key}`);
|
|
2445
2731
|
return { routes: {}, searchSchemas: {} };
|
|
2446
2732
|
}
|
|
2447
2733
|
visited.add(key);
|
|
@@ -2502,6 +2788,7 @@ function countPublicRouteEntries(source) {
|
|
|
2502
2788
|
return count;
|
|
2503
2789
|
}
|
|
2504
2790
|
var ROUTER_CALL_PATTERN = /\bcreateRouter\s*[<(]/;
|
|
2791
|
+
var ROUTER_CALL_PATTERN_G = /\bcreateRouter\s*[<(]/g;
|
|
2505
2792
|
function isRoutableSourceFile(name) {
|
|
2506
2793
|
return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
|
|
2507
2794
|
}
|
|
@@ -2511,7 +2798,7 @@ function findRouterFilesRecursive(dir, filter, results) {
|
|
|
2511
2798
|
entries = readdirSync(dir, { withFileTypes: true });
|
|
2512
2799
|
} catch (err) {
|
|
2513
2800
|
console.warn(
|
|
2514
|
-
`[
|
|
2801
|
+
`[rango] Failed to scan directory ${dir}: ${err.message}`
|
|
2515
2802
|
);
|
|
2516
2803
|
return;
|
|
2517
2804
|
}
|
|
@@ -2529,7 +2816,7 @@ function findRouterFilesRecursive(dir, filter, results) {
|
|
|
2529
2816
|
if (filter && !filter(fullPath)) continue;
|
|
2530
2817
|
try {
|
|
2531
2818
|
const source = readFileSync2(fullPath, "utf-8");
|
|
2532
|
-
if (ROUTER_CALL_PATTERN.test(source)) {
|
|
2819
|
+
if (ROUTER_CALL_PATTERN.test(source) && firstCodeMatchIndex(source, ROUTER_CALL_PATTERN_G) >= 0) {
|
|
2533
2820
|
routerFilesInDir.push(fullPath);
|
|
2534
2821
|
}
|
|
2535
2822
|
} catch {
|
|
@@ -2567,7 +2854,7 @@ function findNestedRouterConflict(routerFiles) {
|
|
|
2567
2854
|
}
|
|
2568
2855
|
return null;
|
|
2569
2856
|
}
|
|
2570
|
-
function formatNestedRouterConflictError(conflict, prefix = "[
|
|
2857
|
+
function formatNestedRouterConflictError(conflict, prefix = "[rango]") {
|
|
2571
2858
|
return `${prefix} Nested router roots are not supported.
|
|
2572
2859
|
Router root: ${conflict.ancestor}
|
|
2573
2860
|
Nested router: ${conflict.nested}
|
|
@@ -2663,19 +2950,38 @@ function extractBasenameFromRouter(code) {
|
|
|
2663
2950
|
visit(sourceFile);
|
|
2664
2951
|
return result;
|
|
2665
2952
|
}
|
|
2666
|
-
function applyBasenameToRoutes(result,
|
|
2953
|
+
function applyBasenameToRoutes(result, basename2) {
|
|
2667
2954
|
const prefixed = {};
|
|
2668
2955
|
for (const [name, pattern] of Object.entries(result.routes)) {
|
|
2669
2956
|
if (pattern === "/") {
|
|
2670
|
-
prefixed[name] =
|
|
2671
|
-
} else if (
|
|
2672
|
-
prefixed[name] =
|
|
2957
|
+
prefixed[name] = basename2;
|
|
2958
|
+
} else if (basename2.endsWith("/") && pattern.startsWith("/")) {
|
|
2959
|
+
prefixed[name] = basename2 + pattern.slice(1);
|
|
2673
2960
|
} else {
|
|
2674
|
-
prefixed[name] =
|
|
2961
|
+
prefixed[name] = basename2 + pattern;
|
|
2675
2962
|
}
|
|
2676
2963
|
}
|
|
2677
2964
|
return { routes: prefixed, searchSchemas: result.searchSchemas };
|
|
2678
2965
|
}
|
|
2966
|
+
function genFileTsPath(sourceFile) {
|
|
2967
|
+
const base = pathBasename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
2968
|
+
return join(dirname2(sourceFile), `${base}.named-routes.gen.ts`);
|
|
2969
|
+
}
|
|
2970
|
+
function resolveSearchSchemas(publicRouteNames, runtimeSchemas, sourceFile) {
|
|
2971
|
+
if (runtimeSchemas && Object.keys(runtimeSchemas).length > 0) {
|
|
2972
|
+
return runtimeSchemas;
|
|
2973
|
+
}
|
|
2974
|
+
const staticParsed = buildCombinedRouteMapForRouterFile(sourceFile);
|
|
2975
|
+
if (Object.keys(staticParsed.searchSchemas).length === 0) {
|
|
2976
|
+
return runtimeSchemas;
|
|
2977
|
+
}
|
|
2978
|
+
const filtered = {};
|
|
2979
|
+
for (const name of publicRouteNames) {
|
|
2980
|
+
const schema = staticParsed.searchSchemas[name];
|
|
2981
|
+
if (schema) filtered[name] = schema;
|
|
2982
|
+
}
|
|
2983
|
+
return Object.keys(filtered).length > 0 ? filtered : runtimeSchemas;
|
|
2984
|
+
}
|
|
2679
2985
|
function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
2680
2986
|
let routerSource;
|
|
2681
2987
|
try {
|
|
@@ -2688,7 +2994,7 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
|
2688
2994
|
return { routes: {}, searchSchemas: {} };
|
|
2689
2995
|
}
|
|
2690
2996
|
const rawBasename = extractBasenameFromRouter(routerSource);
|
|
2691
|
-
const
|
|
2997
|
+
const basename2 = rawBasename ? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "") : void 0;
|
|
2692
2998
|
let result;
|
|
2693
2999
|
if (extraction.kind === "inline") {
|
|
2694
3000
|
result = buildCombinedRouteMapWithSearch(
|
|
@@ -2713,8 +3019,8 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
|
2713
3019
|
result = buildCombinedRouteMapWithSearch(routerFilePath, extraction.name);
|
|
2714
3020
|
}
|
|
2715
3021
|
}
|
|
2716
|
-
if (
|
|
2717
|
-
result = applyBasenameToRoutes(result,
|
|
3022
|
+
if (basename2) {
|
|
3023
|
+
result = applyBasenameToRoutes(result, basename2);
|
|
2718
3024
|
}
|
|
2719
3025
|
return result;
|
|
2720
3026
|
}
|
|
@@ -2729,7 +3035,7 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
|
2729
3035
|
if (existsSync3(oldCombinedPath)) {
|
|
2730
3036
|
unlinkSync(oldCombinedPath);
|
|
2731
3037
|
console.log(
|
|
2732
|
-
`[
|
|
3038
|
+
`[rango] Removed stale combined route types: ${oldCombinedPath}`
|
|
2733
3039
|
);
|
|
2734
3040
|
}
|
|
2735
3041
|
} catch {
|
|
@@ -2751,18 +3057,12 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
|
2751
3057
|
}
|
|
2752
3058
|
if (!extractUrlsFromRouter(routerSource)) continue;
|
|
2753
3059
|
}
|
|
2754
|
-
const
|
|
2755
|
-
/\.(tsx?|jsx?)$/,
|
|
2756
|
-
""
|
|
2757
|
-
);
|
|
2758
|
-
const outPath = join(
|
|
2759
|
-
dirname2(routerFilePath),
|
|
2760
|
-
`${routerBasename}.named-routes.gen.ts`
|
|
2761
|
-
);
|
|
3060
|
+
const outPath = genFileTsPath(routerFilePath);
|
|
2762
3061
|
const existing = existsSync3(outPath) ? readFileSync2(outPath, "utf-8") : null;
|
|
2763
3062
|
if (Object.keys(result.routes).length === 0) {
|
|
2764
3063
|
if (!existing) {
|
|
2765
3064
|
const emptySource = generateRouteTypesSource({});
|
|
3065
|
+
opts?.onWrite?.(outPath, emptySource);
|
|
2766
3066
|
writeFileSync(outPath, emptySource);
|
|
2767
3067
|
}
|
|
2768
3068
|
continue;
|
|
@@ -2782,9 +3082,10 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
|
2782
3082
|
continue;
|
|
2783
3083
|
}
|
|
2784
3084
|
}
|
|
3085
|
+
opts?.onWrite?.(outPath, source);
|
|
2785
3086
|
writeFileSync(outPath, source);
|
|
2786
3087
|
console.log(
|
|
2787
|
-
`[
|
|
3088
|
+
`[rango] Generated route types (${Object.keys(result.routes).length} routes) -> ${outPath}`
|
|
2788
3089
|
);
|
|
2789
3090
|
}
|
|
2790
3091
|
}
|
|
@@ -2801,7 +3102,7 @@ function normalizeModuleId(id) {
|
|
|
2801
3102
|
function getClientModuleSignature(source) {
|
|
2802
3103
|
let program;
|
|
2803
3104
|
try {
|
|
2804
|
-
program = parseAst3(source, {
|
|
3105
|
+
program = parseAst3(source, { lang: "tsx" });
|
|
2805
3106
|
} catch {
|
|
2806
3107
|
return void 0;
|
|
2807
3108
|
}
|
|
@@ -2884,11 +3185,12 @@ function createVersionPlugin() {
|
|
|
2884
3185
|
let currentVersion = buildVersion;
|
|
2885
3186
|
let isDev = false;
|
|
2886
3187
|
let server = null;
|
|
3188
|
+
let resolvedCacheDir;
|
|
2887
3189
|
const clientModuleSignatures = /* @__PURE__ */ new Map();
|
|
2888
3190
|
let versionCounter = 0;
|
|
2889
3191
|
const bumpVersion = (reason) => {
|
|
2890
3192
|
currentVersion = Date.now().toString(16) + String(++versionCounter);
|
|
2891
|
-
console.log(`[
|
|
3193
|
+
console.log(`[rango] ${reason}, version updated: ${currentVersion}`);
|
|
2892
3194
|
const rscEnv = server?.environments?.rsc;
|
|
2893
3195
|
const versionMod = rscEnv?.moduleGraph?.getModuleById(
|
|
2894
3196
|
"\0" + VIRTUAL_IDS.version
|
|
@@ -2902,6 +3204,7 @@ function createVersionPlugin() {
|
|
|
2902
3204
|
enforce: "pre",
|
|
2903
3205
|
configResolved(config) {
|
|
2904
3206
|
isDev = config.command === "serve";
|
|
3207
|
+
resolvedCacheDir = config.cacheDir ? String(config.cacheDir).replace(/\\/g, "/") : void 0;
|
|
2905
3208
|
},
|
|
2906
3209
|
configureServer(devServer) {
|
|
2907
3210
|
server = devServer;
|
|
@@ -2943,6 +3246,7 @@ function createVersionPlugin() {
|
|
|
2943
3246
|
if (!isDev) return;
|
|
2944
3247
|
const isRscModule = this.environment?.name === "rsc";
|
|
2945
3248
|
if (!isRscModule) return;
|
|
3249
|
+
if (isViteDepCachePath(ctx.file, resolvedCacheDir)) return;
|
|
2946
3250
|
if (ctx.modules.length === 1 && ctx.modules[0].id === "\0" + VIRTUAL_IDS.version) {
|
|
2947
3251
|
return;
|
|
2948
3252
|
}
|
|
@@ -2972,12 +3276,24 @@ function createVersionPlugin() {
|
|
|
2972
3276
|
}
|
|
2973
3277
|
};
|
|
2974
3278
|
}
|
|
3279
|
+
function isViteDepCachePath(filePath, cacheDir) {
|
|
3280
|
+
if (!filePath) return false;
|
|
3281
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
3282
|
+
if (cacheDir) {
|
|
3283
|
+
const normalizedCacheDir = cacheDir.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
3284
|
+
if (normalized === normalizedCacheDir || normalized.startsWith(normalizedCacheDir + "/")) {
|
|
3285
|
+
return true;
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
return /\/node_modules\/\.vite[^/]*\//.test(normalized) || normalized.includes("/.vite-isolated/");
|
|
3289
|
+
}
|
|
2975
3290
|
|
|
2976
3291
|
// src/vite/utils/shared-utils.ts
|
|
2977
3292
|
import * as Vite from "vite";
|
|
2978
3293
|
|
|
2979
3294
|
// src/vite/plugins/performance-tracks.ts
|
|
2980
3295
|
import { readFile } from "node:fs/promises";
|
|
3296
|
+
var debug6 = createRangoDebugger(NS.transform);
|
|
2981
3297
|
var RSDW_PATCH_RE = /((?:var|let|const)\s+\w+\s*=\s*root\._children\s*,\s*(\w+)\s*=\s*root\._debugInfo\s*[;,])/;
|
|
2982
3298
|
function buildPatchReplacement(match, debugInfoVar) {
|
|
2983
3299
|
return `${match}
|
|
@@ -2999,62 +3315,65 @@ function patchRsdwClientDebugInfoRecovery(code) {
|
|
|
2999
3315
|
};
|
|
3000
3316
|
}
|
|
3001
3317
|
function performanceTracksOptimizeDepsPlugin() {
|
|
3318
|
+
const RSDW_CLIENT_RE = /react-server-dom-webpack-client\.browser\.(development|production)\.js$/;
|
|
3002
3319
|
return {
|
|
3003
3320
|
name: "@rangojs/router:performance-tracks-optimize-deps",
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
contents: patched.code,
|
|
3014
|
-
loader: "js"
|
|
3015
|
-
};
|
|
3016
|
-
}
|
|
3017
|
-
);
|
|
3321
|
+
// Vite 8 optimizes deps with Rolldown (Rollup-style plugin pipeline), so the
|
|
3322
|
+
// pre-bundled RSDW client is patched via load() rather than esbuild's onLoad.
|
|
3323
|
+
// Returning code overrides Rolldown's default filesystem read for the module.
|
|
3324
|
+
async load(id) {
|
|
3325
|
+
const cleanId = id.split("?")[0] ?? id;
|
|
3326
|
+
if (!RSDW_CLIENT_RE.test(cleanId)) return null;
|
|
3327
|
+
const code = await readFile(cleanId, "utf8");
|
|
3328
|
+
const patched = patchRsdwClientDebugInfoRecovery(code);
|
|
3329
|
+
return { code: patched.code };
|
|
3018
3330
|
}
|
|
3019
3331
|
};
|
|
3020
3332
|
}
|
|
3021
3333
|
function performanceTracksPlugin() {
|
|
3334
|
+
const counter = createCounter(debug6, "performance-tracks");
|
|
3022
3335
|
return {
|
|
3023
3336
|
name: "@rangojs/router:performance-tracks",
|
|
3337
|
+
buildEnd() {
|
|
3338
|
+
counter?.flush();
|
|
3339
|
+
},
|
|
3024
3340
|
transform(code, id) {
|
|
3025
3341
|
if (!id.includes("react-server-dom") || !id.includes("client")) return;
|
|
3026
|
-
const
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
);
|
|
3034
|
-
|
|
3342
|
+
const start = counter ? performance.now() : 0;
|
|
3343
|
+
try {
|
|
3344
|
+
const patched = patchRsdwClientDebugInfoRecovery(code);
|
|
3345
|
+
if (!patched.debugInfoVar) return;
|
|
3346
|
+
debug6?.("patched RSDW client (var: %s)", patched.debugInfoVar);
|
|
3347
|
+
return patched.code;
|
|
3348
|
+
} finally {
|
|
3349
|
+
counter?.record(id, performance.now() - start);
|
|
3350
|
+
}
|
|
3035
3351
|
}
|
|
3036
3352
|
};
|
|
3037
3353
|
}
|
|
3038
3354
|
|
|
3039
3355
|
// src/vite/utils/shared-utils.ts
|
|
3040
|
-
|
|
3356
|
+
function resolveRscEntryFromConfig(config) {
|
|
3357
|
+
const entries = config.environments?.["rsc"]?.optimizeDeps?.entries;
|
|
3358
|
+
if (typeof entries === "string") return entries;
|
|
3359
|
+
if (Array.isArray(entries) && entries.length > 0) return entries[0];
|
|
3360
|
+
return void 0;
|
|
3361
|
+
}
|
|
3362
|
+
var versionRolldownPlugin = {
|
|
3041
3363
|
name: "@rangojs/router-version",
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
loader: "js"
|
|
3052
|
-
})
|
|
3053
|
-
);
|
|
3364
|
+
resolveId(id) {
|
|
3365
|
+
if (id === VIRTUAL_IDS.version) return "\0" + VIRTUAL_IDS.version;
|
|
3366
|
+
return void 0;
|
|
3367
|
+
},
|
|
3368
|
+
load(id) {
|
|
3369
|
+
if (id === "\0" + VIRTUAL_IDS.version) {
|
|
3370
|
+
return getVirtualVersionContent("dev");
|
|
3371
|
+
}
|
|
3372
|
+
return void 0;
|
|
3054
3373
|
}
|
|
3055
3374
|
};
|
|
3056
|
-
var
|
|
3057
|
-
plugins: [
|
|
3375
|
+
var sharedRolldownOptions = {
|
|
3376
|
+
plugins: [versionRolldownPlugin, performanceTracksOptimizeDepsPlugin()]
|
|
3058
3377
|
};
|
|
3059
3378
|
function createVirtualEntriesPlugin(entries, routerPathRef) {
|
|
3060
3379
|
const virtualModules = {};
|
|
@@ -3096,8 +3415,29 @@ function createVirtualEntriesPlugin(entries, routerPathRef) {
|
|
|
3096
3415
|
}
|
|
3097
3416
|
};
|
|
3098
3417
|
}
|
|
3418
|
+
function isContentHashedAssetConflict(message) {
|
|
3419
|
+
if (!message) return false;
|
|
3420
|
+
const match = /The emitted file "?([^"\s]+)"? overwrites a previously emitted file/.exec(
|
|
3421
|
+
message
|
|
3422
|
+
);
|
|
3423
|
+
if (!match) return false;
|
|
3424
|
+
const fileName = match[1];
|
|
3425
|
+
const base = fileName.slice(fileName.lastIndexOf("/") + 1);
|
|
3426
|
+
const dot = base.lastIndexOf(".");
|
|
3427
|
+
if (dot <= 0) return false;
|
|
3428
|
+
const stem = base.slice(0, dot);
|
|
3429
|
+
const HASH_LEN = 8;
|
|
3430
|
+
if (stem.length < HASH_LEN + 1 || stem[stem.length - HASH_LEN - 1] !== "-") {
|
|
3431
|
+
return false;
|
|
3432
|
+
}
|
|
3433
|
+
const hash = stem.slice(-HASH_LEN);
|
|
3434
|
+
return /^[A-Za-z0-9_-]+$/.test(hash) && /[A-Z0-9]/.test(hash);
|
|
3435
|
+
}
|
|
3099
3436
|
function onwarn(warning, defaultHandler) {
|
|
3100
|
-
if (warning.code === "MODULE_LEVEL_DIRECTIVE" || warning.code === "SOURCEMAP_ERROR" || warning.code === "EMPTY_BUNDLE") {
|
|
3437
|
+
if (warning.code === "MODULE_LEVEL_DIRECTIVE" || warning.code === "SOURCEMAP_ERROR" || warning.code === "EMPTY_BUNDLE" || warning.code === "INEFFECTIVE_DYNAMIC_IMPORT") {
|
|
3438
|
+
return;
|
|
3439
|
+
}
|
|
3440
|
+
if (warning.code === "FILE_NAME_CONFLICT" && isContentHashedAssetConflict(warning.message)) {
|
|
3101
3441
|
return;
|
|
3102
3442
|
}
|
|
3103
3443
|
if (warning.message?.includes("Sourcemap is likely to be incorrect")) {
|
|
@@ -3116,12 +3456,138 @@ function getManualChunks(id) {
|
|
|
3116
3456
|
return "react";
|
|
3117
3457
|
}
|
|
3118
3458
|
const packageName = getPublishedPackageName();
|
|
3119
|
-
if (normalized.includes(`node_modules/${packageName}/`) ||
|
|
3459
|
+
if (normalized.includes(`node_modules/${packageName}/`) || /\/packages\/(rsc-router|rangojs-router)\/(src|dist)\//.test(normalized)) {
|
|
3120
3460
|
return "router";
|
|
3121
3461
|
}
|
|
3122
3462
|
return void 0;
|
|
3123
3463
|
}
|
|
3124
3464
|
|
|
3465
|
+
// src/vite/plugins/client-ref-hashing.ts
|
|
3466
|
+
import { relative } from "node:path";
|
|
3467
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
3468
|
+
var debug7 = createRangoDebugger(NS.transform);
|
|
3469
|
+
var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
|
|
3470
|
+
var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
|
|
3471
|
+
var FS_PREFIX = "/@fs/";
|
|
3472
|
+
function hashRefKey(relativeId) {
|
|
3473
|
+
return createHash2("sha256").update(relativeId).digest("hex").slice(0, 12);
|
|
3474
|
+
}
|
|
3475
|
+
function computeProductionHash(projectRoot, refKey) {
|
|
3476
|
+
let toHash;
|
|
3477
|
+
if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
|
|
3478
|
+
toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
|
|
3479
|
+
} else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
|
|
3480
|
+
const absPath = decodeURIComponent(
|
|
3481
|
+
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
|
|
3482
|
+
);
|
|
3483
|
+
toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
|
|
3484
|
+
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
3485
|
+
const absPath = refKey.slice(FS_PREFIX.length - 1);
|
|
3486
|
+
toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
|
|
3487
|
+
} else if (refKey.startsWith("/")) {
|
|
3488
|
+
toHash = refKey.slice(1);
|
|
3489
|
+
} else {
|
|
3490
|
+
return refKey;
|
|
3491
|
+
}
|
|
3492
|
+
return hashRefKey(toHash);
|
|
3493
|
+
}
|
|
3494
|
+
var REGISTER_CLIENT_REF_RE = /registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
|
|
3495
|
+
function transformClientRefs(code, projectRoot) {
|
|
3496
|
+
if (!code.includes("registerClientReference")) return null;
|
|
3497
|
+
let hasReplacement = false;
|
|
3498
|
+
const result = code.replace(
|
|
3499
|
+
REGISTER_CLIENT_REF_RE,
|
|
3500
|
+
(match, refKey) => {
|
|
3501
|
+
const hash = computeProductionHash(projectRoot, refKey);
|
|
3502
|
+
if (hash === refKey) return match;
|
|
3503
|
+
hasReplacement = true;
|
|
3504
|
+
return match.replace(`"${refKey}"`, `"${hash}"`);
|
|
3505
|
+
}
|
|
3506
|
+
);
|
|
3507
|
+
return hasReplacement ? result : null;
|
|
3508
|
+
}
|
|
3509
|
+
function hashClientRefs(projectRoot) {
|
|
3510
|
+
const counter = createCounter(debug7, "hash-client-refs");
|
|
3511
|
+
return {
|
|
3512
|
+
name: "@rangojs/router:hash-client-refs",
|
|
3513
|
+
// Run after the RSC plugin's transform (default enforce is normal)
|
|
3514
|
+
enforce: "post",
|
|
3515
|
+
applyToEnvironment(env) {
|
|
3516
|
+
return env.name === "rsc";
|
|
3517
|
+
},
|
|
3518
|
+
buildEnd() {
|
|
3519
|
+
counter?.flush();
|
|
3520
|
+
},
|
|
3521
|
+
transform(code, id) {
|
|
3522
|
+
const start = counter ? performance.now() : 0;
|
|
3523
|
+
try {
|
|
3524
|
+
const result = transformClientRefs(code, projectRoot);
|
|
3525
|
+
if (result === null) return;
|
|
3526
|
+
return { code: result, map: null };
|
|
3527
|
+
} finally {
|
|
3528
|
+
counter?.record(id, performance.now() - start);
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
};
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
// src/vite/utils/client-chunks.ts
|
|
3535
|
+
var debugChunks = createRangoDebugger(NS.chunks);
|
|
3536
|
+
function isSharedRuntime(meta) {
|
|
3537
|
+
return [meta.id, meta.normalizedId].some(
|
|
3538
|
+
(path6) => path6.includes("/node_modules/") || /\/@rangojs\/router\//.test(path6) || /\/packages\/(rangojs-router|rsc-router)\/(src|dist)\//.test(path6)
|
|
3539
|
+
);
|
|
3540
|
+
}
|
|
3541
|
+
function sanitizeGroup(name) {
|
|
3542
|
+
return name.replace(/[^a-zA-Z0-9_-]+/g, "_").replace(/^_+|_+$/g, "") || "app";
|
|
3543
|
+
}
|
|
3544
|
+
var ROUTE_ROOT_DIRS = /* @__PURE__ */ new Set([
|
|
3545
|
+
"routes",
|
|
3546
|
+
"route",
|
|
3547
|
+
"pages",
|
|
3548
|
+
"page",
|
|
3549
|
+
"app",
|
|
3550
|
+
"features",
|
|
3551
|
+
"feature",
|
|
3552
|
+
"views",
|
|
3553
|
+
"view",
|
|
3554
|
+
"handlers",
|
|
3555
|
+
"urls",
|
|
3556
|
+
"modules",
|
|
3557
|
+
"screens",
|
|
3558
|
+
"sections"
|
|
3559
|
+
]);
|
|
3560
|
+
function directoryClientChunks(meta, ctx) {
|
|
3561
|
+
if (isSharedRuntime(meta)) {
|
|
3562
|
+
return void 0;
|
|
3563
|
+
}
|
|
3564
|
+
if (ctx?.fallbackRefs.size && ctx.fallbackRefs.has(hashRefKey(meta.normalizedId))) {
|
|
3565
|
+
debugChunks?.("fallback %s -> app-fallback", meta.normalizedId);
|
|
3566
|
+
return "app-fallback";
|
|
3567
|
+
}
|
|
3568
|
+
const segments = meta.normalizedId.split("/").filter(Boolean);
|
|
3569
|
+
const dirCount = segments.length - 1;
|
|
3570
|
+
if (dirCount >= 1) {
|
|
3571
|
+
for (let i = 0; i < dirCount - 1; i++) {
|
|
3572
|
+
if (ROUTE_ROOT_DIRS.has(segments[i].toLowerCase())) {
|
|
3573
|
+
const group = `app-${sanitizeGroup(segments[i + 1])}`;
|
|
3574
|
+
debugChunks?.("split %s -> %s", meta.normalizedId, group);
|
|
3575
|
+
return group;
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
debugChunks?.(
|
|
3580
|
+
"shared %s (no route-root marker; inherits default grouping)",
|
|
3581
|
+
meta.normalizedId
|
|
3582
|
+
);
|
|
3583
|
+
return void 0;
|
|
3584
|
+
}
|
|
3585
|
+
function resolveClientChunks(option, ctx) {
|
|
3586
|
+
if (!option) return void 0;
|
|
3587
|
+
if (option === true) return (meta) => directoryClientChunks(meta, ctx);
|
|
3588
|
+
return option;
|
|
3589
|
+
}
|
|
3590
|
+
|
|
3125
3591
|
// src/vite/utils/banner.ts
|
|
3126
3592
|
var rangoVersion = package_default.version;
|
|
3127
3593
|
var _bannerPrinted = false;
|
|
@@ -3158,15 +3624,7 @@ function createVersionInjectorPlugin(rscEntryPath) {
|
|
|
3158
3624
|
enforce: "pre",
|
|
3159
3625
|
configResolved(config) {
|
|
3160
3626
|
let entryPath = rscEntryPath;
|
|
3161
|
-
if (!entryPath)
|
|
3162
|
-
const rscEnvConfig = config.environments?.["rsc"];
|
|
3163
|
-
const entries = rscEnvConfig?.optimizeDeps?.entries;
|
|
3164
|
-
if (typeof entries === "string") {
|
|
3165
|
-
entryPath = entries;
|
|
3166
|
-
} else if (Array.isArray(entries) && entries.length > 0) {
|
|
3167
|
-
entryPath = entries[0];
|
|
3168
|
-
}
|
|
3169
|
-
}
|
|
3627
|
+
if (!entryPath) entryPath = resolveRscEntryFromConfig(config);
|
|
3170
3628
|
if (entryPath) {
|
|
3171
3629
|
resolvedEntryPath = resolve4(config.root, entryPath);
|
|
3172
3630
|
}
|
|
@@ -3178,11 +3636,10 @@ function createVersionInjectorPlugin(rscEntryPath) {
|
|
|
3178
3636
|
if (normalizedId !== normalizedEntry) {
|
|
3179
3637
|
return null;
|
|
3180
3638
|
}
|
|
3181
|
-
const prepend = [
|
|
3639
|
+
const prepend = [
|
|
3640
|
+
`import "virtual:rsc-router/routes-manifest";`
|
|
3641
|
+
];
|
|
3182
3642
|
let newCode = code;
|
|
3183
|
-
if (!code.includes("virtual:rsc-router/routes-manifest")) {
|
|
3184
|
-
prepend.push(`import "virtual:rsc-router/routes-manifest";`);
|
|
3185
|
-
}
|
|
3186
3643
|
const needsVersion = code.includes("createRSCHandler") && !code.includes("@rangojs/router:version") && /createRSCHandler\s*\(\s*\{/.test(code);
|
|
3187
3644
|
if (needsVersion) {
|
|
3188
3645
|
prepend.push(`import { VERSION } from "@rangojs/router:version";`);
|
|
@@ -3191,8 +3648,21 @@ function createVersionInjectorPlugin(rscEntryPath) {
|
|
|
3191
3648
|
"createRSCHandler({\n version: VERSION,"
|
|
3192
3649
|
);
|
|
3193
3650
|
}
|
|
3194
|
-
|
|
3195
|
-
|
|
3651
|
+
const lines = newCode.split("\n");
|
|
3652
|
+
let insertAt = 0;
|
|
3653
|
+
while (insertAt < lines.length) {
|
|
3654
|
+
const trimmed = lines[insertAt].trim();
|
|
3655
|
+
if (trimmed === "" || /^\/\/\/\s*<reference\b/.test(trimmed)) {
|
|
3656
|
+
insertAt++;
|
|
3657
|
+
} else {
|
|
3658
|
+
break;
|
|
3659
|
+
}
|
|
3660
|
+
}
|
|
3661
|
+
newCode = [
|
|
3662
|
+
...lines.slice(0, insertAt),
|
|
3663
|
+
...prepend,
|
|
3664
|
+
...lines.slice(insertAt)
|
|
3665
|
+
].join("\n");
|
|
3196
3666
|
return {
|
|
3197
3667
|
code: newCode,
|
|
3198
3668
|
map: null
|
|
@@ -3202,21 +3672,23 @@ function createVersionInjectorPlugin(rscEntryPath) {
|
|
|
3202
3672
|
}
|
|
3203
3673
|
|
|
3204
3674
|
// src/vite/plugins/cjs-to-esm.ts
|
|
3675
|
+
var debug8 = createRangoDebugger(NS.transform);
|
|
3205
3676
|
function createCjsToEsmPlugin() {
|
|
3206
3677
|
return {
|
|
3207
3678
|
name: "@rangojs/router:cjs-to-esm",
|
|
3208
3679
|
enforce: "pre",
|
|
3209
3680
|
transform(code, id) {
|
|
3210
|
-
const cleanId = id.split("?")[0];
|
|
3211
|
-
if (cleanId.includes("vendor/react-server-dom/client.browser.js")
|
|
3681
|
+
const cleanId = id.split("?")[0].replaceAll("\\", "/");
|
|
3682
|
+
if (cleanId.includes("vendor/react-server-dom/client.browser.js")) {
|
|
3212
3683
|
const isProd = process.env.NODE_ENV === "production";
|
|
3213
3684
|
const cjsFile = isProd ? "./cjs/react-server-dom-webpack-client.browser.production.js" : "./cjs/react-server-dom-webpack-client.browser.development.js";
|
|
3685
|
+
debug8?.("cjs-to-esm entry redirect %s", id);
|
|
3214
3686
|
return {
|
|
3215
3687
|
code: `export * from "${cjsFile}";`,
|
|
3216
3688
|
map: null
|
|
3217
3689
|
};
|
|
3218
3690
|
}
|
|
3219
|
-
if (
|
|
3691
|
+
if (cleanId.includes("vendor/react-server-dom/cjs/") && cleanId.includes("client.browser")) {
|
|
3220
3692
|
let transformed = code;
|
|
3221
3693
|
const licenseMatch = transformed.match(/^\/\*\*[\s\S]*?\*\//);
|
|
3222
3694
|
const license = licenseMatch ? licenseMatch[0] : "";
|
|
@@ -3246,6 +3718,7 @@ function createCjsToEsmPlugin() {
|
|
|
3246
3718
|
"export const $1 ="
|
|
3247
3719
|
);
|
|
3248
3720
|
transformed = license + "\n" + transformed;
|
|
3721
|
+
debug8?.("cjs-to-esm body rewrite %s", id);
|
|
3249
3722
|
return {
|
|
3250
3723
|
code: transformed,
|
|
3251
3724
|
map: null
|
|
@@ -3260,7 +3733,7 @@ function createCjsToEsmPlugin() {
|
|
|
3260
3733
|
import { createServer as createViteServer } from "vite";
|
|
3261
3734
|
import { resolve as resolve8 } from "node:path";
|
|
3262
3735
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
3263
|
-
import { createRequire } from "node:module";
|
|
3736
|
+
import { createRequire as createRequire2, register } from "node:module";
|
|
3264
3737
|
import { pathToFileURL } from "node:url";
|
|
3265
3738
|
|
|
3266
3739
|
// src/vite/plugins/virtual-stub-plugin.ts
|
|
@@ -3287,61 +3760,112 @@ function createVirtualStubPlugin() {
|
|
|
3287
3760
|
};
|
|
3288
3761
|
}
|
|
3289
3762
|
|
|
3290
|
-
// src/vite/plugins/
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
var
|
|
3294
|
-
var
|
|
3295
|
-
var
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
function
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
}
|
|
3330
|
-
function hashClientRefs(projectRoot) {
|
|
3763
|
+
// src/vite/plugins/cloudflare-protocol-stub.ts
|
|
3764
|
+
var VIRTUAL_PREFIX = "virtual:rango-cloudflare-stub-";
|
|
3765
|
+
var NULL_PREFIX = "\0" + VIRTUAL_PREFIX;
|
|
3766
|
+
var CF_PREFIX = "cloudflare:";
|
|
3767
|
+
var BUILD_ENV_GLOBAL_KEY = "__rango_build_env__";
|
|
3768
|
+
var SOURCE_EXT_RE = /\.[mc]?[jt]sx?$/;
|
|
3769
|
+
var IMPORT_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
3770
|
+
"ImportDeclaration",
|
|
3771
|
+
"ImportExpression",
|
|
3772
|
+
"ExportNamedDeclaration",
|
|
3773
|
+
"ExportAllDeclaration"
|
|
3774
|
+
]);
|
|
3775
|
+
var STUBS = {
|
|
3776
|
+
"cloudflare:workers": `
|
|
3777
|
+
export class DurableObject { constructor(_ctx, _env) {} }
|
|
3778
|
+
export class WorkerEntrypoint { constructor(_ctx, _env) {} }
|
|
3779
|
+
export class WorkflowEntrypoint { constructor(_ctx, _env) {} }
|
|
3780
|
+
export class RpcTarget {}
|
|
3781
|
+
export const env = globalThis[${JSON.stringify(BUILD_ENV_GLOBAL_KEY)}] ?? {};
|
|
3782
|
+
export default {};
|
|
3783
|
+
`,
|
|
3784
|
+
"cloudflare:email": `
|
|
3785
|
+
export class EmailMessage { constructor(_from, _to, _raw) {} }
|
|
3786
|
+
export default {};
|
|
3787
|
+
`,
|
|
3788
|
+
"cloudflare:sockets": `
|
|
3789
|
+
export function connect() { return {}; }
|
|
3790
|
+
export default {};
|
|
3791
|
+
`,
|
|
3792
|
+
"cloudflare:workflows": `
|
|
3793
|
+
export class NonRetryableError extends Error {
|
|
3794
|
+
constructor(message, name) { super(message); this.name = name ?? "NonRetryableError"; }
|
|
3795
|
+
}
|
|
3796
|
+
export default {};
|
|
3797
|
+
`
|
|
3798
|
+
};
|
|
3799
|
+
var FALLBACK_STUB = `export default {};
|
|
3800
|
+
`;
|
|
3801
|
+
function createCloudflareProtocolStubPlugin() {
|
|
3331
3802
|
return {
|
|
3332
|
-
name: "@rangojs/router:
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3803
|
+
name: "@rangojs/router:cloudflare-protocol-stub",
|
|
3804
|
+
transform(code, id) {
|
|
3805
|
+
const cleanId = id.split("?")[0] ?? id;
|
|
3806
|
+
if (!SOURCE_EXT_RE.test(cleanId)) return null;
|
|
3807
|
+
if (!code.includes(CF_PREFIX)) return null;
|
|
3808
|
+
let ast;
|
|
3809
|
+
try {
|
|
3810
|
+
ast = this.parse(code, { lang: "tsx" });
|
|
3811
|
+
} catch {
|
|
3812
|
+
return null;
|
|
3813
|
+
}
|
|
3814
|
+
const hits = [];
|
|
3815
|
+
walk(ast, (node) => {
|
|
3816
|
+
if (!IMPORT_NODE_TYPES.has(node.type)) return;
|
|
3817
|
+
const source = node.source;
|
|
3818
|
+
if (!source || source.type !== "Literal") return;
|
|
3819
|
+
if (typeof source.value !== "string") return;
|
|
3820
|
+
if (!source.value.startsWith(CF_PREFIX)) return;
|
|
3821
|
+
if (typeof source.start !== "number" || typeof source.end !== "number")
|
|
3822
|
+
return;
|
|
3823
|
+
hits.push({
|
|
3824
|
+
start: source.start,
|
|
3825
|
+
end: source.end,
|
|
3826
|
+
value: source.value
|
|
3827
|
+
});
|
|
3828
|
+
});
|
|
3829
|
+
if (hits.length === 0) return null;
|
|
3830
|
+
hits.sort((a, b) => b.start - a.start);
|
|
3831
|
+
let out = code;
|
|
3832
|
+
for (const hit of hits) {
|
|
3833
|
+
const submodule = hit.value.slice(CF_PREFIX.length);
|
|
3834
|
+
const quote = code[hit.start] === "'" ? "'" : '"';
|
|
3835
|
+
out = out.slice(0, hit.start) + quote + VIRTUAL_PREFIX + submodule + quote + out.slice(hit.end);
|
|
3836
|
+
}
|
|
3837
|
+
return { code: out, map: null };
|
|
3337
3838
|
},
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3839
|
+
resolveId(id) {
|
|
3840
|
+
if (id.startsWith(VIRTUAL_PREFIX)) {
|
|
3841
|
+
return "\0" + id;
|
|
3842
|
+
}
|
|
3843
|
+
return null;
|
|
3844
|
+
},
|
|
3845
|
+
load(id) {
|
|
3846
|
+
if (!id.startsWith(NULL_PREFIX)) return null;
|
|
3847
|
+
const submodule = id.slice(NULL_PREFIX.length);
|
|
3848
|
+
const specifier = CF_PREFIX + submodule;
|
|
3849
|
+
return STUBS[specifier] ?? FALLBACK_STUB;
|
|
3342
3850
|
}
|
|
3343
3851
|
};
|
|
3344
3852
|
}
|
|
3853
|
+
function walk(node, visit) {
|
|
3854
|
+
if (!node || typeof node !== "object") return;
|
|
3855
|
+
if (Array.isArray(node)) {
|
|
3856
|
+
for (const child of node) walk(child, visit);
|
|
3857
|
+
return;
|
|
3858
|
+
}
|
|
3859
|
+
const n = node;
|
|
3860
|
+
if (typeof n.type !== "string") return;
|
|
3861
|
+
visit(n);
|
|
3862
|
+
for (const key in n) {
|
|
3863
|
+
if (key === "loc" || key === "start" || key === "end" || key === "range") {
|
|
3864
|
+
continue;
|
|
3865
|
+
}
|
|
3866
|
+
walk(n[key], visit);
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3345
3869
|
|
|
3346
3870
|
// src/vite/utils/bundle-analysis.ts
|
|
3347
3871
|
function findMatchingParenInBundle(code, openParenPos) {
|
|
@@ -3373,7 +3897,7 @@ function extractHandlerExportsFromChunk(chunkCode, handlerModules, fnName, detec
|
|
|
3373
3897
|
if (detectPassthrough) {
|
|
3374
3898
|
const eFnName = escapeRegExp(fnName);
|
|
3375
3899
|
const callStartRe = new RegExp(
|
|
3376
|
-
`const\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
|
|
3900
|
+
`(?:const|let|var)\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
|
|
3377
3901
|
);
|
|
3378
3902
|
const callStart = callStartRe.exec(chunkCode);
|
|
3379
3903
|
if (callStart) {
|
|
@@ -3398,7 +3922,7 @@ function evictHandlerCode(code, exports, fnName, brand) {
|
|
|
3398
3922
|
if (passthrough) continue;
|
|
3399
3923
|
const eName = escapeRegExp(name);
|
|
3400
3924
|
const callStartRe = new RegExp(
|
|
3401
|
-
`const\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
|
|
3925
|
+
`(?:const|let|var)\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
|
|
3402
3926
|
);
|
|
3403
3927
|
const startMatch = callStartRe.exec(modified);
|
|
3404
3928
|
if (!startMatch) continue;
|
|
@@ -3433,6 +3957,8 @@ function createDiscoveryState(entryPath, opts) {
|
|
|
3433
3957
|
projectRoot: "",
|
|
3434
3958
|
isBuildMode: false,
|
|
3435
3959
|
userResolveAlias: void 0,
|
|
3960
|
+
userRunnerConfig: void 0,
|
|
3961
|
+
userResolvePlugins: [],
|
|
3436
3962
|
scanFilter: void 0,
|
|
3437
3963
|
cachedRouterFiles: void 0,
|
|
3438
3964
|
opts,
|
|
@@ -3454,7 +3980,8 @@ function createDiscoveryState(entryPath, opts) {
|
|
|
3454
3980
|
devServerOrigin: null,
|
|
3455
3981
|
devServer: null,
|
|
3456
3982
|
selfWrittenGenFiles: /* @__PURE__ */ new Map(),
|
|
3457
|
-
SELF_WRITE_WINDOW_MS: 5e3
|
|
3983
|
+
SELF_WRITE_WINDOW_MS: 5e3,
|
|
3984
|
+
lastDiscoveryError: null
|
|
3458
3985
|
};
|
|
3459
3986
|
}
|
|
3460
3987
|
|
|
@@ -3466,6 +3993,12 @@ function markSelfGenWrite(state, filePath, content) {
|
|
|
3466
3993
|
state.selfWrittenGenFiles.set(filePath, { at: Date.now(), hash });
|
|
3467
3994
|
}
|
|
3468
3995
|
function consumeSelfGenWrite(state, filePath) {
|
|
3996
|
+
return checkSelfGenWrite(state, filePath, true);
|
|
3997
|
+
}
|
|
3998
|
+
function peekSelfGenWrite(state, filePath) {
|
|
3999
|
+
return checkSelfGenWrite(state, filePath, false);
|
|
4000
|
+
}
|
|
4001
|
+
function checkSelfGenWrite(state, filePath, consume) {
|
|
3469
4002
|
const info = state.selfWrittenGenFiles.get(filePath);
|
|
3470
4003
|
if (!info) return false;
|
|
3471
4004
|
if (Date.now() - info.at > state.SELF_WRITE_WINDOW_MS) {
|
|
@@ -3476,7 +4009,7 @@ function consumeSelfGenWrite(state, filePath) {
|
|
|
3476
4009
|
const current = readFileSync3(filePath, "utf-8");
|
|
3477
4010
|
const currentHash = createHash3("sha256").update(current).digest("hex");
|
|
3478
4011
|
if (currentHash === info.hash) {
|
|
3479
|
-
state.selfWrittenGenFiles.delete(filePath);
|
|
4012
|
+
if (consume) state.selfWrittenGenFiles.delete(filePath);
|
|
3480
4013
|
return true;
|
|
3481
4014
|
}
|
|
3482
4015
|
return false;
|
|
@@ -3486,11 +4019,14 @@ function consumeSelfGenWrite(state, filePath) {
|
|
|
3486
4019
|
}
|
|
3487
4020
|
}
|
|
3488
4021
|
|
|
3489
|
-
// src/
|
|
4022
|
+
// src/build/prefix-tree-utils.ts
|
|
3490
4023
|
function flattenLeafEntries(prefixTree, routeManifest, result) {
|
|
3491
|
-
function visit(node) {
|
|
4024
|
+
function visit(node, ancestorStaticPrefixes) {
|
|
3492
4025
|
const children = node.children || {};
|
|
3493
4026
|
if (Object.keys(children).length === 0 && node.routes && node.routes.length > 0) {
|
|
4027
|
+
if (ancestorStaticPrefixes.has(node.staticPrefix)) {
|
|
4028
|
+
return;
|
|
4029
|
+
}
|
|
3494
4030
|
const routes = {};
|
|
3495
4031
|
for (const name of node.routes) {
|
|
3496
4032
|
if (name in routeManifest) {
|
|
@@ -3499,13 +4035,15 @@ function flattenLeafEntries(prefixTree, routeManifest, result) {
|
|
|
3499
4035
|
}
|
|
3500
4036
|
result.push({ staticPrefix: node.staticPrefix, routes });
|
|
3501
4037
|
} else {
|
|
4038
|
+
const nextAncestors = new Set(ancestorStaticPrefixes);
|
|
4039
|
+
nextAncestors.add(node.staticPrefix);
|
|
3502
4040
|
for (const child of Object.values(children)) {
|
|
3503
|
-
visit(child);
|
|
4041
|
+
visit(child, nextAncestors);
|
|
3504
4042
|
}
|
|
3505
4043
|
}
|
|
3506
4044
|
}
|
|
3507
4045
|
for (const node of Object.values(prefixTree)) {
|
|
3508
|
-
visit(node);
|
|
4046
|
+
visit(node, /* @__PURE__ */ new Set());
|
|
3509
4047
|
}
|
|
3510
4048
|
}
|
|
3511
4049
|
function buildRouteToStaticPrefix(prefixTree, result) {
|
|
@@ -3522,6 +4060,8 @@ function buildRouteToStaticPrefix(prefixTree, result) {
|
|
|
3522
4060
|
visit(node);
|
|
3523
4061
|
}
|
|
3524
4062
|
}
|
|
4063
|
+
|
|
4064
|
+
// src/vite/utils/manifest-utils.ts
|
|
3525
4065
|
function jsonParseExpression(value) {
|
|
3526
4066
|
const json = JSON.stringify(value);
|
|
3527
4067
|
const escaped = json.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
@@ -3698,8 +4238,14 @@ function copyStagedBuildAssets(projectRoot, fileNames) {
|
|
|
3698
4238
|
}
|
|
3699
4239
|
|
|
3700
4240
|
// src/vite/discovery/prerender-collection.ts
|
|
4241
|
+
var debug9 = createRangoDebugger(NS.prerender);
|
|
3701
4242
|
async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
3702
4243
|
if (!state.opts?.enableBuildPrerender || !state.isBuildMode) return;
|
|
4244
|
+
const overallStart = debug9 ? performance.now() : 0;
|
|
4245
|
+
debug9?.(
|
|
4246
|
+
"expandPrerenderRoutes: start (%d router manifest(s))",
|
|
4247
|
+
allManifests.length
|
|
4248
|
+
);
|
|
3703
4249
|
const entries = [];
|
|
3704
4250
|
const allRoutes = {};
|
|
3705
4251
|
for (const { manifest: m } of allManifests) {
|
|
@@ -3726,7 +4272,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3726
4272
|
const progressInterval = totalDynamic > 0 ? setInterval(() => {
|
|
3727
4273
|
const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
|
|
3728
4274
|
console.log(
|
|
3729
|
-
`[
|
|
4275
|
+
`[rango] Resolving prerender params... ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
|
|
3730
4276
|
);
|
|
3731
4277
|
}, 5e3) : void 0;
|
|
3732
4278
|
try {
|
|
@@ -3749,6 +4295,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3749
4295
|
});
|
|
3750
4296
|
} else {
|
|
3751
4297
|
if (def?.getParams) {
|
|
4298
|
+
const getParamsStart = debug9 ? performance.now() : 0;
|
|
3752
4299
|
try {
|
|
3753
4300
|
const buildVars = {};
|
|
3754
4301
|
const buildEnv = state.resolvedBuildEnv;
|
|
@@ -3762,11 +4309,17 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3762
4309
|
get env() {
|
|
3763
4310
|
if (buildEnv !== void 0) return buildEnv;
|
|
3764
4311
|
throw new Error(
|
|
3765
|
-
"[
|
|
4312
|
+
"[rango] ctx.env is not available during build-time getParams(). Configure buildEnv in your rango() plugin options to enable build-time env access."
|
|
3766
4313
|
);
|
|
3767
4314
|
}
|
|
3768
4315
|
};
|
|
3769
4316
|
const paramsList = await def.getParams(getParamsCtx);
|
|
4317
|
+
debug9?.(
|
|
4318
|
+
"getParams %s -> %d params (%sms)",
|
|
4319
|
+
routeName,
|
|
4320
|
+
paramsList.length,
|
|
4321
|
+
(performance.now() - getParamsStart).toFixed(1)
|
|
4322
|
+
);
|
|
3770
4323
|
const concurrency = def.options?.concurrency ?? 1;
|
|
3771
4324
|
const hasBuildVars = Object.keys(buildVars).length > 0 || Object.getOwnPropertySymbols(buildVars).length > 0;
|
|
3772
4325
|
for (const params of paramsList) {
|
|
@@ -3797,7 +4350,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3797
4350
|
resolvedRoutes++;
|
|
3798
4351
|
if (err.name === "Skip") {
|
|
3799
4352
|
console.log(
|
|
3800
|
-
`[
|
|
4353
|
+
`[rango] SKIP route "${routeName}" - ${err.message}`
|
|
3801
4354
|
);
|
|
3802
4355
|
notifyOnError(
|
|
3803
4356
|
registry,
|
|
@@ -3810,14 +4363,14 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3810
4363
|
continue;
|
|
3811
4364
|
}
|
|
3812
4365
|
console.error(
|
|
3813
|
-
`[
|
|
4366
|
+
`[rango] Failed to get params for prerender route "${routeName}": ${err.message}`
|
|
3814
4367
|
);
|
|
3815
4368
|
notifyOnError(registry, err, "prerender", routeName);
|
|
3816
4369
|
throw err;
|
|
3817
4370
|
}
|
|
3818
4371
|
} else {
|
|
3819
4372
|
console.warn(
|
|
3820
|
-
`[
|
|
4373
|
+
`[rango] Dynamic prerender route "${routeName}" has no getParams(), skipping`
|
|
3821
4374
|
);
|
|
3822
4375
|
}
|
|
3823
4376
|
}
|
|
@@ -3828,15 +4381,26 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3828
4381
|
clearInterval(progressInterval);
|
|
3829
4382
|
const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
|
|
3830
4383
|
console.log(
|
|
3831
|
-
`[
|
|
4384
|
+
`[rango] Resolved prerender params: ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
|
|
3832
4385
|
);
|
|
3833
4386
|
}
|
|
3834
4387
|
}
|
|
3835
|
-
if (entries.length === 0)
|
|
4388
|
+
if (entries.length === 0) {
|
|
4389
|
+
debug9?.(
|
|
4390
|
+
"no prerender entries (done in %sms)",
|
|
4391
|
+
(performance.now() - overallStart).toFixed(1)
|
|
4392
|
+
);
|
|
4393
|
+
return;
|
|
4394
|
+
}
|
|
3836
4395
|
const maxConcurrency = Math.max(...entries.map((e) => e.concurrency));
|
|
3837
4396
|
const concurrencyNote = maxConcurrency > 1 ? ` (concurrency: ${maxConcurrency})` : "";
|
|
3838
4397
|
console.log(
|
|
3839
|
-
`[
|
|
4398
|
+
`[rango] Pre-rendering ${entries.length} URL(s)${concurrencyNote}...`
|
|
4399
|
+
);
|
|
4400
|
+
debug9?.(
|
|
4401
|
+
"prerender loop: %d entries, max concurrency %d",
|
|
4402
|
+
entries.length,
|
|
4403
|
+
maxConcurrency
|
|
3840
4404
|
);
|
|
3841
4405
|
const { hashParams } = await rscEnv.runner.import("@rangojs/router/build");
|
|
3842
4406
|
const manifestEntries = {};
|
|
@@ -3864,7 +4428,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3864
4428
|
if (result.passthrough) {
|
|
3865
4429
|
const elapsed2 = (performance.now() - startUrl).toFixed(0);
|
|
3866
4430
|
console.log(
|
|
3867
|
-
`[
|
|
4431
|
+
`[rango] PASS ${entry.urlPath.padEnd(40)} (${elapsed2}ms) - live fallback`
|
|
3868
4432
|
);
|
|
3869
4433
|
doneCount++;
|
|
3870
4434
|
break;
|
|
@@ -3884,10 +4448,9 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3884
4448
|
const interceptKey = `${result.routeName}/${paramHash}/i`;
|
|
3885
4449
|
const interceptValue = JSON.stringify({
|
|
3886
4450
|
segments: [...result.segments, ...result.interceptSegments],
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
}
|
|
4451
|
+
// interceptHandles is the pre-encoded MERGED (main + intercept)
|
|
4452
|
+
// handle string (the producer merged before encoding).
|
|
4453
|
+
handles: result.interceptHandles ?? ""
|
|
3891
4454
|
});
|
|
3892
4455
|
manifestEntries[interceptKey] = stageBuildAssetModule(
|
|
3893
4456
|
state.projectRoot,
|
|
@@ -3897,7 +4460,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3897
4460
|
}
|
|
3898
4461
|
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
3899
4462
|
console.log(
|
|
3900
|
-
`[
|
|
4463
|
+
`[rango] OK ${entry.urlPath.padEnd(40)} (${elapsed}ms)`
|
|
3901
4464
|
);
|
|
3902
4465
|
doneCount++;
|
|
3903
4466
|
break;
|
|
@@ -3905,7 +4468,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3905
4468
|
if (err.name === "Skip") {
|
|
3906
4469
|
const elapsed2 = (performance.now() - startUrl).toFixed(0);
|
|
3907
4470
|
console.log(
|
|
3908
|
-
`[
|
|
4471
|
+
`[rango] SKIP ${entry.urlPath.padEnd(40)} (${elapsed2}ms) - ${err.message}`
|
|
3909
4472
|
);
|
|
3910
4473
|
skipCount++;
|
|
3911
4474
|
notifyOnError(
|
|
@@ -3920,7 +4483,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3920
4483
|
}
|
|
3921
4484
|
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
3922
4485
|
console.error(
|
|
3923
|
-
`[
|
|
4486
|
+
`[rango] FAIL ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`
|
|
3924
4487
|
);
|
|
3925
4488
|
notifyOnError(
|
|
3926
4489
|
registry,
|
|
@@ -3942,12 +4505,24 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3942
4505
|
const parts = [`${doneCount} done`];
|
|
3943
4506
|
if (skipCount > 0) parts.push(`${skipCount} skipped`);
|
|
3944
4507
|
console.log(
|
|
3945
|
-
`[
|
|
4508
|
+
`[rango] Pre-render complete: ${parts.join(", ")} (${totalElapsed}ms total)`
|
|
4509
|
+
);
|
|
4510
|
+
debug9?.(
|
|
4511
|
+
"expandPrerenderRoutes done: %d done, %d skipped, %sms (overall %sms)",
|
|
4512
|
+
doneCount,
|
|
4513
|
+
skipCount,
|
|
4514
|
+
totalElapsed,
|
|
4515
|
+
(performance.now() - overallStart).toFixed(1)
|
|
3946
4516
|
);
|
|
3947
4517
|
}
|
|
3948
4518
|
async function renderStaticHandlers(state, rscEnv, registry) {
|
|
3949
4519
|
if (!state.opts?.enableBuildPrerender || !state.isBuildMode || !state.resolvedStaticModules?.size)
|
|
3950
4520
|
return;
|
|
4521
|
+
const overallStart = debug9 ? performance.now() : 0;
|
|
4522
|
+
debug9?.(
|
|
4523
|
+
"renderStaticHandlers: start (%d static module(s))",
|
|
4524
|
+
state.resolvedStaticModules.size
|
|
4525
|
+
);
|
|
3951
4526
|
const manifestEntries = {};
|
|
3952
4527
|
let staticDone = 0;
|
|
3953
4528
|
let staticSkip = 0;
|
|
@@ -3956,16 +4531,14 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3956
4531
|
totalStaticCount += exportNames.length;
|
|
3957
4532
|
}
|
|
3958
4533
|
const startStatic = performance.now();
|
|
3959
|
-
console.log(
|
|
3960
|
-
`[rsc-router] Rendering ${totalStaticCount} static handler(s)...`
|
|
3961
|
-
);
|
|
4534
|
+
console.log(`[rango] Rendering ${totalStaticCount} static handler(s)...`);
|
|
3962
4535
|
for (const [moduleId, exportNames] of state.resolvedStaticModules) {
|
|
3963
4536
|
let mod;
|
|
3964
4537
|
try {
|
|
3965
4538
|
mod = await rscEnv.runner.import(moduleId);
|
|
3966
4539
|
} catch (err) {
|
|
3967
4540
|
console.error(
|
|
3968
|
-
`[
|
|
4541
|
+
`[rango] Failed to import static module ${moduleId}: ${err.message}`
|
|
3969
4542
|
);
|
|
3970
4543
|
notifyOnError(registry, err, "static");
|
|
3971
4544
|
throw err;
|
|
@@ -3987,7 +4560,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3987
4560
|
!state.isBuildMode
|
|
3988
4561
|
);
|
|
3989
4562
|
if (result) {
|
|
3990
|
-
const hasHandles =
|
|
4563
|
+
const hasHandles = result.handles !== "";
|
|
3991
4564
|
const exportValue = hasHandles ? JSON.stringify(result) : JSON.stringify(result.encoded);
|
|
3992
4565
|
manifestEntries[def.$$id] = stageBuildAssetModule(
|
|
3993
4566
|
state.projectRoot,
|
|
@@ -3995,9 +4568,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3995
4568
|
exportValue
|
|
3996
4569
|
);
|
|
3997
4570
|
const elapsed = (performance.now() - startHandler).toFixed(0);
|
|
3998
|
-
console.log(
|
|
3999
|
-
`[rsc-router] OK ${name.padEnd(40)} (${elapsed}ms)`
|
|
4000
|
-
);
|
|
4571
|
+
console.log(`[rango] OK ${name.padEnd(40)} (${elapsed}ms)`);
|
|
4001
4572
|
staticDone++;
|
|
4002
4573
|
handled = true;
|
|
4003
4574
|
break;
|
|
@@ -4006,7 +4577,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4006
4577
|
if (err.name === "Skip") {
|
|
4007
4578
|
const elapsed2 = (performance.now() - startHandler).toFixed(0);
|
|
4008
4579
|
console.log(
|
|
4009
|
-
`[
|
|
4580
|
+
`[rango] SKIP ${name.padEnd(40)} (${elapsed2}ms) - ${err.message}`
|
|
4010
4581
|
);
|
|
4011
4582
|
staticSkip++;
|
|
4012
4583
|
notifyOnError(registry, err, "static", void 0, void 0, true);
|
|
@@ -4015,16 +4586,14 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4015
4586
|
}
|
|
4016
4587
|
const elapsed = (performance.now() - startHandler).toFixed(0);
|
|
4017
4588
|
console.error(
|
|
4018
|
-
`[
|
|
4589
|
+
`[rango] FAIL ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`
|
|
4019
4590
|
);
|
|
4020
4591
|
notifyOnError(registry, err, "static");
|
|
4021
4592
|
throw err;
|
|
4022
4593
|
}
|
|
4023
4594
|
}
|
|
4024
4595
|
if (!handled) {
|
|
4025
|
-
console.warn(
|
|
4026
|
-
`[rsc-router] No router could render static handler "${name}"`
|
|
4027
|
-
);
|
|
4596
|
+
console.warn(`[rango] No router could render static handler "${name}"`);
|
|
4028
4597
|
}
|
|
4029
4598
|
}
|
|
4030
4599
|
}
|
|
@@ -4035,38 +4604,118 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4035
4604
|
const staticParts = [`${staticDone} done`];
|
|
4036
4605
|
if (staticSkip > 0) staticParts.push(`${staticSkip} skipped`);
|
|
4037
4606
|
console.log(
|
|
4038
|
-
`[
|
|
4607
|
+
`[rango] Static render complete: ${staticParts.join(", ")} (${totalStaticElapsed}ms total)`
|
|
4608
|
+
);
|
|
4609
|
+
debug9?.(
|
|
4610
|
+
"renderStaticHandlers done: %d done, %d skipped, %sms (overall %sms)",
|
|
4611
|
+
staticDone,
|
|
4612
|
+
staticSkip,
|
|
4613
|
+
totalStaticElapsed,
|
|
4614
|
+
(performance.now() - overallStart).toFixed(1)
|
|
4039
4615
|
);
|
|
4040
4616
|
}
|
|
4041
4617
|
|
|
4618
|
+
// src/vite/discovery/discovery-errors.ts
|
|
4619
|
+
function indent(text, pad) {
|
|
4620
|
+
return text.split("\n").map((line) => line.length > 0 ? pad + line : line).join("\n");
|
|
4621
|
+
}
|
|
4622
|
+
async function invokeLazyMount(loader, context, errors) {
|
|
4623
|
+
try {
|
|
4624
|
+
await loader();
|
|
4625
|
+
} catch (error) {
|
|
4626
|
+
errors.push({ context, error });
|
|
4627
|
+
}
|
|
4628
|
+
}
|
|
4629
|
+
function isLazyMount(route) {
|
|
4630
|
+
return !!route && route.kind === "lazy" && typeof route.handler === "function";
|
|
4631
|
+
}
|
|
4632
|
+
async function resolveHostRouterHandlers(hostRegistry) {
|
|
4633
|
+
const errors = [];
|
|
4634
|
+
for (const [hostId, entry] of hostRegistry) {
|
|
4635
|
+
for (const route of entry.routes) {
|
|
4636
|
+
if (isLazyMount(route)) {
|
|
4637
|
+
await invokeLazyMount(
|
|
4638
|
+
route.handler,
|
|
4639
|
+
`host "${hostId}" route handler`,
|
|
4640
|
+
errors
|
|
4641
|
+
);
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
if (isLazyMount(entry.fallback)) {
|
|
4645
|
+
await invokeLazyMount(
|
|
4646
|
+
entry.fallback.handler,
|
|
4647
|
+
`host "${hostId}" fallback handler`,
|
|
4648
|
+
errors
|
|
4649
|
+
);
|
|
4650
|
+
}
|
|
4651
|
+
}
|
|
4652
|
+
return errors;
|
|
4653
|
+
}
|
|
4654
|
+
function formatNoRoutersError(entryPath, errors) {
|
|
4655
|
+
const base = `[rango] No routers found in registry after importing ${entryPath}`;
|
|
4656
|
+
if (errors.length === 0) {
|
|
4657
|
+
return base;
|
|
4658
|
+
}
|
|
4659
|
+
const formatted = errors.map(({ context, error }) => {
|
|
4660
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
4661
|
+
const detail = err.stack ?? err.message;
|
|
4662
|
+
return ` - while resolving ${context}:
|
|
4663
|
+
${indent(detail, " ")}`;
|
|
4664
|
+
}).join("\n");
|
|
4665
|
+
return `${base}
|
|
4666
|
+
|
|
4667
|
+
${errors.length} error(s) were caught during host-router discovery and likely explain why no routers were registered:
|
|
4668
|
+
${formatted}`;
|
|
4669
|
+
}
|
|
4670
|
+
function toCause(errors) {
|
|
4671
|
+
if (errors.length === 0) return void 0;
|
|
4672
|
+
if (errors.length === 1) return errors[0].error;
|
|
4673
|
+
return new AggregateError(
|
|
4674
|
+
errors.map((e) => e.error),
|
|
4675
|
+
"Multiple host-router handlers failed during discovery"
|
|
4676
|
+
);
|
|
4677
|
+
}
|
|
4678
|
+
var DiscoveryError = class _DiscoveryError extends Error {
|
|
4679
|
+
constructor(entryPath, caught) {
|
|
4680
|
+
super(formatNoRoutersError(entryPath, caught));
|
|
4681
|
+
const cause = toCause(caught);
|
|
4682
|
+
if (cause !== void 0) {
|
|
4683
|
+
this.cause = cause;
|
|
4684
|
+
}
|
|
4685
|
+
this.name = "DiscoveryError";
|
|
4686
|
+
this.entryPath = entryPath;
|
|
4687
|
+
this.caught = caught;
|
|
4688
|
+
Object.setPrototypeOf(this, _DiscoveryError.prototype);
|
|
4689
|
+
}
|
|
4690
|
+
};
|
|
4691
|
+
|
|
4042
4692
|
// src/vite/discovery/discover-routers.ts
|
|
4693
|
+
var debug10 = createRangoDebugger(NS.discovery);
|
|
4043
4694
|
async function discoverRouters(state, rscEnv) {
|
|
4044
4695
|
if (!state.resolvedEntryPath) return;
|
|
4045
|
-
await
|
|
4046
|
-
|
|
4696
|
+
await timed(
|
|
4697
|
+
debug10,
|
|
4698
|
+
"inner: import entry",
|
|
4699
|
+
() => rscEnv.runner.import(state.resolvedEntryPath)
|
|
4700
|
+
);
|
|
4701
|
+
const serverMod = await timed(
|
|
4702
|
+
debug10,
|
|
4703
|
+
"inner: import @rangojs/router/server",
|
|
4704
|
+
() => rscEnv.runner.import("@rangojs/router/server")
|
|
4705
|
+
);
|
|
4047
4706
|
let registry = serverMod.RouterRegistry;
|
|
4048
4707
|
if (!registry || registry.size === 0) {
|
|
4708
|
+
const discoveryErrors = [];
|
|
4049
4709
|
try {
|
|
4050
4710
|
const hostRegistry = serverMod.HostRouterRegistry;
|
|
4051
4711
|
if (hostRegistry && hostRegistry.size > 0) {
|
|
4052
4712
|
console.log(
|
|
4053
|
-
`[
|
|
4713
|
+
`[rango] Found ${hostRegistry.size} host router(s), resolving lazy handlers...`
|
|
4054
4714
|
);
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
await route.handler();
|
|
4060
|
-
} catch {
|
|
4061
|
-
}
|
|
4062
|
-
}
|
|
4063
|
-
}
|
|
4064
|
-
if (entry.fallback && typeof entry.fallback.handler === "function") {
|
|
4065
|
-
try {
|
|
4066
|
-
await entry.fallback.handler();
|
|
4067
|
-
} catch {
|
|
4068
|
-
}
|
|
4069
|
-
}
|
|
4715
|
+
const handlerErrors = await resolveHostRouterHandlers(hostRegistry);
|
|
4716
|
+
discoveryErrors.push(...handlerErrors);
|
|
4717
|
+
for (const { context, error } of handlerErrors) {
|
|
4718
|
+
debug10?.("caught error while resolving %s: %O", context, error);
|
|
4070
4719
|
}
|
|
4071
4720
|
const freshServerMod = await rscEnv.runner.import(
|
|
4072
4721
|
"@rangojs/router/server"
|
|
@@ -4077,16 +4726,20 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4077
4726
|
registry = freshRegistry;
|
|
4078
4727
|
}
|
|
4079
4728
|
}
|
|
4080
|
-
} catch {
|
|
4729
|
+
} catch (error) {
|
|
4730
|
+
discoveryErrors.push({ context: "host-router discovery", error });
|
|
4081
4731
|
}
|
|
4082
4732
|
if (!registry || registry.size === 0) {
|
|
4083
|
-
throw new
|
|
4084
|
-
`[rsc-router] No routers found in registry after importing ${state.resolvedEntryPath}`
|
|
4085
|
-
);
|
|
4733
|
+
throw new DiscoveryError(state.resolvedEntryPath, discoveryErrors);
|
|
4086
4734
|
}
|
|
4087
4735
|
}
|
|
4088
|
-
const buildMod = await
|
|
4736
|
+
const buildMod = await timed(
|
|
4737
|
+
debug10,
|
|
4738
|
+
"inner: import @rangojs/router/build",
|
|
4739
|
+
() => rscEnv.runner.import("@rangojs/router/build")
|
|
4740
|
+
);
|
|
4089
4741
|
const generateManifestFull = buildMod.generateManifestFull;
|
|
4742
|
+
debug10?.("inner: found %d router(s) in registry", registry.size);
|
|
4090
4743
|
const nestedRouterConflict = findNestedRouterConflict(
|
|
4091
4744
|
[...registry.values()].map((router) => router.__sourceFile).filter(
|
|
4092
4745
|
(sourceFile) => typeof sourceFile === "string"
|
|
@@ -4105,6 +4758,16 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4105
4758
|
let mergedRouteTrailingSlash = {};
|
|
4106
4759
|
let routerMountIndex = 0;
|
|
4107
4760
|
const allManifests = [];
|
|
4761
|
+
const clientChunkCtx = state.opts?.clientChunkCtx;
|
|
4762
|
+
const collectClientFallbackRef = clientChunkCtx ? (refKey) => clientChunkCtx.fallbackRefs.add(
|
|
4763
|
+
computeProductionHash(state.projectRoot, refKey)
|
|
4764
|
+
) : void 0;
|
|
4765
|
+
const collectFromBoundaryNode = (node) => {
|
|
4766
|
+
if (collectClientFallbackRef && buildMod.collectFallbackClientRefs) {
|
|
4767
|
+
buildMod.collectFallbackClientRefs(node, collectClientFallbackRef);
|
|
4768
|
+
}
|
|
4769
|
+
};
|
|
4770
|
+
const manifestGenStart = debug10 ? performance.now() : 0;
|
|
4108
4771
|
for (const [id, router] of registry) {
|
|
4109
4772
|
if (!router.urlpatterns || !generateManifestFull) {
|
|
4110
4773
|
continue;
|
|
@@ -4112,10 +4775,18 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4112
4775
|
const manifest = generateManifestFull(
|
|
4113
4776
|
router.urlpatterns,
|
|
4114
4777
|
routerMountIndex,
|
|
4115
|
-
|
|
4778
|
+
{
|
|
4779
|
+
...router.__basename ? { urlPrefix: router.__basename } : {},
|
|
4780
|
+
...collectClientFallbackRef ? { collectClientFallbackRef } : {}
|
|
4781
|
+
}
|
|
4116
4782
|
);
|
|
4117
4783
|
routerMountIndex++;
|
|
4118
4784
|
allManifests.push({ id, manifest });
|
|
4785
|
+
if (collectClientFallbackRef) {
|
|
4786
|
+
collectFromBoundaryNode(router.__defaultErrorBoundary);
|
|
4787
|
+
collectFromBoundaryNode(router.__defaultNotFoundBoundary);
|
|
4788
|
+
collectFromBoundaryNode(router.__notFound);
|
|
4789
|
+
}
|
|
4119
4790
|
const routeCount = Object.keys(manifest.routeManifest).length;
|
|
4120
4791
|
const staticRoutes = Object.values(manifest.routeManifest).filter(
|
|
4121
4792
|
(p) => !p.includes(":") && !p.includes("*")
|
|
@@ -4166,7 +4837,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4166
4837
|
);
|
|
4167
4838
|
newPerRouterPrecomputedMap.set(id, routerPrecomputed);
|
|
4168
4839
|
console.log(
|
|
4169
|
-
`[
|
|
4840
|
+
`[rango] Router "${id}" -> ${routeCount} routes (${staticRoutes} static, ${dynamicRoutes} dynamic)`
|
|
4170
4841
|
);
|
|
4171
4842
|
}
|
|
4172
4843
|
if (registry.size > 1) {
|
|
@@ -4175,11 +4846,17 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4175
4846
|
);
|
|
4176
4847
|
if (autoIds.length > 1) {
|
|
4177
4848
|
console.warn(
|
|
4178
|
-
`[
|
|
4849
|
+
`[rango] WARNING: ${autoIds.length} routers use auto-generated IDs (${autoIds.join(", ")}). In multi-router setups, each createRouter() must have an explicit \`id\` option to ensure per-router manifest data is matched correctly at runtime. Example: createRouter({ id: "site", ... })`
|
|
4179
4850
|
);
|
|
4180
4851
|
}
|
|
4181
4852
|
}
|
|
4853
|
+
debug10?.(
|
|
4854
|
+
"inner: generated manifests for %d router(s) (%sms)",
|
|
4855
|
+
allManifests.length,
|
|
4856
|
+
(performance.now() - manifestGenStart).toFixed(1)
|
|
4857
|
+
);
|
|
4182
4858
|
let newMergedRouteTrie = null;
|
|
4859
|
+
const trieStart = debug10 ? performance.now() : 0;
|
|
4183
4860
|
if (Object.keys(newMergedRouteManifest).length > 0) {
|
|
4184
4861
|
const buildRouteTrie = buildMod.buildRouteTrie;
|
|
4185
4862
|
if (buildRouteTrie && mergedRouteAncestry) {
|
|
@@ -4214,34 +4891,24 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4214
4891
|
newMergedRouteManifest,
|
|
4215
4892
|
mergedRouteAncestry,
|
|
4216
4893
|
routeToStaticPrefix,
|
|
4217
|
-
|
|
4218
|
-
prerenderRouteNames
|
|
4219
|
-
passthroughRouteNames
|
|
4220
|
-
|
|
4894
|
+
mergedRouteTrailingSlash,
|
|
4895
|
+
prerenderRouteNames,
|
|
4896
|
+
passthroughRouteNames,
|
|
4897
|
+
mergedResponseTypeRoutes
|
|
4221
4898
|
);
|
|
4899
|
+
const buildPerRouterTrie = buildMod.buildPerRouterTrie;
|
|
4222
4900
|
for (const { id, manifest } of allManifests) {
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
for (const name of Object.keys(manifest.routeManifest)) {
|
|
4227
|
-
perRouterStaticPrefix[name] = "";
|
|
4901
|
+
const perRouterTrie = buildPerRouterTrie ? buildPerRouterTrie(manifest) : null;
|
|
4902
|
+
if (perRouterTrie) {
|
|
4903
|
+
newPerRouterTrieMap.set(id, perRouterTrie);
|
|
4228
4904
|
}
|
|
4229
|
-
buildRouteToStaticPrefix(manifest.prefixTree, perRouterStaticPrefix);
|
|
4230
|
-
const perRouterPrerenderNames = manifest.prerenderRoutes ? new Set(manifest.prerenderRoutes) : void 0;
|
|
4231
|
-
const perRouterPassthroughNames = manifest.passthroughRoutes ? new Set(manifest.passthroughRoutes) : void 0;
|
|
4232
|
-
const perRouterTrie = buildRouteTrie(
|
|
4233
|
-
manifest.routeManifest,
|
|
4234
|
-
manifest._routeAncestry,
|
|
4235
|
-
perRouterStaticPrefix,
|
|
4236
|
-
manifest.routeTrailingSlash && Object.keys(manifest.routeTrailingSlash).length > 0 ? manifest.routeTrailingSlash : void 0,
|
|
4237
|
-
perRouterPrerenderNames && perRouterPrerenderNames.size > 0 ? perRouterPrerenderNames : void 0,
|
|
4238
|
-
perRouterPassthroughNames && perRouterPassthroughNames.size > 0 ? perRouterPassthroughNames : void 0,
|
|
4239
|
-
manifest.responseTypeRoutes && Object.keys(manifest.responseTypeRoutes).length > 0 ? manifest.responseTypeRoutes : void 0
|
|
4240
|
-
);
|
|
4241
|
-
newPerRouterTrieMap.set(id, perRouterTrie);
|
|
4242
4905
|
}
|
|
4243
4906
|
}
|
|
4244
4907
|
}
|
|
4908
|
+
debug10?.(
|
|
4909
|
+
"inner: trie build done (%sms)",
|
|
4910
|
+
(performance.now() - trieStart).toFixed(1)
|
|
4911
|
+
);
|
|
4245
4912
|
state.mergedRouteManifest = newMergedRouteManifest;
|
|
4246
4913
|
state.mergedPrecomputedEntries = newMergedPrecomputedEntries;
|
|
4247
4914
|
state.perRouterManifests = newPerRouterManifests;
|
|
@@ -4255,7 +4922,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4255
4922
|
}
|
|
4256
4923
|
|
|
4257
4924
|
// src/vite/discovery/route-types-writer.ts
|
|
4258
|
-
import { dirname as dirname3,
|
|
4925
|
+
import { dirname as dirname3, join as join2, resolve as resolve6 } from "node:path";
|
|
4259
4926
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, unlinkSync as unlinkSync2 } from "node:fs";
|
|
4260
4927
|
function filterUserNamedRoutes(manifest) {
|
|
4261
4928
|
const filtered = {};
|
|
@@ -4266,39 +4933,20 @@ function filterUserNamedRoutes(manifest) {
|
|
|
4266
4933
|
}
|
|
4267
4934
|
return filtered;
|
|
4268
4935
|
}
|
|
4936
|
+
function writeGenFileIfChanged(state, outPath, source, opts) {
|
|
4937
|
+
const existing = existsSync5(outPath) ? readFileSync4(outPath, "utf-8") : null;
|
|
4938
|
+
if (existing === source) return;
|
|
4939
|
+
markSelfGenWrite(state, outPath, source);
|
|
4940
|
+
writeFileSync3(outPath, source);
|
|
4941
|
+
if (opts?.log) console.log(`[rango] Generated route types -> ${outPath}`);
|
|
4942
|
+
}
|
|
4269
4943
|
function writeCombinedRouteTypesWithTracking(state, opts) {
|
|
4270
4944
|
const routerFiles = state.cachedRouterFiles ?? findRouterFiles(state.projectRoot, state.scanFilter);
|
|
4271
4945
|
state.cachedRouterFiles = routerFiles;
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
/\.(tsx?|jsx?)$/,
|
|
4277
|
-
""
|
|
4278
|
-
);
|
|
4279
|
-
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4280
|
-
try {
|
|
4281
|
-
preContent.set(outPath, readFileSync4(outPath, "utf-8"));
|
|
4282
|
-
} catch {
|
|
4283
|
-
}
|
|
4284
|
-
}
|
|
4285
|
-
writeCombinedRouteTypes(state.projectRoot, routerFiles, opts);
|
|
4286
|
-
for (const routerFilePath of routerFiles) {
|
|
4287
|
-
const routerDir = dirname3(routerFilePath);
|
|
4288
|
-
const routerBasename = basename(routerFilePath).replace(
|
|
4289
|
-
/\.(tsx?|jsx?)$/,
|
|
4290
|
-
""
|
|
4291
|
-
);
|
|
4292
|
-
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4293
|
-
if (!existsSync5(outPath)) continue;
|
|
4294
|
-
try {
|
|
4295
|
-
const content = readFileSync4(outPath, "utf-8");
|
|
4296
|
-
if (content !== preContent.get(outPath)) {
|
|
4297
|
-
markSelfGenWrite(state, outPath, content);
|
|
4298
|
-
}
|
|
4299
|
-
} catch {
|
|
4300
|
-
}
|
|
4301
|
-
}
|
|
4946
|
+
writeCombinedRouteTypes(state.projectRoot, routerFiles, {
|
|
4947
|
+
...opts,
|
|
4948
|
+
onWrite: (outPath, content) => markSelfGenWrite(state, outPath, content)
|
|
4949
|
+
});
|
|
4302
4950
|
}
|
|
4303
4951
|
function writeRouteTypesFiles(state) {
|
|
4304
4952
|
if (state.perRouterManifests.length === 0) return;
|
|
@@ -4310,7 +4958,7 @@ function writeRouteTypesFiles(state) {
|
|
|
4310
4958
|
if (existsSync5(oldCombinedPath)) {
|
|
4311
4959
|
unlinkSync2(oldCombinedPath);
|
|
4312
4960
|
console.log(
|
|
4313
|
-
`[
|
|
4961
|
+
`[rango] Removed stale combined route types: ${oldCombinedPath}`
|
|
4314
4962
|
);
|
|
4315
4963
|
}
|
|
4316
4964
|
} catch {
|
|
@@ -4324,39 +4972,23 @@ function writeRouteTypesFiles(state) {
|
|
|
4324
4972
|
if (!sourceFile) continue;
|
|
4325
4973
|
if (sourceFile.includes("node_modules")) {
|
|
4326
4974
|
throw new Error(
|
|
4327
|
-
`[
|
|
4975
|
+
`[rango] Router "${id}" has sourceFile inside node_modules: ${sourceFile}
|
|
4328
4976
|
This means createRouter() stack trace parsing matched a Vite internal frame.
|
|
4329
4977
|
Set an explicit \`id\` on createRouter() or check the call site.`
|
|
4330
4978
|
);
|
|
4331
4979
|
}
|
|
4332
|
-
const
|
|
4333
|
-
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
4334
|
-
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4980
|
+
const outPath = genFileTsPath(sourceFile);
|
|
4335
4981
|
const userRoutes = filterUserNamedRoutes(routeManifest);
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
for (const name of Object.keys(userRoutes)) {
|
|
4342
|
-
const schema = staticParsed.searchSchemas[name];
|
|
4343
|
-
if (schema) filtered[name] = schema;
|
|
4344
|
-
}
|
|
4345
|
-
if (Object.keys(filtered).length > 0) {
|
|
4346
|
-
effectiveSearchSchemas = filtered;
|
|
4347
|
-
}
|
|
4348
|
-
}
|
|
4349
|
-
}
|
|
4982
|
+
const effectiveSearchSchemas = resolveSearchSchemas(
|
|
4983
|
+
Object.keys(userRoutes),
|
|
4984
|
+
routeSearchSchemas,
|
|
4985
|
+
sourceFile
|
|
4986
|
+
);
|
|
4350
4987
|
const source = generateRouteTypesSource(
|
|
4351
4988
|
userRoutes,
|
|
4352
4989
|
effectiveSearchSchemas && Object.keys(effectiveSearchSchemas).length > 0 ? effectiveSearchSchemas : void 0
|
|
4353
4990
|
);
|
|
4354
|
-
|
|
4355
|
-
if (existing !== source) {
|
|
4356
|
-
markSelfGenWrite(state, outPath, source);
|
|
4357
|
-
writeFileSync3(outPath, source);
|
|
4358
|
-
console.log(`[rsc-router] Generated route types -> ${outPath}`);
|
|
4359
|
-
}
|
|
4991
|
+
writeGenFileIfChanged(state, outPath, source, { log: true });
|
|
4360
4992
|
}
|
|
4361
4993
|
}
|
|
4362
4994
|
function supplementGenFilesWithRuntimeRoutes(state) {
|
|
@@ -4394,23 +5026,17 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
4394
5026
|
}
|
|
4395
5027
|
}
|
|
4396
5028
|
}
|
|
4397
|
-
const
|
|
4398
|
-
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
4399
|
-
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
5029
|
+
const outPath = genFileTsPath(sourceFile);
|
|
4400
5030
|
const source = generateRouteTypesSource(
|
|
4401
5031
|
mergedRoutes,
|
|
4402
5032
|
Object.keys(mergedSearchSchemas).length > 0 ? mergedSearchSchemas : void 0
|
|
4403
5033
|
);
|
|
4404
|
-
|
|
4405
|
-
if (existing !== source) {
|
|
4406
|
-
markSelfGenWrite(state, outPath, source);
|
|
4407
|
-
writeFileSync3(outPath, source);
|
|
4408
|
-
}
|
|
5034
|
+
writeGenFileIfChanged(state, outPath, source);
|
|
4409
5035
|
}
|
|
4410
5036
|
}
|
|
4411
5037
|
|
|
4412
5038
|
// src/vite/discovery/virtual-module-codegen.ts
|
|
4413
|
-
import { dirname as dirname4, basename
|
|
5039
|
+
import { dirname as dirname4, basename, join as join3 } from "node:path";
|
|
4414
5040
|
function generateRoutesManifestModule(state) {
|
|
4415
5041
|
const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
|
|
4416
5042
|
if (hasManifest) {
|
|
@@ -4421,7 +5047,7 @@ function generateRoutesManifestModule(state) {
|
|
|
4421
5047
|
for (const entry of state.perRouterManifests) {
|
|
4422
5048
|
if (entry.sourceFile) {
|
|
4423
5049
|
const routerDir = dirname4(entry.sourceFile);
|
|
4424
|
-
const routerBasename =
|
|
5050
|
+
const routerBasename = basename(entry.sourceFile).replace(
|
|
4425
5051
|
/\.(tsx?|jsx?)$/,
|
|
4426
5052
|
""
|
|
4427
5053
|
);
|
|
@@ -4442,7 +5068,7 @@ function generateRoutesManifestModule(state) {
|
|
|
4442
5068
|
}
|
|
4443
5069
|
}
|
|
4444
5070
|
const lines = [
|
|
4445
|
-
`import { setCachedManifest,
|
|
5071
|
+
`import { setCachedManifest, setRouterManifest, registerRouterManifestLoader, clearAllRouterData } from "@rangojs/router/server";`,
|
|
4446
5072
|
...genFileImports,
|
|
4447
5073
|
// Clear stale per-router cached data (manifest, trie, precomputed entries)
|
|
4448
5074
|
// before re-populating. In Cloudflare dev mode, program reloads re-evaluate
|
|
@@ -4478,18 +5104,6 @@ function generateRoutesManifestModule(state) {
|
|
|
4478
5104
|
);
|
|
4479
5105
|
}
|
|
4480
5106
|
}
|
|
4481
|
-
if (state.isBuildMode) {
|
|
4482
|
-
if (state.mergedPrecomputedEntries && state.mergedPrecomputedEntries.length > 0) {
|
|
4483
|
-
lines.push(
|
|
4484
|
-
`setPrecomputedEntries(${jsonParseExpression(state.mergedPrecomputedEntries)});`
|
|
4485
|
-
);
|
|
4486
|
-
}
|
|
4487
|
-
if (state.mergedRouteTrie) {
|
|
4488
|
-
lines.push(
|
|
4489
|
-
`setRouteTrie(${jsonParseExpression(state.mergedRouteTrie)});`
|
|
4490
|
-
);
|
|
4491
|
-
}
|
|
4492
|
-
}
|
|
4493
5107
|
for (const routerId of state.perRouterManifestDataMap.keys()) {
|
|
4494
5108
|
lines.push(
|
|
4495
5109
|
`registerRouterManifestLoader(${JSON.stringify(routerId)}, () => import(${JSON.stringify(VIRTUAL_ROUTES_MANIFEST_ID + "/" + routerId)}));`
|
|
@@ -4518,7 +5132,7 @@ function generatePerRouterModule(state, routerId) {
|
|
|
4518
5132
|
const lines = [];
|
|
4519
5133
|
if (routerEntry?.sourceFile) {
|
|
4520
5134
|
const routerDir = dirname4(routerEntry.sourceFile);
|
|
4521
|
-
const routerBasename =
|
|
5135
|
+
const routerBasename = basename(routerEntry.sourceFile).replace(
|
|
4522
5136
|
/\.(tsx?|jsx?)$/,
|
|
4523
5137
|
""
|
|
4524
5138
|
);
|
|
@@ -4589,12 +5203,12 @@ function postprocessBundle(state) {
|
|
|
4589
5203
|
writeFileSync4(chunkPath, result.code);
|
|
4590
5204
|
const savedKB = (result.savedBytes / 1024).toFixed(1);
|
|
4591
5205
|
console.log(
|
|
4592
|
-
`[
|
|
5206
|
+
`[rango] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
|
|
4593
5207
|
);
|
|
4594
5208
|
}
|
|
4595
5209
|
} catch (replaceErr) {
|
|
4596
5210
|
console.warn(
|
|
4597
|
-
`[
|
|
5211
|
+
`[rango] Failed to evict ${target.label}: ${replaceErr.message}`
|
|
4598
5212
|
);
|
|
4599
5213
|
}
|
|
4600
5214
|
}
|
|
@@ -4632,11 +5246,11 @@ function postprocessBundle(state) {
|
|
|
4632
5246
|
writeFileSync4(rscEntryPath, injection + rscCode);
|
|
4633
5247
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
4634
5248
|
console.log(
|
|
4635
|
-
`[
|
|
5249
|
+
`[rango] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.prerenderManifestEntries).length} entries)`
|
|
4636
5250
|
);
|
|
4637
5251
|
} catch (err) {
|
|
4638
5252
|
throw new Error(
|
|
4639
|
-
`[
|
|
5253
|
+
`[rango] Failed to write prerender assets: ${err.message}`
|
|
4640
5254
|
);
|
|
4641
5255
|
}
|
|
4642
5256
|
}
|
|
@@ -4670,28 +5284,180 @@ function postprocessBundle(state) {
|
|
|
4670
5284
|
writeFileSync4(rscEntryPath, injection + rscCode);
|
|
4671
5285
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
4672
5286
|
console.log(
|
|
4673
|
-
`[
|
|
5287
|
+
`[rango] Wrote static assets (${totalKB} KB total, ${Object.keys(state.staticManifestEntries).length} entries)`
|
|
4674
5288
|
);
|
|
4675
5289
|
} catch (err) {
|
|
4676
5290
|
throw new Error(
|
|
4677
|
-
`[
|
|
5291
|
+
`[rango] Failed to write static assets: ${err.message}`
|
|
4678
5292
|
);
|
|
4679
5293
|
}
|
|
4680
5294
|
}
|
|
4681
5295
|
}
|
|
4682
5296
|
}
|
|
4683
5297
|
|
|
5298
|
+
// src/vite/discovery/gate-state.ts
|
|
5299
|
+
function createDiscoveryGate(s, debug11) {
|
|
5300
|
+
let gatePending = false;
|
|
5301
|
+
let gateResolver = () => {
|
|
5302
|
+
};
|
|
5303
|
+
let inProgress = false;
|
|
5304
|
+
let queued = false;
|
|
5305
|
+
let pendingEvents = false;
|
|
5306
|
+
const beginGate = () => {
|
|
5307
|
+
if (gatePending) return;
|
|
5308
|
+
s.discoveryDone = new Promise((resolve10) => {
|
|
5309
|
+
gateResolver = resolve10;
|
|
5310
|
+
});
|
|
5311
|
+
gatePending = true;
|
|
5312
|
+
};
|
|
5313
|
+
const resolveGate = () => {
|
|
5314
|
+
if (!gatePending) return;
|
|
5315
|
+
if (inProgress || queued || pendingEvents) {
|
|
5316
|
+
debug11?.(
|
|
5317
|
+
"hmr: resolveGate deferred \u2014 work in flight (inProgress=%s queued=%s pendingEvents=%s)",
|
|
5318
|
+
inProgress,
|
|
5319
|
+
queued,
|
|
5320
|
+
pendingEvents
|
|
5321
|
+
);
|
|
5322
|
+
return;
|
|
5323
|
+
}
|
|
5324
|
+
gatePending = false;
|
|
5325
|
+
debug11?.("hmr: discoveryDone resolved");
|
|
5326
|
+
gateResolver();
|
|
5327
|
+
};
|
|
5328
|
+
const noteRouteEvent = () => {
|
|
5329
|
+
pendingEvents = true;
|
|
5330
|
+
beginGate();
|
|
5331
|
+
};
|
|
5332
|
+
const runRefreshCycle = async (work) => {
|
|
5333
|
+
if (inProgress) {
|
|
5334
|
+
queued = true;
|
|
5335
|
+
debug11?.("hmr: rediscovery in flight \u2014 queued for a follow-up cycle");
|
|
5336
|
+
return;
|
|
5337
|
+
}
|
|
5338
|
+
pendingEvents = false;
|
|
5339
|
+
inProgress = true;
|
|
5340
|
+
try {
|
|
5341
|
+
await work();
|
|
5342
|
+
} finally {
|
|
5343
|
+
inProgress = false;
|
|
5344
|
+
if (queued) {
|
|
5345
|
+
queued = false;
|
|
5346
|
+
debug11?.("hmr: consuming queued rediscovery");
|
|
5347
|
+
runRefreshCycle(work).catch((err) => {
|
|
5348
|
+
debug11?.(
|
|
5349
|
+
"hmr: queued cycle rejected \u2014 releasing gate (%s)",
|
|
5350
|
+
err instanceof Error ? err.message : String(err)
|
|
5351
|
+
);
|
|
5352
|
+
resolveGate();
|
|
5353
|
+
});
|
|
5354
|
+
} else if (pendingEvents) {
|
|
5355
|
+
debug11?.(
|
|
5356
|
+
"hmr: holding gate for pending events (debounce not yet fired)"
|
|
5357
|
+
);
|
|
5358
|
+
} else {
|
|
5359
|
+
resolveGate();
|
|
5360
|
+
}
|
|
5361
|
+
}
|
|
5362
|
+
};
|
|
5363
|
+
return {
|
|
5364
|
+
beginGate,
|
|
5365
|
+
resolveGate,
|
|
5366
|
+
noteRouteEvent,
|
|
5367
|
+
runRefreshCycle,
|
|
5368
|
+
state: () => ({ gatePending, inProgress, queued, pendingEvents })
|
|
5369
|
+
};
|
|
5370
|
+
}
|
|
5371
|
+
|
|
5372
|
+
// src/vite/utils/forward-user-plugins.ts
|
|
5373
|
+
function isDenied(name) {
|
|
5374
|
+
return name.startsWith("vite:") || name === "rsc" || name.startsWith("rsc:") || name.startsWith("@rangojs/router") || name.startsWith("@cloudflare/vite-plugin") || name.startsWith("vite-plugin-cloudflare");
|
|
5375
|
+
}
|
|
5376
|
+
function hasResolutionHooks(p) {
|
|
5377
|
+
return Boolean(p.resolveId || p.load);
|
|
5378
|
+
}
|
|
5379
|
+
function stripToResolutionHooks(p) {
|
|
5380
|
+
const stripped = { name: p.name };
|
|
5381
|
+
if (p.enforce) stripped.enforce = p.enforce;
|
|
5382
|
+
if (p.applyToEnvironment)
|
|
5383
|
+
stripped.applyToEnvironment = p.applyToEnvironment;
|
|
5384
|
+
if (p.resolveId) stripped.resolveId = p.resolveId;
|
|
5385
|
+
if (p.load) stripped.load = p.load;
|
|
5386
|
+
return stripped;
|
|
5387
|
+
}
|
|
5388
|
+
function selectForwardableResolvePlugins(plugins) {
|
|
5389
|
+
if (!plugins) return [];
|
|
5390
|
+
const forwarded = [];
|
|
5391
|
+
for (const p of plugins) {
|
|
5392
|
+
const name = p?.name;
|
|
5393
|
+
if (!name || isDenied(name)) continue;
|
|
5394
|
+
if (!hasResolutionHooks(p)) continue;
|
|
5395
|
+
forwarded.push(stripToResolutionHooks(p));
|
|
5396
|
+
}
|
|
5397
|
+
return forwarded;
|
|
5398
|
+
}
|
|
5399
|
+
function pickForwardedRunnerConfig(config) {
|
|
5400
|
+
const r = config.resolve ?? {};
|
|
5401
|
+
const resolve10 = {};
|
|
5402
|
+
if (r.alias !== void 0) resolve10.alias = r.alias;
|
|
5403
|
+
if (r.dedupe !== void 0) resolve10.dedupe = r.dedupe;
|
|
5404
|
+
if (r.conditions !== void 0) resolve10.conditions = r.conditions;
|
|
5405
|
+
if (r.mainFields !== void 0) resolve10.mainFields = r.mainFields;
|
|
5406
|
+
if (r.extensions !== void 0) resolve10.extensions = r.extensions;
|
|
5407
|
+
if (r.preserveSymlinks !== void 0)
|
|
5408
|
+
resolve10.preserveSymlinks = r.preserveSymlinks;
|
|
5409
|
+
if (r.tsconfigPaths !== void 0) resolve10.tsconfigPaths = r.tsconfigPaths;
|
|
5410
|
+
const userOxc = config.oxc;
|
|
5411
|
+
const userJsx = userOxc && typeof userOxc === "object" && typeof userOxc.jsx === "object" && userOxc.jsx !== null ? userOxc.jsx : {};
|
|
5412
|
+
const oxc = userOxc && typeof userOxc === "object" ? {
|
|
5413
|
+
...userOxc,
|
|
5414
|
+
jsx: { ...userJsx, runtime: "automatic", importSource: "react" }
|
|
5415
|
+
} : { jsx: { runtime: "automatic", importSource: "react" } };
|
|
5416
|
+
return {
|
|
5417
|
+
resolve: resolve10,
|
|
5418
|
+
define: config.define,
|
|
5419
|
+
oxc
|
|
5420
|
+
};
|
|
5421
|
+
}
|
|
5422
|
+
|
|
4684
5423
|
// src/vite/router-discovery.ts
|
|
5424
|
+
var debugDiscovery = createRangoDebugger(NS.discovery);
|
|
5425
|
+
var debugRoutes = createRangoDebugger(NS.routes);
|
|
5426
|
+
var debugBuild = createRangoDebugger(NS.build);
|
|
5427
|
+
var debugDev = createRangoDebugger(NS.dev);
|
|
5428
|
+
var loaderHookRegistered = false;
|
|
5429
|
+
function ensureCloudflareProtocolLoaderRegistered() {
|
|
5430
|
+
if (loaderHookRegistered) return;
|
|
5431
|
+
loaderHookRegistered = true;
|
|
5432
|
+
try {
|
|
5433
|
+
register(
|
|
5434
|
+
new URL("./plugins/cloudflare-protocol-loader-hook.mjs", import.meta.url)
|
|
5435
|
+
);
|
|
5436
|
+
} catch (err) {
|
|
5437
|
+
console.warn(
|
|
5438
|
+
`[rango] Could not register Node ESM loader hook for cloudflare:* imports (${err?.message ?? err}). Falling back to Vite transform only.`
|
|
5439
|
+
);
|
|
5440
|
+
}
|
|
5441
|
+
}
|
|
4685
5442
|
async function createTempRscServer(state, options = {}) {
|
|
5443
|
+
ensureCloudflareProtocolLoaderRegistered();
|
|
4686
5444
|
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
5445
|
+
const runnerConfig = state.userRunnerConfig;
|
|
5446
|
+
const resolveConfig = runnerConfig?.resolve ?? {
|
|
5447
|
+
alias: state.userResolveAlias
|
|
5448
|
+
};
|
|
5449
|
+
const oxcConfig = runnerConfig?.oxc ?? {
|
|
5450
|
+
jsx: { runtime: "automatic", importSource: "react" }
|
|
5451
|
+
};
|
|
4687
5452
|
return createViteServer({
|
|
4688
5453
|
root: state.projectRoot,
|
|
4689
5454
|
configFile: false,
|
|
4690
5455
|
server: { middlewareMode: true },
|
|
4691
5456
|
appType: "custom",
|
|
4692
5457
|
logLevel: "silent",
|
|
4693
|
-
resolve:
|
|
4694
|
-
|
|
5458
|
+
resolve: resolveConfig,
|
|
5459
|
+
...runnerConfig?.define ? { define: runnerConfig.define } : {},
|
|
5460
|
+
oxc: oxcConfig,
|
|
4695
5461
|
...options.cacheDir && { cacheDir: options.cacheDir },
|
|
4696
5462
|
plugins: [
|
|
4697
5463
|
rsc({
|
|
@@ -4705,10 +5471,15 @@ async function createTempRscServer(state, options = {}) {
|
|
|
4705
5471
|
...options.forceBuild ? [hashClientRefs(state.projectRoot)] : [],
|
|
4706
5472
|
createVersionPlugin(),
|
|
4707
5473
|
createVirtualStubPlugin(),
|
|
5474
|
+
createCloudflareProtocolStubPlugin(),
|
|
4708
5475
|
// Dev prerender must use dev-mode IDs (path-based) to match the workerd
|
|
4709
5476
|
// runtime. forceBuild produces hashed IDs for production bundle consistency.
|
|
4710
5477
|
exposeInternalIds(options.forceBuild ? { forceBuild: true } : void 0),
|
|
4711
|
-
exposeRouterId()
|
|
5478
|
+
exposeRouterId(),
|
|
5479
|
+
// Forwarded user resolution plugins (e.g. vite-tsconfig-paths). Stripped
|
|
5480
|
+
// to resolveId/load and placed last so framework resolution runs first;
|
|
5481
|
+
// Vite re-sorts by `enforce`, so `enforce: "pre"` resolvers still lead.
|
|
5482
|
+
...state.userResolvePlugins
|
|
4712
5483
|
]
|
|
4713
5484
|
});
|
|
4714
5485
|
}
|
|
@@ -4717,11 +5488,11 @@ async function resolveBuildEnv(option, factoryCtx) {
|
|
|
4717
5488
|
if (option === "auto") {
|
|
4718
5489
|
if (factoryCtx.preset !== "cloudflare") {
|
|
4719
5490
|
throw new Error(
|
|
4720
|
-
'[
|
|
5491
|
+
'[rango] buildEnv: "auto" is only supported with preset: "cloudflare". Use a factory function or plain object for other presets.'
|
|
4721
5492
|
);
|
|
4722
5493
|
}
|
|
4723
5494
|
try {
|
|
4724
|
-
const userRequire =
|
|
5495
|
+
const userRequire = createRequire2(
|
|
4725
5496
|
resolve8(factoryCtx.root, "package.json")
|
|
4726
5497
|
);
|
|
4727
5498
|
const wranglerPath = userRequire.resolve("wrangler");
|
|
@@ -4733,7 +5504,7 @@ async function resolveBuildEnv(option, factoryCtx) {
|
|
|
4733
5504
|
};
|
|
4734
5505
|
} catch (err) {
|
|
4735
5506
|
throw new Error(
|
|
4736
|
-
`[
|
|
5507
|
+
`[rango] buildEnv: "auto" requires wrangler to be installed.
|
|
4737
5508
|
Install it with: pnpm add -D wrangler
|
|
4738
5509
|
${err.message}`
|
|
4739
5510
|
);
|
|
@@ -4756,6 +5527,7 @@ async function acquireBuildEnv(s, command, mode) {
|
|
|
4756
5527
|
if (!result) return false;
|
|
4757
5528
|
s.resolvedBuildEnv = result.env;
|
|
4758
5529
|
s.buildEnvDispose = result.dispose ?? null;
|
|
5530
|
+
globalThis[BUILD_ENV_GLOBAL_KEY] = result.env;
|
|
4759
5531
|
return true;
|
|
4760
5532
|
}
|
|
4761
5533
|
async function releaseBuildEnv(s) {
|
|
@@ -4763,11 +5535,12 @@ async function releaseBuildEnv(s) {
|
|
|
4763
5535
|
try {
|
|
4764
5536
|
await s.buildEnvDispose();
|
|
4765
5537
|
} catch (err) {
|
|
4766
|
-
console.warn(`[
|
|
5538
|
+
console.warn(`[rango] buildEnv dispose failed: ${err.message}`);
|
|
4767
5539
|
}
|
|
4768
5540
|
s.buildEnvDispose = null;
|
|
4769
5541
|
}
|
|
4770
5542
|
s.resolvedBuildEnv = void 0;
|
|
5543
|
+
delete globalThis[BUILD_ENV_GLOBAL_KEY];
|
|
4771
5544
|
}
|
|
4772
5545
|
function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
4773
5546
|
const s = createDiscoveryState(entryPath, opts);
|
|
@@ -4789,17 +5562,16 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4789
5562
|
viteCommand = config.command;
|
|
4790
5563
|
viteMode = config.mode;
|
|
4791
5564
|
s.userResolveAlias = config.resolve.alias;
|
|
5565
|
+
s.userRunnerConfig = pickForwardedRunnerConfig(config);
|
|
5566
|
+
s.userResolvePlugins = selectForwardableResolvePlugins(
|
|
5567
|
+
config.plugins
|
|
5568
|
+
);
|
|
4792
5569
|
if (!s.resolvedEntryPath && opts?.routerPathRef?.path) {
|
|
4793
5570
|
s.resolvedEntryPath = opts.routerPathRef.path;
|
|
4794
5571
|
}
|
|
4795
5572
|
if (!s.resolvedEntryPath) {
|
|
4796
|
-
const
|
|
4797
|
-
|
|
4798
|
-
if (typeof entries === "string") {
|
|
4799
|
-
s.resolvedEntryPath = entries;
|
|
4800
|
-
} else if (Array.isArray(entries) && entries.length > 0) {
|
|
4801
|
-
s.resolvedEntryPath = entries[0];
|
|
4802
|
-
}
|
|
5573
|
+
const entry = resolveRscEntryFromConfig(config);
|
|
5574
|
+
if (entry) s.resolvedEntryPath = entry;
|
|
4803
5575
|
}
|
|
4804
5576
|
if (opts?.staticRouteTypesGeneration !== false) {
|
|
4805
5577
|
s.cachedRouterFiles = findRouterFiles(s.projectRoot, s.scanFilter);
|
|
@@ -4823,6 +5595,9 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4823
5595
|
const discoveryPromise = new Promise((resolve10) => {
|
|
4824
5596
|
resolveDiscovery = resolve10;
|
|
4825
5597
|
});
|
|
5598
|
+
const gate = createDiscoveryGate(s, debugDiscovery);
|
|
5599
|
+
const beginDiscoveryGate = gate.beginGate;
|
|
5600
|
+
const resolveDiscoveryGate = gate.resolveGate;
|
|
4826
5601
|
const getDevServerOrigin = () => server.resolvedUrls?.local?.[0]?.replace(/\/$/, "") || `http://localhost:${server.config.server.port || 5173}`;
|
|
4827
5602
|
let prerenderTempServer = null;
|
|
4828
5603
|
let prerenderNodeRegistry = null;
|
|
@@ -4835,74 +5610,241 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4835
5610
|
releaseBuildEnv(s).catch(() => {
|
|
4836
5611
|
});
|
|
4837
5612
|
});
|
|
5613
|
+
async function importEntryAndRegistry(tempRscEnv) {
|
|
5614
|
+
const flagAlreadySet = !!globalThis.__rscRouterDiscoveryActive;
|
|
5615
|
+
if (!flagAlreadySet) {
|
|
5616
|
+
globalThis.__rscRouterDiscoveryActive = true;
|
|
5617
|
+
}
|
|
5618
|
+
try {
|
|
5619
|
+
debugDiscovery?.(
|
|
5620
|
+
"importEntryAndRegistry: importing entry (flag=%s)",
|
|
5621
|
+
globalThis.__rscRouterDiscoveryActive ?? false
|
|
5622
|
+
);
|
|
5623
|
+
await tempRscEnv.runner.import(s.resolvedEntryPath);
|
|
5624
|
+
debugDiscovery?.(
|
|
5625
|
+
"importEntryAndRegistry: entry import OK, fetching RouterRegistry"
|
|
5626
|
+
);
|
|
5627
|
+
const serverMod = await tempRscEnv.runner.import(
|
|
5628
|
+
"@rangojs/router/server"
|
|
5629
|
+
);
|
|
5630
|
+
prerenderNodeRegistry = serverMod.RouterRegistry;
|
|
5631
|
+
debugDiscovery?.(
|
|
5632
|
+
"importEntryAndRegistry: registry size=%d",
|
|
5633
|
+
prerenderNodeRegistry?.size ?? 0
|
|
5634
|
+
);
|
|
5635
|
+
} finally {
|
|
5636
|
+
if (!flagAlreadySet) {
|
|
5637
|
+
delete globalThis.__rscRouterDiscoveryActive;
|
|
5638
|
+
debugDiscovery?.(
|
|
5639
|
+
"importEntryAndRegistry: cleared __rscRouterDiscoveryActive"
|
|
5640
|
+
);
|
|
5641
|
+
}
|
|
5642
|
+
}
|
|
5643
|
+
}
|
|
4838
5644
|
async function getOrCreateTempServer() {
|
|
4839
|
-
if (
|
|
4840
|
-
|
|
5645
|
+
if (prerenderTempServer) {
|
|
5646
|
+
const existingEnv = prerenderTempServer.environments?.rsc;
|
|
5647
|
+
if (existingEnv?.runner) {
|
|
5648
|
+
if (prerenderNodeRegistry) {
|
|
5649
|
+
debugDiscovery?.(
|
|
5650
|
+
"getOrCreateTempServer: cached temp runner reused"
|
|
5651
|
+
);
|
|
5652
|
+
return existingEnv;
|
|
5653
|
+
}
|
|
5654
|
+
debugDiscovery?.(
|
|
5655
|
+
"getOrCreateTempServer: server alive but registry missing \u2014 re-importing"
|
|
5656
|
+
);
|
|
5657
|
+
try {
|
|
5658
|
+
await importEntryAndRegistry(existingEnv);
|
|
5659
|
+
return existingEnv;
|
|
5660
|
+
} catch (err) {
|
|
5661
|
+
debugDiscovery?.(
|
|
5662
|
+
"getOrCreateTempServer: reuse import failed (%s) \u2014 closing orphan and creating fresh",
|
|
5663
|
+
err?.message ?? String(err)
|
|
5664
|
+
);
|
|
5665
|
+
await prerenderTempServer.close().catch(() => {
|
|
5666
|
+
});
|
|
5667
|
+
prerenderTempServer = null;
|
|
5668
|
+
prerenderNodeRegistry = null;
|
|
5669
|
+
}
|
|
5670
|
+
} else {
|
|
5671
|
+
debugDiscovery?.(
|
|
5672
|
+
"getOrCreateTempServer: existing server has no rsc.runner \u2014 closing and recreating"
|
|
5673
|
+
);
|
|
5674
|
+
await prerenderTempServer.close().catch(() => {
|
|
5675
|
+
});
|
|
5676
|
+
prerenderTempServer = null;
|
|
5677
|
+
prerenderNodeRegistry = null;
|
|
5678
|
+
}
|
|
4841
5679
|
}
|
|
5680
|
+
debugDiscovery?.(
|
|
5681
|
+
"getOrCreateTempServer: creating new temp server, entry=%s",
|
|
5682
|
+
s.resolvedEntryPath ?? "(unset)"
|
|
5683
|
+
);
|
|
4842
5684
|
try {
|
|
4843
5685
|
prerenderTempServer = await createTempRscServer(s, {
|
|
4844
5686
|
cacheDir: "node_modules/.vite_prerender"
|
|
4845
5687
|
});
|
|
4846
5688
|
const tempRscEnv = prerenderTempServer.environments?.rsc;
|
|
4847
5689
|
if (tempRscEnv?.runner) {
|
|
4848
|
-
await tempRscEnv
|
|
4849
|
-
const serverMod = await tempRscEnv.runner.import(
|
|
4850
|
-
"@rangojs/router/server"
|
|
4851
|
-
);
|
|
4852
|
-
prerenderNodeRegistry = serverMod.RouterRegistry;
|
|
5690
|
+
await importEntryAndRegistry(tempRscEnv);
|
|
4853
5691
|
return tempRscEnv;
|
|
4854
5692
|
}
|
|
5693
|
+
debugDiscovery?.(
|
|
5694
|
+
"getOrCreateTempServer: tempRscEnv.runner unavailable"
|
|
5695
|
+
);
|
|
4855
5696
|
} catch (err) {
|
|
4856
|
-
|
|
4857
|
-
|
|
5697
|
+
debugDiscovery?.(
|
|
5698
|
+
"getOrCreateTempServer: FAILED message=%s",
|
|
5699
|
+
err.message
|
|
4858
5700
|
);
|
|
5701
|
+
console.warn(`[rango] Failed to create temp runner: ${err.message}`);
|
|
4859
5702
|
}
|
|
4860
5703
|
return null;
|
|
4861
5704
|
}
|
|
5705
|
+
async function clearTempRegistries(tempRscEnv) {
|
|
5706
|
+
try {
|
|
5707
|
+
const serverMod = await tempRscEnv.runner.import(
|
|
5708
|
+
"@rangojs/router/server"
|
|
5709
|
+
);
|
|
5710
|
+
if (typeof serverMod?.RouterRegistry?.clear === "function") {
|
|
5711
|
+
serverMod.RouterRegistry.clear();
|
|
5712
|
+
}
|
|
5713
|
+
if (typeof serverMod?.HostRouterRegistry?.clear === "function") {
|
|
5714
|
+
serverMod.HostRouterRegistry.clear();
|
|
5715
|
+
}
|
|
5716
|
+
debugDiscovery?.(
|
|
5717
|
+
"clearTempRegistries: cleared RouterRegistry + HostRouterRegistry"
|
|
5718
|
+
);
|
|
5719
|
+
} catch (err) {
|
|
5720
|
+
debugDiscovery?.(
|
|
5721
|
+
"clearTempRegistries: import @rangojs/router/server failed (%s)",
|
|
5722
|
+
err?.message ?? String(err)
|
|
5723
|
+
);
|
|
5724
|
+
}
|
|
5725
|
+
}
|
|
5726
|
+
async function refreshTempRscEnv() {
|
|
5727
|
+
let tempRscEnv = await getOrCreateTempServer();
|
|
5728
|
+
if (!tempRscEnv) return null;
|
|
5729
|
+
const envGraph = tempRscEnv.moduleGraph;
|
|
5730
|
+
const serverGraph = prerenderTempServer?.moduleGraph;
|
|
5731
|
+
const target = envGraph?.invalidateAll ? envGraph : serverGraph?.invalidateAll ? serverGraph : null;
|
|
5732
|
+
if (!target) {
|
|
5733
|
+
debugDiscovery?.(
|
|
5734
|
+
"refreshTempRscEnv: invalidateAll unavailable on env+server graphs, falling back to close+recreate"
|
|
5735
|
+
);
|
|
5736
|
+
if (prerenderTempServer) {
|
|
5737
|
+
await prerenderTempServer.close().catch(() => {
|
|
5738
|
+
});
|
|
5739
|
+
prerenderTempServer = null;
|
|
5740
|
+
prerenderNodeRegistry = null;
|
|
5741
|
+
}
|
|
5742
|
+
return await getOrCreateTempServer();
|
|
5743
|
+
}
|
|
5744
|
+
debugDiscovery?.(
|
|
5745
|
+
"refreshTempRscEnv: invalidating module graph (%s)",
|
|
5746
|
+
envGraph?.invalidateAll ? "env" : "server"
|
|
5747
|
+
);
|
|
5748
|
+
target.invalidateAll();
|
|
5749
|
+
prerenderNodeRegistry = null;
|
|
5750
|
+
await clearTempRegistries(tempRscEnv);
|
|
5751
|
+
await importEntryAndRegistry(tempRscEnv);
|
|
5752
|
+
return tempRscEnv;
|
|
5753
|
+
}
|
|
4862
5754
|
const discover = async () => {
|
|
5755
|
+
const discoverStart = performance.now();
|
|
4863
5756
|
const rscEnv = server.environments?.rsc;
|
|
4864
5757
|
if (!rscEnv?.runner) {
|
|
5758
|
+
debugDiscovery?.(
|
|
5759
|
+
"dev: cloudflare path start, __rscRouterDiscoveryActive=%s",
|
|
5760
|
+
globalThis.__rscRouterDiscoveryActive ?? false
|
|
5761
|
+
);
|
|
4865
5762
|
s.devServerOrigin = getDevServerOrigin();
|
|
4866
5763
|
try {
|
|
4867
|
-
await
|
|
4868
|
-
|
|
5764
|
+
await timed(
|
|
5765
|
+
debugDiscovery,
|
|
5766
|
+
"acquireBuildEnv",
|
|
5767
|
+
() => acquireBuildEnv(s, viteCommand, viteMode)
|
|
5768
|
+
);
|
|
5769
|
+
const tempRscEnv = await timed(
|
|
5770
|
+
debugDiscovery,
|
|
5771
|
+
"getOrCreateTempServer",
|
|
5772
|
+
() => getOrCreateTempServer()
|
|
5773
|
+
);
|
|
4869
5774
|
if (tempRscEnv) {
|
|
4870
|
-
await
|
|
4871
|
-
|
|
5775
|
+
await timed(
|
|
5776
|
+
debugDiscovery,
|
|
5777
|
+
"discoverRouters (cloudflare)",
|
|
5778
|
+
() => discoverRouters(s, tempRscEnv)
|
|
5779
|
+
);
|
|
5780
|
+
timedSync(
|
|
5781
|
+
debugDiscovery,
|
|
5782
|
+
"writeRouteTypesFiles",
|
|
5783
|
+
() => writeRouteTypesFiles(s)
|
|
5784
|
+
);
|
|
4872
5785
|
}
|
|
4873
5786
|
} catch (err) {
|
|
4874
5787
|
console.warn(
|
|
4875
|
-
`[
|
|
5788
|
+
`[rango] Cloudflare dev discovery failed: ${err.message}
|
|
4876
5789
|
${err.stack}`
|
|
4877
5790
|
);
|
|
4878
5791
|
}
|
|
5792
|
+
debugDiscovery?.(
|
|
5793
|
+
"dev discovery done (%sms)",
|
|
5794
|
+
(performance.now() - discoverStart).toFixed(1)
|
|
5795
|
+
);
|
|
4879
5796
|
resolveDiscovery();
|
|
4880
5797
|
return;
|
|
4881
5798
|
}
|
|
4882
5799
|
try {
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
5800
|
+
debugDiscovery?.("dev: node path start");
|
|
5801
|
+
await timed(
|
|
5802
|
+
debugDiscovery,
|
|
5803
|
+
"acquireBuildEnv",
|
|
5804
|
+
() => acquireBuildEnv(s, viteCommand, viteMode)
|
|
5805
|
+
);
|
|
5806
|
+
const serverMod = await timed(
|
|
5807
|
+
debugDiscovery,
|
|
5808
|
+
"import @rangojs/router/server",
|
|
5809
|
+
() => rscEnv.runner.import("@rangojs/router/server")
|
|
4886
5810
|
);
|
|
4887
5811
|
if (serverMod?.setManifestReadyPromise) {
|
|
4888
5812
|
serverMod.setManifestReadyPromise(discoveryPromise);
|
|
4889
5813
|
}
|
|
4890
|
-
await
|
|
5814
|
+
await timed(
|
|
5815
|
+
debugDiscovery,
|
|
5816
|
+
"discoverRouters",
|
|
5817
|
+
() => discoverRouters(s, rscEnv)
|
|
5818
|
+
);
|
|
4891
5819
|
s.devServerOrigin = getDevServerOrigin();
|
|
4892
|
-
|
|
4893
|
-
|
|
5820
|
+
timedSync(
|
|
5821
|
+
debugDiscovery,
|
|
5822
|
+
"writeRouteTypesFiles",
|
|
5823
|
+
() => writeRouteTypesFiles(s)
|
|
5824
|
+
);
|
|
5825
|
+
await timed(
|
|
5826
|
+
debugDiscovery,
|
|
5827
|
+
"propagateDiscoveryState",
|
|
5828
|
+
() => propagateDiscoveryState(rscEnv)
|
|
5829
|
+
);
|
|
4894
5830
|
} catch (err) {
|
|
4895
5831
|
console.warn(
|
|
4896
|
-
`[
|
|
5832
|
+
`[rango] Router discovery failed: ${err.message}
|
|
4897
5833
|
${err.stack}`
|
|
4898
5834
|
);
|
|
4899
5835
|
} finally {
|
|
5836
|
+
debugDiscovery?.(
|
|
5837
|
+
"dev discovery done (%sms)",
|
|
5838
|
+
(performance.now() - discoverStart).toFixed(1)
|
|
5839
|
+
);
|
|
4900
5840
|
resolveDiscovery();
|
|
4901
5841
|
}
|
|
4902
5842
|
};
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
5843
|
+
beginDiscoveryGate();
|
|
5844
|
+
setTimeout(
|
|
5845
|
+
() => discover().then(resolveDiscoveryGate, resolveDiscoveryGate),
|
|
5846
|
+
0
|
|
5847
|
+
);
|
|
4906
5848
|
let mainRegistry = null;
|
|
4907
5849
|
const propagateDiscoveryState = async (rscEnv) => {
|
|
4908
5850
|
const serverMod = await rscEnv.runner.import("@rangojs/router/server");
|
|
@@ -4920,29 +5862,35 @@ ${err.stack}`
|
|
|
4920
5862
|
if (s.mergedRouteTrie && serverMod.setRouteTrie) {
|
|
4921
5863
|
serverMod.setRouteTrie(s.mergedRouteTrie);
|
|
4922
5864
|
}
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
}
|
|
4933
|
-
if (serverMod.setRouterPrecomputedEntries) {
|
|
4934
|
-
for (const [routerId, entries] of s.perRouterPrecomputedMap) {
|
|
4935
|
-
serverMod.setRouterPrecomputedEntries(routerId, entries);
|
|
4936
|
-
}
|
|
5865
|
+
const perRouterSetters = [
|
|
5866
|
+
[s.perRouterManifestDataMap, "setRouterManifest"],
|
|
5867
|
+
[s.perRouterTrieMap, "setRouterTrie"],
|
|
5868
|
+
[s.perRouterPrecomputedMap, "setRouterPrecomputedEntries"]
|
|
5869
|
+
];
|
|
5870
|
+
for (const [map, fn] of perRouterSetters) {
|
|
5871
|
+
const setter = serverMod[fn];
|
|
5872
|
+
if (typeof setter !== "function") continue;
|
|
5873
|
+
for (const [routerId, value] of map) setter(routerId, value);
|
|
4937
5874
|
}
|
|
4938
5875
|
};
|
|
4939
5876
|
server.middlewares.use("/__rsc_prerender", async (req, res) => {
|
|
5877
|
+
const reqStart = debugDev ? performance.now() : 0;
|
|
5878
|
+
const logResult = (status, note) => {
|
|
5879
|
+
debugDev?.(
|
|
5880
|
+
"/__rsc_prerender %s -> %d %s (%sms)",
|
|
5881
|
+
req.url,
|
|
5882
|
+
status,
|
|
5883
|
+
note,
|
|
5884
|
+
(performance.now() - reqStart).toFixed(1)
|
|
5885
|
+
);
|
|
5886
|
+
};
|
|
4940
5887
|
if (s.discoveryDone) await s.discoveryDone;
|
|
4941
5888
|
const url = new URL(req.url || "/", "http://localhost");
|
|
4942
5889
|
const pathname = url.searchParams.get("pathname");
|
|
4943
5890
|
if (!pathname) {
|
|
4944
5891
|
res.statusCode = 400;
|
|
4945
5892
|
res.end("Missing pathname");
|
|
5893
|
+
logResult(400, "missing pathname");
|
|
4946
5894
|
return;
|
|
4947
5895
|
}
|
|
4948
5896
|
const rscEnv = server.environments?.rsc;
|
|
@@ -4956,10 +5904,11 @@ ${err.stack}`
|
|
|
4956
5904
|
registry = serverMod.RouterRegistry ?? null;
|
|
4957
5905
|
} catch (err) {
|
|
4958
5906
|
console.warn(
|
|
4959
|
-
`[
|
|
5907
|
+
`[rango] Dev prerender module refresh failed: ${err.message}`
|
|
4960
5908
|
);
|
|
4961
5909
|
res.statusCode = 500;
|
|
4962
5910
|
res.end(`Prerender handler error: ${err.message}`);
|
|
5911
|
+
logResult(500, "module refresh failed");
|
|
4963
5912
|
return;
|
|
4964
5913
|
}
|
|
4965
5914
|
} else {
|
|
@@ -4974,6 +5923,7 @@ ${err.stack}`
|
|
|
4974
5923
|
if (!registry || registry.size === 0) {
|
|
4975
5924
|
res.statusCode = 503;
|
|
4976
5925
|
res.end("Prerender runner not available");
|
|
5926
|
+
logResult(503, "no registry");
|
|
4977
5927
|
return;
|
|
4978
5928
|
}
|
|
4979
5929
|
const wantIntercept = url.searchParams.get("intercept") === "1";
|
|
@@ -4999,24 +5949,25 @@ ${err.stack}`
|
|
|
4999
5949
|
if (wantIntercept && result.interceptSegments?.length) {
|
|
5000
5950
|
payload = {
|
|
5001
5951
|
segments: [...result.segments, ...result.interceptSegments],
|
|
5002
|
-
handles
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
}
|
|
5952
|
+
// Pre-encoded MERGED handle string from the producer (handles are
|
|
5953
|
+
// Flight-encoded so Promise/ReactNode values survive the wire).
|
|
5954
|
+
handles: result.interceptHandles ?? ""
|
|
5006
5955
|
};
|
|
5007
5956
|
} else {
|
|
5008
5957
|
payload = { segments: result.segments, handles: result.handles };
|
|
5009
5958
|
}
|
|
5010
5959
|
res.end(JSON.stringify(payload));
|
|
5960
|
+
logResult(200, `match ${result.routeName}`);
|
|
5011
5961
|
return;
|
|
5012
5962
|
} catch (err) {
|
|
5013
5963
|
console.warn(
|
|
5014
|
-
`[
|
|
5964
|
+
`[rango] Dev prerender failed for ${pathname}: ${err.message}`
|
|
5015
5965
|
);
|
|
5016
5966
|
}
|
|
5017
5967
|
}
|
|
5018
5968
|
res.statusCode = 404;
|
|
5019
5969
|
res.end("No prerender match");
|
|
5970
|
+
logResult(404, "no match");
|
|
5020
5971
|
});
|
|
5021
5972
|
if (opts?.staticRouteTypesGeneration !== false) {
|
|
5022
5973
|
const isGeneratedRouteFile = (filePath) => filePath.endsWith(".gen.ts") && (filePath.includes("named-routes.gen.ts") || filePath.includes("urls.gen.ts"));
|
|
@@ -5036,59 +5987,185 @@ ${err.stack}`
|
|
|
5036
5987
|
return true;
|
|
5037
5988
|
};
|
|
5038
5989
|
let routeChangeTimer;
|
|
5039
|
-
let runtimeRediscoveryInProgress = false;
|
|
5040
5990
|
const refreshRuntimeDiscovery = async () => {
|
|
5041
5991
|
const rscEnv = server.environments?.rsc;
|
|
5042
|
-
|
|
5043
|
-
|
|
5992
|
+
const hasMainRunner = !!rscEnv?.runner;
|
|
5993
|
+
if (!hasMainRunner && s.perRouterManifests.length === 0) return;
|
|
5994
|
+
await gate.runRefreshCycle(async () => {
|
|
5995
|
+
const hmrStart = performance.now();
|
|
5996
|
+
try {
|
|
5997
|
+
if (hasMainRunner) {
|
|
5998
|
+
await timed(
|
|
5999
|
+
debugDiscovery,
|
|
6000
|
+
"hmr discoverRouters",
|
|
6001
|
+
() => discoverRouters(s, rscEnv)
|
|
6002
|
+
);
|
|
6003
|
+
timedSync(
|
|
6004
|
+
debugDiscovery,
|
|
6005
|
+
"hmr writeRouteTypesFiles",
|
|
6006
|
+
() => writeRouteTypesFiles(s)
|
|
6007
|
+
);
|
|
6008
|
+
await timed(
|
|
6009
|
+
debugDiscovery,
|
|
6010
|
+
"hmr propagateDiscoveryState",
|
|
6011
|
+
() => propagateDiscoveryState(rscEnv)
|
|
6012
|
+
);
|
|
6013
|
+
} else {
|
|
6014
|
+
const tempRscEnv = await timed(
|
|
6015
|
+
debugDiscovery,
|
|
6016
|
+
"hmr refreshTempRscEnv (cloudflare)",
|
|
6017
|
+
() => refreshTempRscEnv()
|
|
6018
|
+
);
|
|
6019
|
+
if (!tempRscEnv) {
|
|
6020
|
+
throw new Error(
|
|
6021
|
+
"temp runner unavailable for cloudflare HMR rediscovery"
|
|
6022
|
+
);
|
|
6023
|
+
}
|
|
6024
|
+
await timed(
|
|
6025
|
+
debugDiscovery,
|
|
6026
|
+
"hmr discoverRouters (cloudflare)",
|
|
6027
|
+
() => discoverRouters(s, tempRscEnv)
|
|
6028
|
+
);
|
|
6029
|
+
timedSync(
|
|
6030
|
+
debugDiscovery,
|
|
6031
|
+
"hmr writeRouteTypesFiles",
|
|
6032
|
+
() => writeRouteTypesFiles(s)
|
|
6033
|
+
);
|
|
6034
|
+
}
|
|
6035
|
+
if (s.lastDiscoveryError) {
|
|
6036
|
+
debugDiscovery?.(
|
|
6037
|
+
"hmr: cleared lastDiscoveryError (%s) after successful rediscovery",
|
|
6038
|
+
s.lastDiscoveryError.message
|
|
6039
|
+
);
|
|
6040
|
+
s.lastDiscoveryError = null;
|
|
6041
|
+
}
|
|
6042
|
+
if (rscEnv && !rscEnv.runner) forceCloudflareWorkerReload(rscEnv);
|
|
6043
|
+
} catch (err) {
|
|
6044
|
+
s.lastDiscoveryError = {
|
|
6045
|
+
message: err?.message ?? String(err),
|
|
6046
|
+
at: Date.now()
|
|
6047
|
+
};
|
|
6048
|
+
console.warn(
|
|
6049
|
+
`[rango] Runtime re-discovery failed: ${err.message}`
|
|
6050
|
+
);
|
|
6051
|
+
debugDiscovery?.(
|
|
6052
|
+
"hmr: lastDiscoveryError set (%s) \u2014 manifest preserved at last-good; recovery mode active (any in-scan source change will trigger rediscovery)",
|
|
6053
|
+
err?.message
|
|
6054
|
+
);
|
|
6055
|
+
} finally {
|
|
6056
|
+
debugDiscovery?.(
|
|
6057
|
+
"hmr re-discovery done (%sms)",
|
|
6058
|
+
(performance.now() - hmrStart).toFixed(1)
|
|
6059
|
+
);
|
|
6060
|
+
}
|
|
6061
|
+
});
|
|
6062
|
+
};
|
|
6063
|
+
const forceCloudflareWorkerReload = (rscEnv) => {
|
|
6064
|
+
if (!rscEnv?.hot) return;
|
|
5044
6065
|
try {
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
6066
|
+
const graph = rscEnv.moduleGraph;
|
|
6067
|
+
if (graph?.invalidateAll) {
|
|
6068
|
+
graph.invalidateAll();
|
|
6069
|
+
debugDiscovery?.("hmr: invalidated workerd rsc module graph");
|
|
6070
|
+
}
|
|
6071
|
+
rscEnv.hot.send({ type: "full-reload" });
|
|
6072
|
+
debugDiscovery?.(
|
|
6073
|
+
"hmr: forced workerd rsc env reload (full-reload)"
|
|
6074
|
+
);
|
|
5048
6075
|
} catch (err) {
|
|
5049
|
-
|
|
5050
|
-
|
|
6076
|
+
debugDiscovery?.(
|
|
6077
|
+
"hmr: workerd reload failed: %s",
|
|
6078
|
+
err?.message ?? err
|
|
5051
6079
|
);
|
|
5052
|
-
} finally {
|
|
5053
|
-
runtimeRediscoveryInProgress = false;
|
|
5054
6080
|
}
|
|
5055
6081
|
};
|
|
5056
6082
|
const scheduleRouteRegeneration = () => {
|
|
5057
6083
|
clearTimeout(routeChangeTimer);
|
|
5058
6084
|
routeChangeTimer = setTimeout(() => {
|
|
5059
6085
|
routeChangeTimer = void 0;
|
|
6086
|
+
const regenStart = debugDiscovery ? performance.now() : 0;
|
|
6087
|
+
const rscEnv = server.environments?.rsc;
|
|
6088
|
+
const skipStaticWrite = !rscEnv?.runner && s.perRouterManifests.length > 0;
|
|
5060
6089
|
try {
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
6090
|
+
if (skipStaticWrite) {
|
|
6091
|
+
debugDiscovery?.(
|
|
6092
|
+
"watcher: skipping static write (cloudflare HMR \u2014 runtime rediscovery owns gen file)"
|
|
6093
|
+
);
|
|
6094
|
+
} else {
|
|
6095
|
+
writeCombinedRouteTypesWithTracking(s);
|
|
6096
|
+
if (s.perRouterManifests.length > 0) {
|
|
6097
|
+
supplementGenFilesWithRuntimeRoutes(s);
|
|
6098
|
+
}
|
|
5064
6099
|
}
|
|
5065
6100
|
} catch (err) {
|
|
5066
|
-
console.error(
|
|
5067
|
-
`[rsc-router] Route regeneration error: ${err.message}`
|
|
5068
|
-
);
|
|
6101
|
+
console.error(`[rango] Route regeneration error: ${err.message}`);
|
|
5069
6102
|
}
|
|
6103
|
+
debugDiscovery?.(
|
|
6104
|
+
"watcher: regenerated gen files (%sms)",
|
|
6105
|
+
(performance.now() - regenStart).toFixed(1)
|
|
6106
|
+
);
|
|
5070
6107
|
if (s.perRouterManifests.length > 0) {
|
|
5071
6108
|
refreshRuntimeDiscovery().catch((err) => {
|
|
5072
6109
|
console.warn(
|
|
5073
|
-
`[
|
|
6110
|
+
`[rango] Runtime re-discovery error: ${err.message}`
|
|
5074
6111
|
);
|
|
6112
|
+
resolveDiscoveryGate();
|
|
5075
6113
|
});
|
|
5076
6114
|
}
|
|
5077
6115
|
}, 100);
|
|
5078
6116
|
};
|
|
5079
6117
|
const handleRouteFileChange = (filePath) => {
|
|
5080
6118
|
if (maybeHandleGeneratedRouteFileMutation(filePath)) return;
|
|
5081
|
-
if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx") && !filePath.endsWith(".js") && !filePath.endsWith(".jsx"))
|
|
6119
|
+
if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx") && !filePath.endsWith(".js") && !filePath.endsWith(".jsx")) {
|
|
6120
|
+
if (s.lastDiscoveryError) {
|
|
6121
|
+
debugDiscovery?.(
|
|
6122
|
+
"watcher: skip non-source %s [LASTERR %s]",
|
|
6123
|
+
filePath,
|
|
6124
|
+
s.lastDiscoveryError.message
|
|
6125
|
+
);
|
|
6126
|
+
}
|
|
6127
|
+
return;
|
|
6128
|
+
}
|
|
6129
|
+
if (s.scanFilter && !s.scanFilter(filePath)) {
|
|
6130
|
+
if (s.lastDiscoveryError) {
|
|
6131
|
+
debugDiscovery?.(
|
|
6132
|
+
"watcher: skip scan-filter %s [LASTERR %s]",
|
|
6133
|
+
filePath,
|
|
6134
|
+
s.lastDiscoveryError.message
|
|
6135
|
+
);
|
|
6136
|
+
}
|
|
5082
6137
|
return;
|
|
5083
|
-
|
|
6138
|
+
}
|
|
6139
|
+
const inRecoveryMode = !!s.lastDiscoveryError;
|
|
5084
6140
|
try {
|
|
5085
6141
|
const source = readFileSync6(filePath, "utf-8");
|
|
5086
6142
|
const trimmed = source.trimStart();
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
if (
|
|
6143
|
+
const isUseClient = trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'");
|
|
6144
|
+
if (!inRecoveryMode && isUseClient) return;
|
|
6145
|
+
let hasUrls = source.includes("urls(");
|
|
6146
|
+
let hasCreateRouter = /\bcreateRouter\s*[<(]/.test(source);
|
|
6147
|
+
if (hasUrls) hasUrls = firstCodeMatchIndex(source, /urls\(/g) >= 0;
|
|
6148
|
+
if (hasCreateRouter) {
|
|
6149
|
+
hasCreateRouter = firstCodeMatchIndex(source, /\bcreateRouter\s*[<(]/g) >= 0;
|
|
6150
|
+
}
|
|
6151
|
+
if (!inRecoveryMode && !hasUrls && !hasCreateRouter) return;
|
|
6152
|
+
if (inRecoveryMode) {
|
|
6153
|
+
debugDiscovery?.(
|
|
6154
|
+
"watcher: recovery rediscovery for %s (urls=%s, router=%s, useClient=%s) [LASTERR %s]",
|
|
6155
|
+
filePath,
|
|
6156
|
+
hasUrls,
|
|
6157
|
+
hasCreateRouter,
|
|
6158
|
+
isUseClient,
|
|
6159
|
+
s.lastDiscoveryError.message
|
|
6160
|
+
);
|
|
6161
|
+
} else {
|
|
6162
|
+
debugDiscovery?.(
|
|
6163
|
+
"watcher: %s matches (urls=%s, router=%s)",
|
|
6164
|
+
filePath,
|
|
6165
|
+
hasUrls,
|
|
6166
|
+
hasCreateRouter
|
|
6167
|
+
);
|
|
6168
|
+
}
|
|
5092
6169
|
if (hasCreateRouter) {
|
|
5093
6170
|
const nestedRouterConflict = findNestedRouterConflict([
|
|
5094
6171
|
...s.cachedRouterFiles ?? [],
|
|
@@ -5102,8 +6179,19 @@ ${err.stack}`
|
|
|
5102
6179
|
}
|
|
5103
6180
|
s.cachedRouterFiles = void 0;
|
|
5104
6181
|
}
|
|
6182
|
+
if (s.perRouterManifests.length > 0) {
|
|
6183
|
+
gate.noteRouteEvent();
|
|
6184
|
+
}
|
|
5105
6185
|
scheduleRouteRegeneration();
|
|
5106
|
-
} catch {
|
|
6186
|
+
} catch (readErr) {
|
|
6187
|
+
if (s.lastDiscoveryError) {
|
|
6188
|
+
debugDiscovery?.(
|
|
6189
|
+
"watcher: read error %s: %s [LASTERR %s]",
|
|
6190
|
+
filePath,
|
|
6191
|
+
readErr?.message,
|
|
6192
|
+
s.lastDiscoveryError.message
|
|
6193
|
+
);
|
|
6194
|
+
}
|
|
5107
6195
|
}
|
|
5108
6196
|
};
|
|
5109
6197
|
server.watcher.on("add", handleRouteFileChange);
|
|
@@ -5121,19 +6209,35 @@ ${err.stack}`
|
|
|
5121
6209
|
// The manifest data is stored for the virtual module's load hook.
|
|
5122
6210
|
async buildStart() {
|
|
5123
6211
|
if (!s.isBuildMode) return;
|
|
5124
|
-
if (s.mergedRouteManifest !== null)
|
|
6212
|
+
if (s.mergedRouteManifest !== null) {
|
|
6213
|
+
debugDiscovery?.(
|
|
6214
|
+
"build: skip (already discovered, env=%s)",
|
|
6215
|
+
this.environment?.name ?? "?"
|
|
6216
|
+
);
|
|
6217
|
+
return;
|
|
6218
|
+
}
|
|
6219
|
+
const buildStartTime = performance.now();
|
|
6220
|
+
debugDiscovery?.("build: start (env=%s)", this.environment?.name ?? "?");
|
|
5125
6221
|
resetStagedBuildAssets(s.projectRoot);
|
|
5126
6222
|
s.prerenderManifestEntries = null;
|
|
5127
6223
|
s.staticManifestEntries = null;
|
|
5128
|
-
await
|
|
6224
|
+
await timed(
|
|
6225
|
+
debugDiscovery,
|
|
6226
|
+
"build acquireBuildEnv",
|
|
6227
|
+
() => acquireBuildEnv(s, viteCommand, viteMode)
|
|
6228
|
+
);
|
|
5129
6229
|
let tempServer = null;
|
|
5130
6230
|
globalThis.__rscRouterDiscoveryActive = true;
|
|
5131
6231
|
try {
|
|
5132
|
-
tempServer = await
|
|
6232
|
+
tempServer = await timed(
|
|
6233
|
+
debugDiscovery,
|
|
6234
|
+
"build createTempRscServer",
|
|
6235
|
+
() => createTempRscServer(s, { forceBuild: true })
|
|
6236
|
+
);
|
|
5133
6237
|
const rscEnv = tempServer.environments?.rsc;
|
|
5134
6238
|
if (!rscEnv?.runner) {
|
|
5135
6239
|
console.warn(
|
|
5136
|
-
"[
|
|
6240
|
+
"[rango] RSC environment runner not available during build, skipping manifest generation"
|
|
5137
6241
|
);
|
|
5138
6242
|
return;
|
|
5139
6243
|
}
|
|
@@ -5143,8 +6247,16 @@ ${err.stack}`
|
|
|
5143
6247
|
if (tempIdsPlugin?.api?.staticHandlerModules) {
|
|
5144
6248
|
s.resolvedStaticModules = tempIdsPlugin.api.staticHandlerModules;
|
|
5145
6249
|
}
|
|
5146
|
-
await
|
|
5147
|
-
|
|
6250
|
+
await timed(
|
|
6251
|
+
debugDiscovery,
|
|
6252
|
+
"build discoverRouters",
|
|
6253
|
+
() => discoverRouters(s, rscEnv)
|
|
6254
|
+
);
|
|
6255
|
+
timedSync(
|
|
6256
|
+
debugDiscovery,
|
|
6257
|
+
"build writeRouteTypesFiles",
|
|
6258
|
+
() => writeRouteTypesFiles(s)
|
|
6259
|
+
);
|
|
5148
6260
|
} catch (err) {
|
|
5149
6261
|
const sourceFile = err.stack?.split("\n").find(
|
|
5150
6262
|
(line) => line.includes(s.projectRoot) && !line.includes("node_modules")
|
|
@@ -5157,15 +6269,52 @@ ${err.stack}`
|
|
|
5157
6269
|
${err.stack}` : null
|
|
5158
6270
|
].filter(Boolean).join("\n");
|
|
5159
6271
|
throw new Error(
|
|
5160
|
-
`[
|
|
5161
|
-
${details}
|
|
6272
|
+
`[rango] Build-time router discovery failed:
|
|
6273
|
+
${details}`,
|
|
6274
|
+
{ cause: err }
|
|
5162
6275
|
);
|
|
5163
6276
|
} finally {
|
|
5164
6277
|
delete globalThis.__rscRouterDiscoveryActive;
|
|
5165
6278
|
if (tempServer) {
|
|
5166
|
-
await
|
|
6279
|
+
await timed(
|
|
6280
|
+
debugDiscovery,
|
|
6281
|
+
"build tempServer.close",
|
|
6282
|
+
() => tempServer.close()
|
|
6283
|
+
);
|
|
5167
6284
|
}
|
|
5168
6285
|
await releaseBuildEnv(s);
|
|
6286
|
+
debugDiscovery?.(
|
|
6287
|
+
"build discovery done (%sms)",
|
|
6288
|
+
(performance.now() - buildStartTime).toFixed(1)
|
|
6289
|
+
);
|
|
6290
|
+
}
|
|
6291
|
+
},
|
|
6292
|
+
// Suppress vite's HMR cascade for our own gen-file writes.
|
|
6293
|
+
//
|
|
6294
|
+
// After every cf HMR cycle, refreshTempRscEnv → writeRouteTypesFiles
|
|
6295
|
+
// writes the configured gen files (default `router.named-routes.gen.ts`,
|
|
6296
|
+
// but the source filenames and gen suffix are user-configurable). The
|
|
6297
|
+
// chokidar watcher then fires twice independently: our
|
|
6298
|
+
// `handleRouteFileChange` (already short-circuited by
|
|
6299
|
+
// `consumeSelfGenWrite` inside `maybeHandleGeneratedRouteFileMutation`),
|
|
6300
|
+
// AND vite's own HMR pipeline (which invalidates the gen file's
|
|
6301
|
+
// importers and triggers a second workerd full reload — visible to the
|
|
6302
|
+
// user as a duplicate "[Rango] HMR: version changed" on the client).
|
|
6303
|
+
//
|
|
6304
|
+
// `peekSelfGenWrite` is the authoritative filter: its map only contains
|
|
6305
|
+
// paths that `markSelfGenWrite` has registered, so it natively works
|
|
6306
|
+
// for any configured gen-file name. It is non-consuming so the chokidar
|
|
6307
|
+
// handler that fires later can still consume the same entry. Returning
|
|
6308
|
+
// [] tells vite "no modules invalidated by this change" — safe because
|
|
6309
|
+
// `s.perRouterManifests` is already up-to-date (the write that just
|
|
6310
|
+
// happened is the consequence of our just-completed rediscovery).
|
|
6311
|
+
handleHotUpdate(ctx) {
|
|
6312
|
+
if (peekSelfGenWrite(s, ctx.file)) {
|
|
6313
|
+
debugDiscovery?.(
|
|
6314
|
+
"handleHotUpdate: suppressing self-write HMR cascade for %s",
|
|
6315
|
+
ctx.file
|
|
6316
|
+
);
|
|
6317
|
+
return [];
|
|
5169
6318
|
}
|
|
5170
6319
|
},
|
|
5171
6320
|
// Virtual module: provides the pre-generated route manifest as a JS module
|
|
@@ -5182,17 +6331,36 @@ ${details}`
|
|
|
5182
6331
|
async load(id) {
|
|
5183
6332
|
if (id === "\0" + VIRTUAL_ROUTES_MANIFEST_ID) {
|
|
5184
6333
|
if (s.discoveryDone) {
|
|
5185
|
-
await
|
|
6334
|
+
await timed(
|
|
6335
|
+
debugRoutes,
|
|
6336
|
+
"await discoveryDone (manifest)",
|
|
6337
|
+
() => s.discoveryDone
|
|
6338
|
+
);
|
|
5186
6339
|
}
|
|
5187
|
-
|
|
6340
|
+
const code = await timed(
|
|
6341
|
+
debugRoutes,
|
|
6342
|
+
"generateRoutesManifestModule",
|
|
6343
|
+
() => generateRoutesManifestModule(s)
|
|
6344
|
+
);
|
|
6345
|
+
debugRoutes?.("manifest module emitted (%d bytes)", code?.length ?? 0);
|
|
6346
|
+
return code;
|
|
5188
6347
|
}
|
|
5189
6348
|
const perRouterPrefix = "\0" + VIRTUAL_ROUTES_MANIFEST_ID + "/";
|
|
5190
6349
|
if (id.startsWith(perRouterPrefix)) {
|
|
5191
6350
|
if (s.discoveryDone) {
|
|
5192
|
-
await
|
|
6351
|
+
await timed(
|
|
6352
|
+
debugRoutes,
|
|
6353
|
+
"await discoveryDone (per-router)",
|
|
6354
|
+
() => s.discoveryDone
|
|
6355
|
+
);
|
|
5193
6356
|
}
|
|
5194
6357
|
const routerId = id.slice(perRouterPrefix.length);
|
|
5195
|
-
|
|
6358
|
+
const code = await timed(
|
|
6359
|
+
debugRoutes,
|
|
6360
|
+
`generatePerRouterModule ${routerId}`,
|
|
6361
|
+
() => generatePerRouterModule(s, routerId)
|
|
6362
|
+
);
|
|
6363
|
+
return code;
|
|
5196
6364
|
}
|
|
5197
6365
|
return null;
|
|
5198
6366
|
},
|
|
@@ -5200,14 +6368,20 @@ ${details}`
|
|
|
5200
6368
|
// Used by closeBundle for handler code eviction and prerender data injection.
|
|
5201
6369
|
generateBundle(_options, bundle) {
|
|
5202
6370
|
if (this.environment?.name !== "rsc") return;
|
|
6371
|
+
const genStart = debugBuild ? performance.now() : 0;
|
|
5203
6372
|
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
5204
6373
|
if (chunk.type === "chunk" && chunk.isEntry) {
|
|
5205
6374
|
s.rscEntryFileName = fileName;
|
|
5206
6375
|
break;
|
|
5207
6376
|
}
|
|
5208
6377
|
}
|
|
5209
|
-
if (!s.resolvedPrerenderModules?.size && !s.resolvedStaticModules?.size)
|
|
6378
|
+
if (!s.resolvedPrerenderModules?.size && !s.resolvedStaticModules?.size) {
|
|
6379
|
+
debugBuild?.(
|
|
6380
|
+
"generateBundle (rsc): no handlers to scan (%sms)",
|
|
6381
|
+
(performance.now() - genStart).toFixed(1)
|
|
6382
|
+
);
|
|
5210
6383
|
return;
|
|
6384
|
+
}
|
|
5211
6385
|
s.handlerChunkInfoMap.clear();
|
|
5212
6386
|
s.staticHandlerChunkInfoMap.clear();
|
|
5213
6387
|
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
@@ -5251,6 +6425,13 @@ ${details}`
|
|
|
5251
6425
|
}
|
|
5252
6426
|
}
|
|
5253
6427
|
}
|
|
6428
|
+
debugBuild?.(
|
|
6429
|
+
"generateBundle (rsc): scanned %d chunks, %d prerender chunk(s), %d static chunk(s) (%sms)",
|
|
6430
|
+
Object.keys(bundle).length,
|
|
6431
|
+
s.handlerChunkInfoMap.size,
|
|
6432
|
+
s.staticHandlerChunkInfoMap.size,
|
|
6433
|
+
(performance.now() - genStart).toFixed(1)
|
|
6434
|
+
);
|
|
5254
6435
|
},
|
|
5255
6436
|
// Build-time pre-rendering: evict handler code and inject collected prerender data.
|
|
5256
6437
|
// Collection now happens in-process during discoverRouters() via RSC runner.
|
|
@@ -5261,29 +6442,45 @@ ${details}`
|
|
|
5261
6442
|
async handler() {
|
|
5262
6443
|
if (!s.isBuildMode) return;
|
|
5263
6444
|
if (this.environment && this.environment.name !== "rsc") return;
|
|
5264
|
-
|
|
6445
|
+
timedSync(
|
|
6446
|
+
debugBuild,
|
|
6447
|
+
"closeBundle postprocessBundle",
|
|
6448
|
+
() => postprocessBundle(s)
|
|
6449
|
+
);
|
|
5265
6450
|
}
|
|
5266
6451
|
}
|
|
5267
6452
|
};
|
|
5268
6453
|
}
|
|
5269
6454
|
|
|
5270
6455
|
// src/vite/rango.ts
|
|
6456
|
+
var debugConfig = createRangoDebugger(NS.config);
|
|
5271
6457
|
async function rango(options) {
|
|
6458
|
+
const rangoStart = performance.now();
|
|
5272
6459
|
const resolvedOptions = options ?? { preset: "node" };
|
|
5273
6460
|
const preset = resolvedOptions.preset ?? "node";
|
|
5274
6461
|
const showBanner = resolvedOptions.banner ?? true;
|
|
6462
|
+
const clientChunksOption = resolvedOptions.clientChunks ?? true;
|
|
6463
|
+
const useBuiltInClientChunks = clientChunksOption === true;
|
|
6464
|
+
const clientChunkCtx = useBuiltInClientChunks ? { fallbackRefs: /* @__PURE__ */ new Set() } : void 0;
|
|
6465
|
+
const clientChunks = resolveClientChunks(clientChunksOption, clientChunkCtx);
|
|
6466
|
+
debugConfig?.("rango(%s) setup start", preset);
|
|
5275
6467
|
const plugins = [];
|
|
5276
|
-
const rangoAliases = getPackageAliases();
|
|
6468
|
+
const rangoAliases = { ...getPackageAliases(), ...getVendorAliases() };
|
|
5277
6469
|
const excludeDeps = [
|
|
5278
6470
|
...getExcludeDeps(),
|
|
5279
|
-
//
|
|
5280
|
-
//
|
|
5281
|
-
// .
|
|
6471
|
+
// plugin-rsc itself injects these into the client env's
|
|
6472
|
+
// optimizeDeps.include, which overrides exclude for the dep's own
|
|
6473
|
+
// pre-bundle entry. What exclude still controls is how *other*
|
|
6474
|
+
// pre-bundled deps treat imports of these specs (external vs inlined)
|
|
6475
|
+
// via esbuildCjsExternalPlugin. The cjs-to-esm transform in
|
|
6476
|
+
// plugins/cjs-to-esm.ts is the fallback for strict-pnpm consumers,
|
|
6477
|
+
// where client.browser's bare include fails to resolve and Vite ends up
|
|
6478
|
+
// serving the raw CJS file at dev-serve time.
|
|
5282
6479
|
"@vitejs/plugin-rsc/browser",
|
|
5283
|
-
// Keep the browser RSDW client out of Vite's dep optimizer so our
|
|
5284
|
-
// cjs-to-esm transform can patch the real file.
|
|
5285
6480
|
"@vitejs/plugin-rsc/vendor/react-server-dom/client.browser"
|
|
5286
6481
|
];
|
|
6482
|
+
const pkg = getPublishedPackageName();
|
|
6483
|
+
const nested = (spec) => `${pkg} > ${spec}`;
|
|
5287
6484
|
const routerRef = { path: void 0 };
|
|
5288
6485
|
const prerenderEnabled = true;
|
|
5289
6486
|
if (preset === "cloudflare") {
|
|
@@ -5301,10 +6498,18 @@ async function rango(options) {
|
|
|
5301
6498
|
// This ensures the same Context instance is used by both browser entry and RSC proxy modules
|
|
5302
6499
|
optimizeDeps: {
|
|
5303
6500
|
exclude: excludeDeps,
|
|
5304
|
-
|
|
6501
|
+
rolldownOptions: sharedRolldownOptions
|
|
5305
6502
|
},
|
|
5306
6503
|
resolve: {
|
|
5307
|
-
alias: rangoAliases
|
|
6504
|
+
alias: rangoAliases,
|
|
6505
|
+
// Force a single React/React-DOM copy across all three RSC
|
|
6506
|
+
// environments. RSC requires exactly one react/react-dom instance
|
|
6507
|
+
// per environment runtime; consumer install topologies (pnpm
|
|
6508
|
+
// strict layout, experimental React pins, third-party "use client"
|
|
6509
|
+
// packages) can otherwise resolve duplicate copies, causing
|
|
6510
|
+
// "Invalid hook call" / lost context. Child environments inherit
|
|
6511
|
+
// this root dedupe, and Vite merges it with any consumer dedupe.
|
|
6512
|
+
dedupe: ["react", "react-dom"]
|
|
5308
6513
|
},
|
|
5309
6514
|
build: {
|
|
5310
6515
|
rollupOptions: { onwarn }
|
|
@@ -5313,6 +6518,14 @@ async function rango(options) {
|
|
|
5313
6518
|
client: {
|
|
5314
6519
|
build: {
|
|
5315
6520
|
rollupOptions: {
|
|
6521
|
+
// FILE_NAME_CONFLICT (and any other client-build warning) is
|
|
6522
|
+
// emitted by the CLIENT environment build, which consults THIS
|
|
6523
|
+
// env's onwarn -- Vite 8's environment builds do NOT propagate
|
|
6524
|
+
// the top-level build.rollupOptions.onwarn into the client env.
|
|
6525
|
+
// Wire it here so the suppression runs where the conflicts
|
|
6526
|
+
// originate (the top-level handler is invoked 0x for these; the
|
|
6527
|
+
// client-env handler is invoked for all of them).
|
|
6528
|
+
onwarn,
|
|
5316
6529
|
output: {
|
|
5317
6530
|
manualChunks: getManualChunks
|
|
5318
6531
|
}
|
|
@@ -5321,9 +6534,9 @@ async function rango(options) {
|
|
|
5321
6534
|
// Pre-bundle rsc-html-stream to prevent discovery during first request
|
|
5322
6535
|
// Exclude rsc-router modules to ensure same Context instance
|
|
5323
6536
|
optimizeDeps: {
|
|
5324
|
-
include: ["rsc-html-stream/client"],
|
|
6537
|
+
include: [nested("rsc-html-stream/client")],
|
|
5325
6538
|
exclude: excludeDeps,
|
|
5326
|
-
|
|
6539
|
+
rolldownOptions: sharedRolldownOptions
|
|
5327
6540
|
}
|
|
5328
6541
|
},
|
|
5329
6542
|
ssr: {
|
|
@@ -5331,10 +6544,6 @@ async function rango(options) {
|
|
|
5331
6544
|
build: {
|
|
5332
6545
|
outDir: "./dist/rsc/ssr"
|
|
5333
6546
|
},
|
|
5334
|
-
resolve: {
|
|
5335
|
-
// Ensure single React instance in SSR child environment
|
|
5336
|
-
dedupe: ["react", "react-dom"]
|
|
5337
|
-
},
|
|
5338
6547
|
// Pre-bundle SSR entry and React for proper module linking with childEnvironments
|
|
5339
6548
|
// All deps must be listed to avoid late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
5340
6549
|
optimizeDeps: {
|
|
@@ -5346,11 +6555,13 @@ async function rango(options) {
|
|
|
5346
6555
|
"react-dom/static.edge",
|
|
5347
6556
|
"react/jsx-runtime",
|
|
5348
6557
|
"react/jsx-dev-runtime",
|
|
5349
|
-
"rsc-html-stream/server",
|
|
5350
|
-
|
|
6558
|
+
nested("rsc-html-stream/server"),
|
|
6559
|
+
nested(
|
|
6560
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
|
|
6561
|
+
)
|
|
5351
6562
|
],
|
|
5352
6563
|
exclude: excludeDeps,
|
|
5353
|
-
|
|
6564
|
+
rolldownOptions: sharedRolldownOptions
|
|
5354
6565
|
}
|
|
5355
6566
|
},
|
|
5356
6567
|
rsc: {
|
|
@@ -5362,10 +6573,12 @@ async function rango(options) {
|
|
|
5362
6573
|
"react",
|
|
5363
6574
|
"react/jsx-runtime",
|
|
5364
6575
|
"react/jsx-dev-runtime",
|
|
5365
|
-
|
|
6576
|
+
nested(
|
|
6577
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
6578
|
+
)
|
|
5366
6579
|
],
|
|
5367
6580
|
exclude: excludeDeps,
|
|
5368
|
-
|
|
6581
|
+
rolldownOptions: sharedRolldownOptions
|
|
5369
6582
|
}
|
|
5370
6583
|
}
|
|
5371
6584
|
}
|
|
@@ -5383,7 +6596,8 @@ async function rango(options) {
|
|
|
5383
6596
|
plugins.push(
|
|
5384
6597
|
rsc({
|
|
5385
6598
|
entries: finalEntries,
|
|
5386
|
-
serverHandler: false
|
|
6599
|
+
serverHandler: false,
|
|
6600
|
+
clientChunks
|
|
5387
6601
|
})
|
|
5388
6602
|
);
|
|
5389
6603
|
plugins.push(clientRefDedup());
|
|
@@ -5401,7 +6615,7 @@ async function rango(options) {
|
|
|
5401
6615
|
const list = candidates.map(
|
|
5402
6616
|
(f) => " - " + (f.startsWith(root) ? f.slice(root.length + 1) : f)
|
|
5403
6617
|
).join("\n");
|
|
5404
|
-
throw new Error(`[
|
|
6618
|
+
throw new Error(`[rango] Multiple routers found:
|
|
5405
6619
|
${list}`);
|
|
5406
6620
|
}
|
|
5407
6621
|
}
|
|
@@ -5420,18 +6634,34 @@ ${list}`);
|
|
|
5420
6634
|
return {
|
|
5421
6635
|
optimizeDeps: {
|
|
5422
6636
|
exclude: excludeDeps,
|
|
5423
|
-
|
|
6637
|
+
rolldownOptions: sharedRolldownOptions
|
|
5424
6638
|
},
|
|
5425
6639
|
build: {
|
|
5426
6640
|
rollupOptions: { onwarn }
|
|
5427
6641
|
},
|
|
5428
6642
|
resolve: {
|
|
5429
|
-
alias: rangoAliases
|
|
6643
|
+
alias: rangoAliases,
|
|
6644
|
+
// Force a single React/React-DOM copy across all three RSC
|
|
6645
|
+
// environments. RSC requires exactly one react/react-dom instance
|
|
6646
|
+
// per environment runtime; consumer install topologies (pnpm
|
|
6647
|
+
// strict layout, experimental React pins, third-party "use client"
|
|
6648
|
+
// packages) can otherwise resolve duplicate copies, causing
|
|
6649
|
+
// "Invalid hook call" / lost context. Child environments inherit
|
|
6650
|
+
// this root dedupe, and Vite merges it with any consumer dedupe.
|
|
6651
|
+
dedupe: ["react", "react-dom"]
|
|
5430
6652
|
},
|
|
5431
6653
|
environments: {
|
|
5432
6654
|
client: {
|
|
5433
6655
|
build: {
|
|
5434
6656
|
rollupOptions: {
|
|
6657
|
+
// FILE_NAME_CONFLICT (and any other client-build warning) is
|
|
6658
|
+
// emitted by the CLIENT environment build, which consults THIS
|
|
6659
|
+
// env's onwarn -- Vite 8's environment builds do NOT propagate
|
|
6660
|
+
// the top-level build.rollupOptions.onwarn into the client env.
|
|
6661
|
+
// Wire it here so the suppression runs where the conflicts
|
|
6662
|
+
// originate (the top-level handler is invoked 0x for these; the
|
|
6663
|
+
// client-env handler is invoked for all of them).
|
|
6664
|
+
onwarn,
|
|
5435
6665
|
output: {
|
|
5436
6666
|
manualChunks: getManualChunks
|
|
5437
6667
|
}
|
|
@@ -5443,10 +6673,10 @@ ${list}`);
|
|
|
5443
6673
|
"react-dom",
|
|
5444
6674
|
"react/jsx-runtime",
|
|
5445
6675
|
"react/jsx-dev-runtime",
|
|
5446
|
-
"rsc-html-stream/client"
|
|
6676
|
+
nested("rsc-html-stream/client")
|
|
5447
6677
|
],
|
|
5448
6678
|
exclude: excludeDeps,
|
|
5449
|
-
|
|
6679
|
+
rolldownOptions: sharedRolldownOptions,
|
|
5450
6680
|
entries: [VIRTUAL_IDS.browser]
|
|
5451
6681
|
}
|
|
5452
6682
|
},
|
|
@@ -5460,10 +6690,12 @@ ${list}`);
|
|
|
5460
6690
|
"react-dom/static.edge",
|
|
5461
6691
|
"react/jsx-runtime",
|
|
5462
6692
|
"react/jsx-dev-runtime",
|
|
5463
|
-
|
|
6693
|
+
nested(
|
|
6694
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
|
|
6695
|
+
)
|
|
5464
6696
|
],
|
|
5465
6697
|
exclude: excludeDeps,
|
|
5466
|
-
|
|
6698
|
+
rolldownOptions: sharedRolldownOptions
|
|
5467
6699
|
}
|
|
5468
6700
|
},
|
|
5469
6701
|
rsc: {
|
|
@@ -5473,9 +6705,11 @@ ${list}`);
|
|
|
5473
6705
|
"react",
|
|
5474
6706
|
"react/jsx-runtime",
|
|
5475
6707
|
"react/jsx-dev-runtime",
|
|
5476
|
-
|
|
6708
|
+
nested(
|
|
6709
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
6710
|
+
)
|
|
5477
6711
|
],
|
|
5478
|
-
|
|
6712
|
+
rolldownOptions: sharedRolldownOptions
|
|
5479
6713
|
}
|
|
5480
6714
|
}
|
|
5481
6715
|
}
|
|
@@ -5492,7 +6726,7 @@ ${list}`);
|
|
|
5492
6726
|
if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
|
|
5493
6727
|
hasWarnedDuplicate = true;
|
|
5494
6728
|
console.warn(
|
|
5495
|
-
"[
|
|
6729
|
+
"[rango] Duplicate @vitejs/plugin-rsc detected. Remove rsc() from your vite config \u2014 rango() includes it automatically."
|
|
5496
6730
|
);
|
|
5497
6731
|
}
|
|
5498
6732
|
}
|
|
@@ -5501,7 +6735,8 @@ ${list}`);
|
|
|
5501
6735
|
plugins.push(performanceTracksPlugin());
|
|
5502
6736
|
plugins.push(
|
|
5503
6737
|
rsc({
|
|
5504
|
-
entries: finalEntries
|
|
6738
|
+
entries: finalEntries,
|
|
6739
|
+
clientChunks
|
|
5505
6740
|
})
|
|
5506
6741
|
);
|
|
5507
6742
|
plugins.push(clientRefDedup());
|
|
@@ -5540,9 +6775,16 @@ ${list}`);
|
|
|
5540
6775
|
routerPathRef: discoveryRouterRef,
|
|
5541
6776
|
enableBuildPrerender: prerenderEnabled,
|
|
5542
6777
|
buildEnv: options?.buildEnv,
|
|
5543
|
-
preset
|
|
6778
|
+
preset,
|
|
6779
|
+
clientChunkCtx
|
|
5544
6780
|
})
|
|
5545
6781
|
);
|
|
6782
|
+
debugConfig?.(
|
|
6783
|
+
"rango(%s) setup done: %d plugin(s) (%sms)",
|
|
6784
|
+
preset,
|
|
6785
|
+
plugins.length,
|
|
6786
|
+
(performance.now() - rangoStart).toFixed(1)
|
|
6787
|
+
);
|
|
5546
6788
|
return plugins;
|
|
5547
6789
|
}
|
|
5548
6790
|
|
|
@@ -5553,7 +6795,7 @@ function poke() {
|
|
|
5553
6795
|
apply: "serve",
|
|
5554
6796
|
configureServer(server) {
|
|
5555
6797
|
const stdin = process.stdin;
|
|
5556
|
-
const
|
|
6798
|
+
const debug11 = process.env.RANGO_POKE_DEBUG === "1";
|
|
5557
6799
|
const triggerReload = (source) => {
|
|
5558
6800
|
server.hot.send({ type: "full-reload", path: "*" });
|
|
5559
6801
|
server.config.logger.info(` browser reload (${source})`, {
|
|
@@ -5586,7 +6828,7 @@ function poke() {
|
|
|
5586
6828
|
lines.pop();
|
|
5587
6829
|
return lines;
|
|
5588
6830
|
};
|
|
5589
|
-
if (
|
|
6831
|
+
if (debug11) {
|
|
5590
6832
|
server.config.logger.info(
|
|
5591
6833
|
` poke debug enabled (isTTY=${stdin.isTTY ? "yes" : "no"}, isRaw=${stdin.isTTY ? stdin.isRaw ? "yes" : "no" : "n/a"})`,
|
|
5592
6834
|
{ timestamp: true }
|
|
@@ -5599,7 +6841,7 @@ function poke() {
|
|
|
5599
6841
|
);
|
|
5600
6842
|
}
|
|
5601
6843
|
const onData = (data) => {
|
|
5602
|
-
if (
|
|
6844
|
+
if (debug11) {
|
|
5603
6845
|
server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
|
|
5604
6846
|
timestamp: true
|
|
5605
6847
|
});
|