@rangojs/router 0.0.0-experimental.dfdb0387 → 0.0.0-experimental.e16b7c00
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 +2106 -842
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +13 -8
- package/skills/breadcrumbs/SKILL.md +3 -1
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +222 -30
- package/skills/caching/SKILL.md +188 -8
- package/skills/composability/SKILL.md +27 -2
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +229 -20
- package/skills/host-router/SKILL.md +45 -20
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +46 -4
- package/skills/layout/SKILL.md +28 -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 +582 -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 +71 -6
- package/skills/prerender/SKILL.md +14 -33
- package/skills/rango/SKILL.md +236 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +66 -9
- package/skills/route/SKILL.md +57 -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/typesafety/SKILL.md +319 -27
- package/skills/use-cache/SKILL.md +36 -5
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +117 -0
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/app-shell.ts +52 -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 +86 -11
- package/src/browser/navigation-client.ts +45 -25
- package/src/browser/navigation-store.ts +32 -9
- package/src/browser/navigation-transaction.ts +10 -28
- package/src/browser/partial-update.ts +61 -28
- package/src/browser/prefetch/cache.ts +124 -26
- package/src/browser/prefetch/fetch.ts +129 -37
- package/src/browser/prefetch/queue.ts +36 -5
- package/src/browser/rango-state.ts +53 -13
- package/src/browser/react/Link.tsx +18 -13
- package/src/browser/react/NavigationProvider.tsx +72 -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 +22 -2
- package/src/browser/react/use-segments.ts +11 -8
- package/src/browser/response-adapter.ts +25 -0
- package/src/browser/rsc-router.tsx +64 -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 +23 -30
- package/src/browser/types.ts +21 -0
- 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 +2 -0
- package/src/build/route-trie.ts +52 -25
- 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-error.ts +104 -0
- package/src/cache/cache-policy.ts +95 -1
- package/src/cache/cache-runtime.ts +79 -13
- package/src/cache/cache-scope.ts +77 -46
- package/src/cache/cache-tag.ts +135 -0
- package/src/cache/cf/cf-cache-store.ts +1067 -176
- package/src/cache/cf/index.ts +4 -1
- package/src/cache/document-cache.ts +59 -7
- package/src/cache/index.ts +6 -0
- package/src/cache/memory-segment-store.ts +158 -14
- package/src/cache/tag-invalidation.ts +206 -0
- package/src/cache/types.ts +27 -0
- package/src/client.rsc.tsx +3 -0
- package/src/client.tsx +92 -182
- package/src/context-var.ts +5 -5
- package/src/decode-loader-results.ts +36 -0
- package/src/errors.ts +30 -1
- 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 -20
- package/src/index.rsc.ts +16 -4
- package/src/index.ts +65 -15
- 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.ts +4 -4
- package/src/response-utils.ts +37 -0
- package/src/reverse.ts +65 -36
- package/src/route-content-wrapper.tsx +6 -28
- package/src/route-definition/dsl-helpers.ts +384 -257
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +100 -28
- 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/handler-context.ts +21 -38
- package/src/router/intercept-resolution.ts +4 -18
- package/src/router/lazy-includes.ts +8 -8
- package/src/router/loader-resolution.ts +19 -2
- package/src/router/manifest.ts +22 -13
- package/src/router/match-api.ts +4 -3
- package/src/router/match-handlers.ts +1 -0
- package/src/router/match-middleware/cache-lookup.ts +46 -92
- 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 +101 -17
- package/src/router/prerender-match.ts +3 -1
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +4 -28
- package/src/router/revalidation.ts +58 -2
- package/src/router/router-interfaces.ts +45 -28
- 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/loader-cache.ts +8 -17
- package/src/router/segment-resolution/revalidation.ts +147 -106
- 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 +18 -13
- package/src/router/types.ts +8 -0
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +23 -18
- package/src/rsc/handler-context.ts +2 -2
- package/src/rsc/handler.ts +38 -70
- package/src/rsc/helpers.ts +72 -43
- package/src/rsc/index.ts +1 -1
- package/src/rsc/origin-guard.ts +28 -10
- package/src/rsc/progressive-enhancement.ts +4 -0
- package/src/rsc/response-route-handler.ts +54 -54
- package/src/rsc/rsc-rendering.ts +35 -51
- package/src/rsc/runtime-warnings.ts +9 -10
- package/src/rsc/server-action.ts +17 -37
- 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 +143 -53
- package/src/server/cookie-store.ts +28 -4
- package/src/server/request-context.ts +46 -44
- package/src/ssr/index.tsx +5 -1
- package/src/static-handler.ts +1 -1
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +5 -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 +5 -6
- 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 +0 -3
- package/src/urls/path-helper-types.ts +41 -7
- 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 +26 -116
- 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 +101 -51
- 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 +67 -26
- 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 +750 -100
- 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 +21 -5
- package/src/vite/utils/package-resolution.ts +41 -1
- package/src/vite/utils/prerender-utils.ts +21 -6
- 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.e16b7c00",
|
|
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 };
|
|
3838
|
+
},
|
|
3839
|
+
resolveId(id) {
|
|
3840
|
+
if (id.startsWith(VIRTUAL_PREFIX)) {
|
|
3841
|
+
return "\0" + id;
|
|
3842
|
+
}
|
|
3843
|
+
return null;
|
|
3337
3844
|
},
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
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;
|
|
@@ -3488,9 +4021,12 @@ function consumeSelfGenWrite(state, filePath) {
|
|
|
3488
4021
|
|
|
3489
4022
|
// src/vite/utils/manifest-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) {
|
|
@@ -3580,11 +4118,19 @@ function substituteRouteParams(pattern, params, encode = encodeURIComponent) {
|
|
|
3580
4118
|
let hadOmittedOptional = false;
|
|
3581
4119
|
for (const [key, value] of Object.entries(params)) {
|
|
3582
4120
|
const escaped = escapeRegExp2(key);
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
4121
|
+
if (value === "") {
|
|
4122
|
+
result = result.replace(
|
|
4123
|
+
new RegExp(`:${escaped}(\\([^)]*\\))?(?!\\?)`),
|
|
4124
|
+
""
|
|
4125
|
+
);
|
|
4126
|
+
result = result.replace(`*${key}`, "");
|
|
4127
|
+
} else {
|
|
4128
|
+
result = result.replace(
|
|
4129
|
+
new RegExp(`:${escaped}(\\([^)]*\\))?\\??`),
|
|
4130
|
+
encode(value)
|
|
4131
|
+
);
|
|
4132
|
+
result = result.replace(`*${key}`, encode(value));
|
|
4133
|
+
}
|
|
3588
4134
|
}
|
|
3589
4135
|
result = result.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\([^)]*\))?\?/g, () => {
|
|
3590
4136
|
hadOmittedOptional = true;
|
|
@@ -3690,8 +4236,14 @@ function copyStagedBuildAssets(projectRoot, fileNames) {
|
|
|
3690
4236
|
}
|
|
3691
4237
|
|
|
3692
4238
|
// src/vite/discovery/prerender-collection.ts
|
|
4239
|
+
var debug9 = createRangoDebugger(NS.prerender);
|
|
3693
4240
|
async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
3694
4241
|
if (!state.opts?.enableBuildPrerender || !state.isBuildMode) return;
|
|
4242
|
+
const overallStart = debug9 ? performance.now() : 0;
|
|
4243
|
+
debug9?.(
|
|
4244
|
+
"expandPrerenderRoutes: start (%d router manifest(s))",
|
|
4245
|
+
allManifests.length
|
|
4246
|
+
);
|
|
3695
4247
|
const entries = [];
|
|
3696
4248
|
const allRoutes = {};
|
|
3697
4249
|
for (const { manifest: m } of allManifests) {
|
|
@@ -3718,7 +4270,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3718
4270
|
const progressInterval = totalDynamic > 0 ? setInterval(() => {
|
|
3719
4271
|
const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
|
|
3720
4272
|
console.log(
|
|
3721
|
-
`[
|
|
4273
|
+
`[rango] Resolving prerender params... ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
|
|
3722
4274
|
);
|
|
3723
4275
|
}, 5e3) : void 0;
|
|
3724
4276
|
try {
|
|
@@ -3741,6 +4293,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3741
4293
|
});
|
|
3742
4294
|
} else {
|
|
3743
4295
|
if (def?.getParams) {
|
|
4296
|
+
const getParamsStart = debug9 ? performance.now() : 0;
|
|
3744
4297
|
try {
|
|
3745
4298
|
const buildVars = {};
|
|
3746
4299
|
const buildEnv = state.resolvedBuildEnv;
|
|
@@ -3754,11 +4307,17 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3754
4307
|
get env() {
|
|
3755
4308
|
if (buildEnv !== void 0) return buildEnv;
|
|
3756
4309
|
throw new Error(
|
|
3757
|
-
"[
|
|
4310
|
+
"[rango] ctx.env is not available during build-time getParams(). Configure buildEnv in your rango() plugin options to enable build-time env access."
|
|
3758
4311
|
);
|
|
3759
4312
|
}
|
|
3760
4313
|
};
|
|
3761
4314
|
const paramsList = await def.getParams(getParamsCtx);
|
|
4315
|
+
debug9?.(
|
|
4316
|
+
"getParams %s -> %d params (%sms)",
|
|
4317
|
+
routeName,
|
|
4318
|
+
paramsList.length,
|
|
4319
|
+
(performance.now() - getParamsStart).toFixed(1)
|
|
4320
|
+
);
|
|
3762
4321
|
const concurrency = def.options?.concurrency ?? 1;
|
|
3763
4322
|
const hasBuildVars = Object.keys(buildVars).length > 0 || Object.getOwnPropertySymbols(buildVars).length > 0;
|
|
3764
4323
|
for (const params of paramsList) {
|
|
@@ -3789,7 +4348,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3789
4348
|
resolvedRoutes++;
|
|
3790
4349
|
if (err.name === "Skip") {
|
|
3791
4350
|
console.log(
|
|
3792
|
-
`[
|
|
4351
|
+
`[rango] SKIP route "${routeName}" - ${err.message}`
|
|
3793
4352
|
);
|
|
3794
4353
|
notifyOnError(
|
|
3795
4354
|
registry,
|
|
@@ -3802,14 +4361,14 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3802
4361
|
continue;
|
|
3803
4362
|
}
|
|
3804
4363
|
console.error(
|
|
3805
|
-
`[
|
|
4364
|
+
`[rango] Failed to get params for prerender route "${routeName}": ${err.message}`
|
|
3806
4365
|
);
|
|
3807
4366
|
notifyOnError(registry, err, "prerender", routeName);
|
|
3808
4367
|
throw err;
|
|
3809
4368
|
}
|
|
3810
4369
|
} else {
|
|
3811
4370
|
console.warn(
|
|
3812
|
-
`[
|
|
4371
|
+
`[rango] Dynamic prerender route "${routeName}" has no getParams(), skipping`
|
|
3813
4372
|
);
|
|
3814
4373
|
}
|
|
3815
4374
|
}
|
|
@@ -3820,15 +4379,26 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3820
4379
|
clearInterval(progressInterval);
|
|
3821
4380
|
const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
|
|
3822
4381
|
console.log(
|
|
3823
|
-
`[
|
|
4382
|
+
`[rango] Resolved prerender params: ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
|
|
3824
4383
|
);
|
|
3825
4384
|
}
|
|
3826
4385
|
}
|
|
3827
|
-
if (entries.length === 0)
|
|
4386
|
+
if (entries.length === 0) {
|
|
4387
|
+
debug9?.(
|
|
4388
|
+
"no prerender entries (done in %sms)",
|
|
4389
|
+
(performance.now() - overallStart).toFixed(1)
|
|
4390
|
+
);
|
|
4391
|
+
return;
|
|
4392
|
+
}
|
|
3828
4393
|
const maxConcurrency = Math.max(...entries.map((e) => e.concurrency));
|
|
3829
4394
|
const concurrencyNote = maxConcurrency > 1 ? ` (concurrency: ${maxConcurrency})` : "";
|
|
3830
4395
|
console.log(
|
|
3831
|
-
`[
|
|
4396
|
+
`[rango] Pre-rendering ${entries.length} URL(s)${concurrencyNote}...`
|
|
4397
|
+
);
|
|
4398
|
+
debug9?.(
|
|
4399
|
+
"prerender loop: %d entries, max concurrency %d",
|
|
4400
|
+
entries.length,
|
|
4401
|
+
maxConcurrency
|
|
3832
4402
|
);
|
|
3833
4403
|
const { hashParams } = await rscEnv.runner.import("@rangojs/router/build");
|
|
3834
4404
|
const manifestEntries = {};
|
|
@@ -3856,7 +4426,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3856
4426
|
if (result.passthrough) {
|
|
3857
4427
|
const elapsed2 = (performance.now() - startUrl).toFixed(0);
|
|
3858
4428
|
console.log(
|
|
3859
|
-
`[
|
|
4429
|
+
`[rango] PASS ${entry.urlPath.padEnd(40)} (${elapsed2}ms) - live fallback`
|
|
3860
4430
|
);
|
|
3861
4431
|
doneCount++;
|
|
3862
4432
|
break;
|
|
@@ -3889,7 +4459,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3889
4459
|
}
|
|
3890
4460
|
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
3891
4461
|
console.log(
|
|
3892
|
-
`[
|
|
4462
|
+
`[rango] OK ${entry.urlPath.padEnd(40)} (${elapsed}ms)`
|
|
3893
4463
|
);
|
|
3894
4464
|
doneCount++;
|
|
3895
4465
|
break;
|
|
@@ -3897,7 +4467,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3897
4467
|
if (err.name === "Skip") {
|
|
3898
4468
|
const elapsed2 = (performance.now() - startUrl).toFixed(0);
|
|
3899
4469
|
console.log(
|
|
3900
|
-
`[
|
|
4470
|
+
`[rango] SKIP ${entry.urlPath.padEnd(40)} (${elapsed2}ms) - ${err.message}`
|
|
3901
4471
|
);
|
|
3902
4472
|
skipCount++;
|
|
3903
4473
|
notifyOnError(
|
|
@@ -3912,7 +4482,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3912
4482
|
}
|
|
3913
4483
|
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
3914
4484
|
console.error(
|
|
3915
|
-
`[
|
|
4485
|
+
`[rango] FAIL ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`
|
|
3916
4486
|
);
|
|
3917
4487
|
notifyOnError(
|
|
3918
4488
|
registry,
|
|
@@ -3934,12 +4504,24 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3934
4504
|
const parts = [`${doneCount} done`];
|
|
3935
4505
|
if (skipCount > 0) parts.push(`${skipCount} skipped`);
|
|
3936
4506
|
console.log(
|
|
3937
|
-
`[
|
|
4507
|
+
`[rango] Pre-render complete: ${parts.join(", ")} (${totalElapsed}ms total)`
|
|
4508
|
+
);
|
|
4509
|
+
debug9?.(
|
|
4510
|
+
"expandPrerenderRoutes done: %d done, %d skipped, %sms (overall %sms)",
|
|
4511
|
+
doneCount,
|
|
4512
|
+
skipCount,
|
|
4513
|
+
totalElapsed,
|
|
4514
|
+
(performance.now() - overallStart).toFixed(1)
|
|
3938
4515
|
);
|
|
3939
4516
|
}
|
|
3940
4517
|
async function renderStaticHandlers(state, rscEnv, registry) {
|
|
3941
4518
|
if (!state.opts?.enableBuildPrerender || !state.isBuildMode || !state.resolvedStaticModules?.size)
|
|
3942
4519
|
return;
|
|
4520
|
+
const overallStart = debug9 ? performance.now() : 0;
|
|
4521
|
+
debug9?.(
|
|
4522
|
+
"renderStaticHandlers: start (%d static module(s))",
|
|
4523
|
+
state.resolvedStaticModules.size
|
|
4524
|
+
);
|
|
3943
4525
|
const manifestEntries = {};
|
|
3944
4526
|
let staticDone = 0;
|
|
3945
4527
|
let staticSkip = 0;
|
|
@@ -3948,16 +4530,14 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3948
4530
|
totalStaticCount += exportNames.length;
|
|
3949
4531
|
}
|
|
3950
4532
|
const startStatic = performance.now();
|
|
3951
|
-
console.log(
|
|
3952
|
-
`[rsc-router] Rendering ${totalStaticCount} static handler(s)...`
|
|
3953
|
-
);
|
|
4533
|
+
console.log(`[rango] Rendering ${totalStaticCount} static handler(s)...`);
|
|
3954
4534
|
for (const [moduleId, exportNames] of state.resolvedStaticModules) {
|
|
3955
4535
|
let mod;
|
|
3956
4536
|
try {
|
|
3957
4537
|
mod = await rscEnv.runner.import(moduleId);
|
|
3958
4538
|
} catch (err) {
|
|
3959
4539
|
console.error(
|
|
3960
|
-
`[
|
|
4540
|
+
`[rango] Failed to import static module ${moduleId}: ${err.message}`
|
|
3961
4541
|
);
|
|
3962
4542
|
notifyOnError(registry, err, "static");
|
|
3963
4543
|
throw err;
|
|
@@ -3987,9 +4567,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3987
4567
|
exportValue
|
|
3988
4568
|
);
|
|
3989
4569
|
const elapsed = (performance.now() - startHandler).toFixed(0);
|
|
3990
|
-
console.log(
|
|
3991
|
-
`[rsc-router] OK ${name.padEnd(40)} (${elapsed}ms)`
|
|
3992
|
-
);
|
|
4570
|
+
console.log(`[rango] OK ${name.padEnd(40)} (${elapsed}ms)`);
|
|
3993
4571
|
staticDone++;
|
|
3994
4572
|
handled = true;
|
|
3995
4573
|
break;
|
|
@@ -3998,7 +4576,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3998
4576
|
if (err.name === "Skip") {
|
|
3999
4577
|
const elapsed2 = (performance.now() - startHandler).toFixed(0);
|
|
4000
4578
|
console.log(
|
|
4001
|
-
`[
|
|
4579
|
+
`[rango] SKIP ${name.padEnd(40)} (${elapsed2}ms) - ${err.message}`
|
|
4002
4580
|
);
|
|
4003
4581
|
staticSkip++;
|
|
4004
4582
|
notifyOnError(registry, err, "static", void 0, void 0, true);
|
|
@@ -4007,16 +4585,14 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4007
4585
|
}
|
|
4008
4586
|
const elapsed = (performance.now() - startHandler).toFixed(0);
|
|
4009
4587
|
console.error(
|
|
4010
|
-
`[
|
|
4588
|
+
`[rango] FAIL ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`
|
|
4011
4589
|
);
|
|
4012
4590
|
notifyOnError(registry, err, "static");
|
|
4013
4591
|
throw err;
|
|
4014
4592
|
}
|
|
4015
4593
|
}
|
|
4016
4594
|
if (!handled) {
|
|
4017
|
-
console.warn(
|
|
4018
|
-
`[rsc-router] No router could render static handler "${name}"`
|
|
4019
|
-
);
|
|
4595
|
+
console.warn(`[rango] No router could render static handler "${name}"`);
|
|
4020
4596
|
}
|
|
4021
4597
|
}
|
|
4022
4598
|
}
|
|
@@ -4027,38 +4603,118 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4027
4603
|
const staticParts = [`${staticDone} done`];
|
|
4028
4604
|
if (staticSkip > 0) staticParts.push(`${staticSkip} skipped`);
|
|
4029
4605
|
console.log(
|
|
4030
|
-
`[
|
|
4606
|
+
`[rango] Static render complete: ${staticParts.join(", ")} (${totalStaticElapsed}ms total)`
|
|
4031
4607
|
);
|
|
4608
|
+
debug9?.(
|
|
4609
|
+
"renderStaticHandlers done: %d done, %d skipped, %sms (overall %sms)",
|
|
4610
|
+
staticDone,
|
|
4611
|
+
staticSkip,
|
|
4612
|
+
totalStaticElapsed,
|
|
4613
|
+
(performance.now() - overallStart).toFixed(1)
|
|
4614
|
+
);
|
|
4615
|
+
}
|
|
4616
|
+
|
|
4617
|
+
// src/vite/discovery/discovery-errors.ts
|
|
4618
|
+
function indent(text, pad) {
|
|
4619
|
+
return text.split("\n").map((line) => line.length > 0 ? pad + line : line).join("\n");
|
|
4032
4620
|
}
|
|
4621
|
+
async function invokeLazyMount(loader, context, errors) {
|
|
4622
|
+
try {
|
|
4623
|
+
await loader();
|
|
4624
|
+
} catch (error) {
|
|
4625
|
+
errors.push({ context, error });
|
|
4626
|
+
}
|
|
4627
|
+
}
|
|
4628
|
+
function isLazyMount(route) {
|
|
4629
|
+
return !!route && route.kind === "lazy" && typeof route.handler === "function";
|
|
4630
|
+
}
|
|
4631
|
+
async function resolveHostRouterHandlers(hostRegistry) {
|
|
4632
|
+
const errors = [];
|
|
4633
|
+
for (const [hostId, entry] of hostRegistry) {
|
|
4634
|
+
for (const route of entry.routes) {
|
|
4635
|
+
if (isLazyMount(route)) {
|
|
4636
|
+
await invokeLazyMount(
|
|
4637
|
+
route.handler,
|
|
4638
|
+
`host "${hostId}" route handler`,
|
|
4639
|
+
errors
|
|
4640
|
+
);
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
if (isLazyMount(entry.fallback)) {
|
|
4644
|
+
await invokeLazyMount(
|
|
4645
|
+
entry.fallback.handler,
|
|
4646
|
+
`host "${hostId}" fallback handler`,
|
|
4647
|
+
errors
|
|
4648
|
+
);
|
|
4649
|
+
}
|
|
4650
|
+
}
|
|
4651
|
+
return errors;
|
|
4652
|
+
}
|
|
4653
|
+
function formatNoRoutersError(entryPath, errors) {
|
|
4654
|
+
const base = `[rango] No routers found in registry after importing ${entryPath}`;
|
|
4655
|
+
if (errors.length === 0) {
|
|
4656
|
+
return base;
|
|
4657
|
+
}
|
|
4658
|
+
const formatted = errors.map(({ context, error }) => {
|
|
4659
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
4660
|
+
const detail = err.stack ?? err.message;
|
|
4661
|
+
return ` - while resolving ${context}:
|
|
4662
|
+
${indent(detail, " ")}`;
|
|
4663
|
+
}).join("\n");
|
|
4664
|
+
return `${base}
|
|
4665
|
+
|
|
4666
|
+
${errors.length} error(s) were caught during host-router discovery and likely explain why no routers were registered:
|
|
4667
|
+
${formatted}`;
|
|
4668
|
+
}
|
|
4669
|
+
function toCause(errors) {
|
|
4670
|
+
if (errors.length === 0) return void 0;
|
|
4671
|
+
if (errors.length === 1) return errors[0].error;
|
|
4672
|
+
return new AggregateError(
|
|
4673
|
+
errors.map((e) => e.error),
|
|
4674
|
+
"Multiple host-router handlers failed during discovery"
|
|
4675
|
+
);
|
|
4676
|
+
}
|
|
4677
|
+
var DiscoveryError = class _DiscoveryError extends Error {
|
|
4678
|
+
constructor(entryPath, caught) {
|
|
4679
|
+
super(formatNoRoutersError(entryPath, caught));
|
|
4680
|
+
const cause = toCause(caught);
|
|
4681
|
+
if (cause !== void 0) {
|
|
4682
|
+
this.cause = cause;
|
|
4683
|
+
}
|
|
4684
|
+
this.name = "DiscoveryError";
|
|
4685
|
+
this.entryPath = entryPath;
|
|
4686
|
+
this.caught = caught;
|
|
4687
|
+
Object.setPrototypeOf(this, _DiscoveryError.prototype);
|
|
4688
|
+
}
|
|
4689
|
+
};
|
|
4033
4690
|
|
|
4034
4691
|
// src/vite/discovery/discover-routers.ts
|
|
4692
|
+
var debug10 = createRangoDebugger(NS.discovery);
|
|
4035
4693
|
async function discoverRouters(state, rscEnv) {
|
|
4036
4694
|
if (!state.resolvedEntryPath) return;
|
|
4037
|
-
await
|
|
4038
|
-
|
|
4695
|
+
await timed(
|
|
4696
|
+
debug10,
|
|
4697
|
+
"inner: import entry",
|
|
4698
|
+
() => rscEnv.runner.import(state.resolvedEntryPath)
|
|
4699
|
+
);
|
|
4700
|
+
const serverMod = await timed(
|
|
4701
|
+
debug10,
|
|
4702
|
+
"inner: import @rangojs/router/server",
|
|
4703
|
+
() => rscEnv.runner.import("@rangojs/router/server")
|
|
4704
|
+
);
|
|
4039
4705
|
let registry = serverMod.RouterRegistry;
|
|
4040
4706
|
if (!registry || registry.size === 0) {
|
|
4707
|
+
const discoveryErrors = [];
|
|
4041
4708
|
try {
|
|
4042
4709
|
const hostRegistry = serverMod.HostRouterRegistry;
|
|
4043
4710
|
if (hostRegistry && hostRegistry.size > 0) {
|
|
4044
4711
|
console.log(
|
|
4045
|
-
`[
|
|
4712
|
+
`[rango] Found ${hostRegistry.size} host router(s), resolving lazy handlers...`
|
|
4046
4713
|
);
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
await route.handler();
|
|
4052
|
-
} catch {
|
|
4053
|
-
}
|
|
4054
|
-
}
|
|
4055
|
-
}
|
|
4056
|
-
if (entry.fallback && typeof entry.fallback.handler === "function") {
|
|
4057
|
-
try {
|
|
4058
|
-
await entry.fallback.handler();
|
|
4059
|
-
} catch {
|
|
4060
|
-
}
|
|
4061
|
-
}
|
|
4714
|
+
const handlerErrors = await resolveHostRouterHandlers(hostRegistry);
|
|
4715
|
+
discoveryErrors.push(...handlerErrors);
|
|
4716
|
+
for (const { context, error } of handlerErrors) {
|
|
4717
|
+
debug10?.("caught error while resolving %s: %O", context, error);
|
|
4062
4718
|
}
|
|
4063
4719
|
const freshServerMod = await rscEnv.runner.import(
|
|
4064
4720
|
"@rangojs/router/server"
|
|
@@ -4069,16 +4725,20 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4069
4725
|
registry = freshRegistry;
|
|
4070
4726
|
}
|
|
4071
4727
|
}
|
|
4072
|
-
} catch {
|
|
4728
|
+
} catch (error) {
|
|
4729
|
+
discoveryErrors.push({ context: "host-router discovery", error });
|
|
4073
4730
|
}
|
|
4074
4731
|
if (!registry || registry.size === 0) {
|
|
4075
|
-
throw new
|
|
4076
|
-
`[rsc-router] No routers found in registry after importing ${state.resolvedEntryPath}`
|
|
4077
|
-
);
|
|
4732
|
+
throw new DiscoveryError(state.resolvedEntryPath, discoveryErrors);
|
|
4078
4733
|
}
|
|
4079
4734
|
}
|
|
4080
|
-
const buildMod = await
|
|
4735
|
+
const buildMod = await timed(
|
|
4736
|
+
debug10,
|
|
4737
|
+
"inner: import @rangojs/router/build",
|
|
4738
|
+
() => rscEnv.runner.import("@rangojs/router/build")
|
|
4739
|
+
);
|
|
4081
4740
|
const generateManifestFull = buildMod.generateManifestFull;
|
|
4741
|
+
debug10?.("inner: found %d router(s) in registry", registry.size);
|
|
4082
4742
|
const nestedRouterConflict = findNestedRouterConflict(
|
|
4083
4743
|
[...registry.values()].map((router) => router.__sourceFile).filter(
|
|
4084
4744
|
(sourceFile) => typeof sourceFile === "string"
|
|
@@ -4097,6 +4757,16 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4097
4757
|
let mergedRouteTrailingSlash = {};
|
|
4098
4758
|
let routerMountIndex = 0;
|
|
4099
4759
|
const allManifests = [];
|
|
4760
|
+
const clientChunkCtx = state.opts?.clientChunkCtx;
|
|
4761
|
+
const collectClientFallbackRef = clientChunkCtx ? (refKey) => clientChunkCtx.fallbackRefs.add(
|
|
4762
|
+
computeProductionHash(state.projectRoot, refKey)
|
|
4763
|
+
) : void 0;
|
|
4764
|
+
const collectFromBoundaryNode = (node) => {
|
|
4765
|
+
if (collectClientFallbackRef && buildMod.collectFallbackClientRefs) {
|
|
4766
|
+
buildMod.collectFallbackClientRefs(node, collectClientFallbackRef);
|
|
4767
|
+
}
|
|
4768
|
+
};
|
|
4769
|
+
const manifestGenStart = debug10 ? performance.now() : 0;
|
|
4100
4770
|
for (const [id, router] of registry) {
|
|
4101
4771
|
if (!router.urlpatterns || !generateManifestFull) {
|
|
4102
4772
|
continue;
|
|
@@ -4104,10 +4774,18 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4104
4774
|
const manifest = generateManifestFull(
|
|
4105
4775
|
router.urlpatterns,
|
|
4106
4776
|
routerMountIndex,
|
|
4107
|
-
|
|
4777
|
+
{
|
|
4778
|
+
...router.__basename ? { urlPrefix: router.__basename } : {},
|
|
4779
|
+
...collectClientFallbackRef ? { collectClientFallbackRef } : {}
|
|
4780
|
+
}
|
|
4108
4781
|
);
|
|
4109
4782
|
routerMountIndex++;
|
|
4110
4783
|
allManifests.push({ id, manifest });
|
|
4784
|
+
if (collectClientFallbackRef) {
|
|
4785
|
+
collectFromBoundaryNode(router.__defaultErrorBoundary);
|
|
4786
|
+
collectFromBoundaryNode(router.__defaultNotFoundBoundary);
|
|
4787
|
+
collectFromBoundaryNode(router.__notFound);
|
|
4788
|
+
}
|
|
4111
4789
|
const routeCount = Object.keys(manifest.routeManifest).length;
|
|
4112
4790
|
const staticRoutes = Object.values(manifest.routeManifest).filter(
|
|
4113
4791
|
(p) => !p.includes(":") && !p.includes("*")
|
|
@@ -4158,7 +4836,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4158
4836
|
);
|
|
4159
4837
|
newPerRouterPrecomputedMap.set(id, routerPrecomputed);
|
|
4160
4838
|
console.log(
|
|
4161
|
-
`[
|
|
4839
|
+
`[rango] Router "${id}" -> ${routeCount} routes (${staticRoutes} static, ${dynamicRoutes} dynamic)`
|
|
4162
4840
|
);
|
|
4163
4841
|
}
|
|
4164
4842
|
if (registry.size > 1) {
|
|
@@ -4167,11 +4845,17 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4167
4845
|
);
|
|
4168
4846
|
if (autoIds.length > 1) {
|
|
4169
4847
|
console.warn(
|
|
4170
|
-
`[
|
|
4848
|
+
`[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", ... })`
|
|
4171
4849
|
);
|
|
4172
4850
|
}
|
|
4173
4851
|
}
|
|
4852
|
+
debug10?.(
|
|
4853
|
+
"inner: generated manifests for %d router(s) (%sms)",
|
|
4854
|
+
allManifests.length,
|
|
4855
|
+
(performance.now() - manifestGenStart).toFixed(1)
|
|
4856
|
+
);
|
|
4174
4857
|
let newMergedRouteTrie = null;
|
|
4858
|
+
const trieStart = debug10 ? performance.now() : 0;
|
|
4175
4859
|
if (Object.keys(newMergedRouteManifest).length > 0) {
|
|
4176
4860
|
const buildRouteTrie = buildMod.buildRouteTrie;
|
|
4177
4861
|
if (buildRouteTrie && mergedRouteAncestry) {
|
|
@@ -4206,10 +4890,10 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4206
4890
|
newMergedRouteManifest,
|
|
4207
4891
|
mergedRouteAncestry,
|
|
4208
4892
|
routeToStaticPrefix,
|
|
4209
|
-
|
|
4210
|
-
prerenderRouteNames
|
|
4211
|
-
passthroughRouteNames
|
|
4212
|
-
|
|
4893
|
+
mergedRouteTrailingSlash,
|
|
4894
|
+
prerenderRouteNames,
|
|
4895
|
+
passthroughRouteNames,
|
|
4896
|
+
mergedResponseTypeRoutes
|
|
4213
4897
|
);
|
|
4214
4898
|
for (const { id, manifest } of allManifests) {
|
|
4215
4899
|
if (!manifest._routeAncestry || Object.keys(manifest._routeAncestry).length === 0)
|
|
@@ -4225,15 +4909,19 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4225
4909
|
manifest.routeManifest,
|
|
4226
4910
|
manifest._routeAncestry,
|
|
4227
4911
|
perRouterStaticPrefix,
|
|
4228
|
-
manifest.routeTrailingSlash
|
|
4229
|
-
perRouterPrerenderNames
|
|
4230
|
-
perRouterPassthroughNames
|
|
4231
|
-
manifest.responseTypeRoutes
|
|
4912
|
+
manifest.routeTrailingSlash,
|
|
4913
|
+
perRouterPrerenderNames,
|
|
4914
|
+
perRouterPassthroughNames,
|
|
4915
|
+
manifest.responseTypeRoutes
|
|
4232
4916
|
);
|
|
4233
4917
|
newPerRouterTrieMap.set(id, perRouterTrie);
|
|
4234
4918
|
}
|
|
4235
4919
|
}
|
|
4236
4920
|
}
|
|
4921
|
+
debug10?.(
|
|
4922
|
+
"inner: trie build done (%sms)",
|
|
4923
|
+
(performance.now() - trieStart).toFixed(1)
|
|
4924
|
+
);
|
|
4237
4925
|
state.mergedRouteManifest = newMergedRouteManifest;
|
|
4238
4926
|
state.mergedPrecomputedEntries = newMergedPrecomputedEntries;
|
|
4239
4927
|
state.perRouterManifests = newPerRouterManifests;
|
|
@@ -4247,7 +4935,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4247
4935
|
}
|
|
4248
4936
|
|
|
4249
4937
|
// src/vite/discovery/route-types-writer.ts
|
|
4250
|
-
import { dirname as dirname3,
|
|
4938
|
+
import { dirname as dirname3, join as join2, resolve as resolve6 } from "node:path";
|
|
4251
4939
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, unlinkSync as unlinkSync2 } from "node:fs";
|
|
4252
4940
|
function filterUserNamedRoutes(manifest) {
|
|
4253
4941
|
const filtered = {};
|
|
@@ -4258,39 +4946,20 @@ function filterUserNamedRoutes(manifest) {
|
|
|
4258
4946
|
}
|
|
4259
4947
|
return filtered;
|
|
4260
4948
|
}
|
|
4949
|
+
function writeGenFileIfChanged(state, outPath, source, opts) {
|
|
4950
|
+
const existing = existsSync5(outPath) ? readFileSync4(outPath, "utf-8") : null;
|
|
4951
|
+
if (existing === source) return;
|
|
4952
|
+
markSelfGenWrite(state, outPath, source);
|
|
4953
|
+
writeFileSync3(outPath, source);
|
|
4954
|
+
if (opts?.log) console.log(`[rango] Generated route types -> ${outPath}`);
|
|
4955
|
+
}
|
|
4261
4956
|
function writeCombinedRouteTypesWithTracking(state, opts) {
|
|
4262
4957
|
const routerFiles = state.cachedRouterFiles ?? findRouterFiles(state.projectRoot, state.scanFilter);
|
|
4263
4958
|
state.cachedRouterFiles = routerFiles;
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
/\.(tsx?|jsx?)$/,
|
|
4269
|
-
""
|
|
4270
|
-
);
|
|
4271
|
-
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4272
|
-
try {
|
|
4273
|
-
preContent.set(outPath, readFileSync4(outPath, "utf-8"));
|
|
4274
|
-
} catch {
|
|
4275
|
-
}
|
|
4276
|
-
}
|
|
4277
|
-
writeCombinedRouteTypes(state.projectRoot, routerFiles, opts);
|
|
4278
|
-
for (const routerFilePath of routerFiles) {
|
|
4279
|
-
const routerDir = dirname3(routerFilePath);
|
|
4280
|
-
const routerBasename = basename(routerFilePath).replace(
|
|
4281
|
-
/\.(tsx?|jsx?)$/,
|
|
4282
|
-
""
|
|
4283
|
-
);
|
|
4284
|
-
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4285
|
-
if (!existsSync5(outPath)) continue;
|
|
4286
|
-
try {
|
|
4287
|
-
const content = readFileSync4(outPath, "utf-8");
|
|
4288
|
-
if (content !== preContent.get(outPath)) {
|
|
4289
|
-
markSelfGenWrite(state, outPath, content);
|
|
4290
|
-
}
|
|
4291
|
-
} catch {
|
|
4292
|
-
}
|
|
4293
|
-
}
|
|
4959
|
+
writeCombinedRouteTypes(state.projectRoot, routerFiles, {
|
|
4960
|
+
...opts,
|
|
4961
|
+
onWrite: (outPath, content) => markSelfGenWrite(state, outPath, content)
|
|
4962
|
+
});
|
|
4294
4963
|
}
|
|
4295
4964
|
function writeRouteTypesFiles(state) {
|
|
4296
4965
|
if (state.perRouterManifests.length === 0) return;
|
|
@@ -4302,7 +4971,7 @@ function writeRouteTypesFiles(state) {
|
|
|
4302
4971
|
if (existsSync5(oldCombinedPath)) {
|
|
4303
4972
|
unlinkSync2(oldCombinedPath);
|
|
4304
4973
|
console.log(
|
|
4305
|
-
`[
|
|
4974
|
+
`[rango] Removed stale combined route types: ${oldCombinedPath}`
|
|
4306
4975
|
);
|
|
4307
4976
|
}
|
|
4308
4977
|
} catch {
|
|
@@ -4316,39 +4985,23 @@ function writeRouteTypesFiles(state) {
|
|
|
4316
4985
|
if (!sourceFile) continue;
|
|
4317
4986
|
if (sourceFile.includes("node_modules")) {
|
|
4318
4987
|
throw new Error(
|
|
4319
|
-
`[
|
|
4988
|
+
`[rango] Router "${id}" has sourceFile inside node_modules: ${sourceFile}
|
|
4320
4989
|
This means createRouter() stack trace parsing matched a Vite internal frame.
|
|
4321
4990
|
Set an explicit \`id\` on createRouter() or check the call site.`
|
|
4322
4991
|
);
|
|
4323
4992
|
}
|
|
4324
|
-
const
|
|
4325
|
-
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
4326
|
-
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4993
|
+
const outPath = genFileTsPath(sourceFile);
|
|
4327
4994
|
const userRoutes = filterUserNamedRoutes(routeManifest);
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
for (const name of Object.keys(userRoutes)) {
|
|
4334
|
-
const schema = staticParsed.searchSchemas[name];
|
|
4335
|
-
if (schema) filtered[name] = schema;
|
|
4336
|
-
}
|
|
4337
|
-
if (Object.keys(filtered).length > 0) {
|
|
4338
|
-
effectiveSearchSchemas = filtered;
|
|
4339
|
-
}
|
|
4340
|
-
}
|
|
4341
|
-
}
|
|
4995
|
+
const effectiveSearchSchemas = resolveSearchSchemas(
|
|
4996
|
+
Object.keys(userRoutes),
|
|
4997
|
+
routeSearchSchemas,
|
|
4998
|
+
sourceFile
|
|
4999
|
+
);
|
|
4342
5000
|
const source = generateRouteTypesSource(
|
|
4343
5001
|
userRoutes,
|
|
4344
5002
|
effectiveSearchSchemas && Object.keys(effectiveSearchSchemas).length > 0 ? effectiveSearchSchemas : void 0
|
|
4345
5003
|
);
|
|
4346
|
-
|
|
4347
|
-
if (existing !== source) {
|
|
4348
|
-
markSelfGenWrite(state, outPath, source);
|
|
4349
|
-
writeFileSync3(outPath, source);
|
|
4350
|
-
console.log(`[rsc-router] Generated route types -> ${outPath}`);
|
|
4351
|
-
}
|
|
5004
|
+
writeGenFileIfChanged(state, outPath, source, { log: true });
|
|
4352
5005
|
}
|
|
4353
5006
|
}
|
|
4354
5007
|
function supplementGenFilesWithRuntimeRoutes(state) {
|
|
@@ -4386,23 +5039,17 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
4386
5039
|
}
|
|
4387
5040
|
}
|
|
4388
5041
|
}
|
|
4389
|
-
const
|
|
4390
|
-
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
4391
|
-
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
5042
|
+
const outPath = genFileTsPath(sourceFile);
|
|
4392
5043
|
const source = generateRouteTypesSource(
|
|
4393
5044
|
mergedRoutes,
|
|
4394
5045
|
Object.keys(mergedSearchSchemas).length > 0 ? mergedSearchSchemas : void 0
|
|
4395
5046
|
);
|
|
4396
|
-
|
|
4397
|
-
if (existing !== source) {
|
|
4398
|
-
markSelfGenWrite(state, outPath, source);
|
|
4399
|
-
writeFileSync3(outPath, source);
|
|
4400
|
-
}
|
|
5047
|
+
writeGenFileIfChanged(state, outPath, source);
|
|
4401
5048
|
}
|
|
4402
5049
|
}
|
|
4403
5050
|
|
|
4404
5051
|
// src/vite/discovery/virtual-module-codegen.ts
|
|
4405
|
-
import { dirname as dirname4, basename
|
|
5052
|
+
import { dirname as dirname4, basename, join as join3 } from "node:path";
|
|
4406
5053
|
function generateRoutesManifestModule(state) {
|
|
4407
5054
|
const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
|
|
4408
5055
|
if (hasManifest) {
|
|
@@ -4413,7 +5060,7 @@ function generateRoutesManifestModule(state) {
|
|
|
4413
5060
|
for (const entry of state.perRouterManifests) {
|
|
4414
5061
|
if (entry.sourceFile) {
|
|
4415
5062
|
const routerDir = dirname4(entry.sourceFile);
|
|
4416
|
-
const routerBasename =
|
|
5063
|
+
const routerBasename = basename(entry.sourceFile).replace(
|
|
4417
5064
|
/\.(tsx?|jsx?)$/,
|
|
4418
5065
|
""
|
|
4419
5066
|
);
|
|
@@ -4434,7 +5081,7 @@ function generateRoutesManifestModule(state) {
|
|
|
4434
5081
|
}
|
|
4435
5082
|
}
|
|
4436
5083
|
const lines = [
|
|
4437
|
-
`import { setCachedManifest,
|
|
5084
|
+
`import { setCachedManifest, setRouterManifest, registerRouterManifestLoader, clearAllRouterData } from "@rangojs/router/server";`,
|
|
4438
5085
|
...genFileImports,
|
|
4439
5086
|
// Clear stale per-router cached data (manifest, trie, precomputed entries)
|
|
4440
5087
|
// before re-populating. In Cloudflare dev mode, program reloads re-evaluate
|
|
@@ -4470,18 +5117,6 @@ function generateRoutesManifestModule(state) {
|
|
|
4470
5117
|
);
|
|
4471
5118
|
}
|
|
4472
5119
|
}
|
|
4473
|
-
if (state.isBuildMode) {
|
|
4474
|
-
if (state.mergedPrecomputedEntries && state.mergedPrecomputedEntries.length > 0) {
|
|
4475
|
-
lines.push(
|
|
4476
|
-
`setPrecomputedEntries(${jsonParseExpression(state.mergedPrecomputedEntries)});`
|
|
4477
|
-
);
|
|
4478
|
-
}
|
|
4479
|
-
if (state.mergedRouteTrie) {
|
|
4480
|
-
lines.push(
|
|
4481
|
-
`setRouteTrie(${jsonParseExpression(state.mergedRouteTrie)});`
|
|
4482
|
-
);
|
|
4483
|
-
}
|
|
4484
|
-
}
|
|
4485
5120
|
for (const routerId of state.perRouterManifestDataMap.keys()) {
|
|
4486
5121
|
lines.push(
|
|
4487
5122
|
`registerRouterManifestLoader(${JSON.stringify(routerId)}, () => import(${JSON.stringify(VIRTUAL_ROUTES_MANIFEST_ID + "/" + routerId)}));`
|
|
@@ -4510,7 +5145,7 @@ function generatePerRouterModule(state, routerId) {
|
|
|
4510
5145
|
const lines = [];
|
|
4511
5146
|
if (routerEntry?.sourceFile) {
|
|
4512
5147
|
const routerDir = dirname4(routerEntry.sourceFile);
|
|
4513
|
-
const routerBasename =
|
|
5148
|
+
const routerBasename = basename(routerEntry.sourceFile).replace(
|
|
4514
5149
|
/\.(tsx?|jsx?)$/,
|
|
4515
5150
|
""
|
|
4516
5151
|
);
|
|
@@ -4581,12 +5216,12 @@ function postprocessBundle(state) {
|
|
|
4581
5216
|
writeFileSync4(chunkPath, result.code);
|
|
4582
5217
|
const savedKB = (result.savedBytes / 1024).toFixed(1);
|
|
4583
5218
|
console.log(
|
|
4584
|
-
`[
|
|
5219
|
+
`[rango] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
|
|
4585
5220
|
);
|
|
4586
5221
|
}
|
|
4587
5222
|
} catch (replaceErr) {
|
|
4588
5223
|
console.warn(
|
|
4589
|
-
`[
|
|
5224
|
+
`[rango] Failed to evict ${target.label}: ${replaceErr.message}`
|
|
4590
5225
|
);
|
|
4591
5226
|
}
|
|
4592
5227
|
}
|
|
@@ -4624,11 +5259,11 @@ function postprocessBundle(state) {
|
|
|
4624
5259
|
writeFileSync4(rscEntryPath, injection + rscCode);
|
|
4625
5260
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
4626
5261
|
console.log(
|
|
4627
|
-
`[
|
|
5262
|
+
`[rango] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.prerenderManifestEntries).length} entries)`
|
|
4628
5263
|
);
|
|
4629
5264
|
} catch (err) {
|
|
4630
5265
|
throw new Error(
|
|
4631
|
-
`[
|
|
5266
|
+
`[rango] Failed to write prerender assets: ${err.message}`
|
|
4632
5267
|
);
|
|
4633
5268
|
}
|
|
4634
5269
|
}
|
|
@@ -4662,28 +5297,180 @@ function postprocessBundle(state) {
|
|
|
4662
5297
|
writeFileSync4(rscEntryPath, injection + rscCode);
|
|
4663
5298
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
4664
5299
|
console.log(
|
|
4665
|
-
`[
|
|
5300
|
+
`[rango] Wrote static assets (${totalKB} KB total, ${Object.keys(state.staticManifestEntries).length} entries)`
|
|
4666
5301
|
);
|
|
4667
5302
|
} catch (err) {
|
|
4668
5303
|
throw new Error(
|
|
4669
|
-
`[
|
|
5304
|
+
`[rango] Failed to write static assets: ${err.message}`
|
|
4670
5305
|
);
|
|
4671
5306
|
}
|
|
4672
5307
|
}
|
|
4673
5308
|
}
|
|
4674
5309
|
}
|
|
4675
5310
|
|
|
5311
|
+
// src/vite/discovery/gate-state.ts
|
|
5312
|
+
function createDiscoveryGate(s, debug11) {
|
|
5313
|
+
let gatePending = false;
|
|
5314
|
+
let gateResolver = () => {
|
|
5315
|
+
};
|
|
5316
|
+
let inProgress = false;
|
|
5317
|
+
let queued = false;
|
|
5318
|
+
let pendingEvents = false;
|
|
5319
|
+
const beginGate = () => {
|
|
5320
|
+
if (gatePending) return;
|
|
5321
|
+
s.discoveryDone = new Promise((resolve10) => {
|
|
5322
|
+
gateResolver = resolve10;
|
|
5323
|
+
});
|
|
5324
|
+
gatePending = true;
|
|
5325
|
+
};
|
|
5326
|
+
const resolveGate = () => {
|
|
5327
|
+
if (!gatePending) return;
|
|
5328
|
+
if (inProgress || queued || pendingEvents) {
|
|
5329
|
+
debug11?.(
|
|
5330
|
+
"hmr: resolveGate deferred \u2014 work in flight (inProgress=%s queued=%s pendingEvents=%s)",
|
|
5331
|
+
inProgress,
|
|
5332
|
+
queued,
|
|
5333
|
+
pendingEvents
|
|
5334
|
+
);
|
|
5335
|
+
return;
|
|
5336
|
+
}
|
|
5337
|
+
gatePending = false;
|
|
5338
|
+
debug11?.("hmr: discoveryDone resolved");
|
|
5339
|
+
gateResolver();
|
|
5340
|
+
};
|
|
5341
|
+
const noteRouteEvent = () => {
|
|
5342
|
+
pendingEvents = true;
|
|
5343
|
+
beginGate();
|
|
5344
|
+
};
|
|
5345
|
+
const runRefreshCycle = async (work) => {
|
|
5346
|
+
if (inProgress) {
|
|
5347
|
+
queued = true;
|
|
5348
|
+
debug11?.("hmr: rediscovery in flight \u2014 queued for a follow-up cycle");
|
|
5349
|
+
return;
|
|
5350
|
+
}
|
|
5351
|
+
pendingEvents = false;
|
|
5352
|
+
inProgress = true;
|
|
5353
|
+
try {
|
|
5354
|
+
await work();
|
|
5355
|
+
} finally {
|
|
5356
|
+
inProgress = false;
|
|
5357
|
+
if (queued) {
|
|
5358
|
+
queued = false;
|
|
5359
|
+
debug11?.("hmr: consuming queued rediscovery");
|
|
5360
|
+
runRefreshCycle(work).catch((err) => {
|
|
5361
|
+
debug11?.(
|
|
5362
|
+
"hmr: queued cycle rejected \u2014 releasing gate (%s)",
|
|
5363
|
+
err instanceof Error ? err.message : String(err)
|
|
5364
|
+
);
|
|
5365
|
+
resolveGate();
|
|
5366
|
+
});
|
|
5367
|
+
} else if (pendingEvents) {
|
|
5368
|
+
debug11?.(
|
|
5369
|
+
"hmr: holding gate for pending events (debounce not yet fired)"
|
|
5370
|
+
);
|
|
5371
|
+
} else {
|
|
5372
|
+
resolveGate();
|
|
5373
|
+
}
|
|
5374
|
+
}
|
|
5375
|
+
};
|
|
5376
|
+
return {
|
|
5377
|
+
beginGate,
|
|
5378
|
+
resolveGate,
|
|
5379
|
+
noteRouteEvent,
|
|
5380
|
+
runRefreshCycle,
|
|
5381
|
+
state: () => ({ gatePending, inProgress, queued, pendingEvents })
|
|
5382
|
+
};
|
|
5383
|
+
}
|
|
5384
|
+
|
|
5385
|
+
// src/vite/utils/forward-user-plugins.ts
|
|
5386
|
+
function isDenied(name) {
|
|
5387
|
+
return name.startsWith("vite:") || name === "rsc" || name.startsWith("rsc:") || name.startsWith("@rangojs/router") || name.startsWith("@cloudflare/vite-plugin") || name.startsWith("vite-plugin-cloudflare");
|
|
5388
|
+
}
|
|
5389
|
+
function hasResolutionHooks(p) {
|
|
5390
|
+
return Boolean(p.resolveId || p.load);
|
|
5391
|
+
}
|
|
5392
|
+
function stripToResolutionHooks(p) {
|
|
5393
|
+
const stripped = { name: p.name };
|
|
5394
|
+
if (p.enforce) stripped.enforce = p.enforce;
|
|
5395
|
+
if (p.applyToEnvironment)
|
|
5396
|
+
stripped.applyToEnvironment = p.applyToEnvironment;
|
|
5397
|
+
if (p.resolveId) stripped.resolveId = p.resolveId;
|
|
5398
|
+
if (p.load) stripped.load = p.load;
|
|
5399
|
+
return stripped;
|
|
5400
|
+
}
|
|
5401
|
+
function selectForwardableResolvePlugins(plugins) {
|
|
5402
|
+
if (!plugins) return [];
|
|
5403
|
+
const forwarded = [];
|
|
5404
|
+
for (const p of plugins) {
|
|
5405
|
+
const name = p?.name;
|
|
5406
|
+
if (!name || isDenied(name)) continue;
|
|
5407
|
+
if (!hasResolutionHooks(p)) continue;
|
|
5408
|
+
forwarded.push(stripToResolutionHooks(p));
|
|
5409
|
+
}
|
|
5410
|
+
return forwarded;
|
|
5411
|
+
}
|
|
5412
|
+
function pickForwardedRunnerConfig(config) {
|
|
5413
|
+
const r = config.resolve ?? {};
|
|
5414
|
+
const resolve10 = {};
|
|
5415
|
+
if (r.alias !== void 0) resolve10.alias = r.alias;
|
|
5416
|
+
if (r.dedupe !== void 0) resolve10.dedupe = r.dedupe;
|
|
5417
|
+
if (r.conditions !== void 0) resolve10.conditions = r.conditions;
|
|
5418
|
+
if (r.mainFields !== void 0) resolve10.mainFields = r.mainFields;
|
|
5419
|
+
if (r.extensions !== void 0) resolve10.extensions = r.extensions;
|
|
5420
|
+
if (r.preserveSymlinks !== void 0)
|
|
5421
|
+
resolve10.preserveSymlinks = r.preserveSymlinks;
|
|
5422
|
+
if (r.tsconfigPaths !== void 0) resolve10.tsconfigPaths = r.tsconfigPaths;
|
|
5423
|
+
const userOxc = config.oxc;
|
|
5424
|
+
const userJsx = userOxc && typeof userOxc === "object" && typeof userOxc.jsx === "object" && userOxc.jsx !== null ? userOxc.jsx : {};
|
|
5425
|
+
const oxc = userOxc && typeof userOxc === "object" ? {
|
|
5426
|
+
...userOxc,
|
|
5427
|
+
jsx: { ...userJsx, runtime: "automatic", importSource: "react" }
|
|
5428
|
+
} : { jsx: { runtime: "automatic", importSource: "react" } };
|
|
5429
|
+
return {
|
|
5430
|
+
resolve: resolve10,
|
|
5431
|
+
define: config.define,
|
|
5432
|
+
oxc
|
|
5433
|
+
};
|
|
5434
|
+
}
|
|
5435
|
+
|
|
4676
5436
|
// src/vite/router-discovery.ts
|
|
5437
|
+
var debugDiscovery = createRangoDebugger(NS.discovery);
|
|
5438
|
+
var debugRoutes = createRangoDebugger(NS.routes);
|
|
5439
|
+
var debugBuild = createRangoDebugger(NS.build);
|
|
5440
|
+
var debugDev = createRangoDebugger(NS.dev);
|
|
5441
|
+
var loaderHookRegistered = false;
|
|
5442
|
+
function ensureCloudflareProtocolLoaderRegistered() {
|
|
5443
|
+
if (loaderHookRegistered) return;
|
|
5444
|
+
loaderHookRegistered = true;
|
|
5445
|
+
try {
|
|
5446
|
+
register(
|
|
5447
|
+
new URL("./plugins/cloudflare-protocol-loader-hook.mjs", import.meta.url)
|
|
5448
|
+
);
|
|
5449
|
+
} catch (err) {
|
|
5450
|
+
console.warn(
|
|
5451
|
+
`[rango] Could not register Node ESM loader hook for cloudflare:* imports (${err?.message ?? err}). Falling back to Vite transform only.`
|
|
5452
|
+
);
|
|
5453
|
+
}
|
|
5454
|
+
}
|
|
4677
5455
|
async function createTempRscServer(state, options = {}) {
|
|
5456
|
+
ensureCloudflareProtocolLoaderRegistered();
|
|
4678
5457
|
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
5458
|
+
const runnerConfig = state.userRunnerConfig;
|
|
5459
|
+
const resolveConfig = runnerConfig?.resolve ?? {
|
|
5460
|
+
alias: state.userResolveAlias
|
|
5461
|
+
};
|
|
5462
|
+
const oxcConfig = runnerConfig?.oxc ?? {
|
|
5463
|
+
jsx: { runtime: "automatic", importSource: "react" }
|
|
5464
|
+
};
|
|
4679
5465
|
return createViteServer({
|
|
4680
5466
|
root: state.projectRoot,
|
|
4681
5467
|
configFile: false,
|
|
4682
5468
|
server: { middlewareMode: true },
|
|
4683
5469
|
appType: "custom",
|
|
4684
5470
|
logLevel: "silent",
|
|
4685
|
-
resolve:
|
|
4686
|
-
|
|
5471
|
+
resolve: resolveConfig,
|
|
5472
|
+
...runnerConfig?.define ? { define: runnerConfig.define } : {},
|
|
5473
|
+
oxc: oxcConfig,
|
|
4687
5474
|
...options.cacheDir && { cacheDir: options.cacheDir },
|
|
4688
5475
|
plugins: [
|
|
4689
5476
|
rsc({
|
|
@@ -4697,10 +5484,15 @@ async function createTempRscServer(state, options = {}) {
|
|
|
4697
5484
|
...options.forceBuild ? [hashClientRefs(state.projectRoot)] : [],
|
|
4698
5485
|
createVersionPlugin(),
|
|
4699
5486
|
createVirtualStubPlugin(),
|
|
5487
|
+
createCloudflareProtocolStubPlugin(),
|
|
4700
5488
|
// Dev prerender must use dev-mode IDs (path-based) to match the workerd
|
|
4701
5489
|
// runtime. forceBuild produces hashed IDs for production bundle consistency.
|
|
4702
5490
|
exposeInternalIds(options.forceBuild ? { forceBuild: true } : void 0),
|
|
4703
|
-
exposeRouterId()
|
|
5491
|
+
exposeRouterId(),
|
|
5492
|
+
// Forwarded user resolution plugins (e.g. vite-tsconfig-paths). Stripped
|
|
5493
|
+
// to resolveId/load and placed last so framework resolution runs first;
|
|
5494
|
+
// Vite re-sorts by `enforce`, so `enforce: "pre"` resolvers still lead.
|
|
5495
|
+
...state.userResolvePlugins
|
|
4704
5496
|
]
|
|
4705
5497
|
});
|
|
4706
5498
|
}
|
|
@@ -4709,11 +5501,11 @@ async function resolveBuildEnv(option, factoryCtx) {
|
|
|
4709
5501
|
if (option === "auto") {
|
|
4710
5502
|
if (factoryCtx.preset !== "cloudflare") {
|
|
4711
5503
|
throw new Error(
|
|
4712
|
-
'[
|
|
5504
|
+
'[rango] buildEnv: "auto" is only supported with preset: "cloudflare". Use a factory function or plain object for other presets.'
|
|
4713
5505
|
);
|
|
4714
5506
|
}
|
|
4715
5507
|
try {
|
|
4716
|
-
const userRequire =
|
|
5508
|
+
const userRequire = createRequire2(
|
|
4717
5509
|
resolve8(factoryCtx.root, "package.json")
|
|
4718
5510
|
);
|
|
4719
5511
|
const wranglerPath = userRequire.resolve("wrangler");
|
|
@@ -4725,7 +5517,7 @@ async function resolveBuildEnv(option, factoryCtx) {
|
|
|
4725
5517
|
};
|
|
4726
5518
|
} catch (err) {
|
|
4727
5519
|
throw new Error(
|
|
4728
|
-
`[
|
|
5520
|
+
`[rango] buildEnv: "auto" requires wrangler to be installed.
|
|
4729
5521
|
Install it with: pnpm add -D wrangler
|
|
4730
5522
|
${err.message}`
|
|
4731
5523
|
);
|
|
@@ -4748,6 +5540,7 @@ async function acquireBuildEnv(s, command, mode) {
|
|
|
4748
5540
|
if (!result) return false;
|
|
4749
5541
|
s.resolvedBuildEnv = result.env;
|
|
4750
5542
|
s.buildEnvDispose = result.dispose ?? null;
|
|
5543
|
+
globalThis[BUILD_ENV_GLOBAL_KEY] = result.env;
|
|
4751
5544
|
return true;
|
|
4752
5545
|
}
|
|
4753
5546
|
async function releaseBuildEnv(s) {
|
|
@@ -4755,11 +5548,12 @@ async function releaseBuildEnv(s) {
|
|
|
4755
5548
|
try {
|
|
4756
5549
|
await s.buildEnvDispose();
|
|
4757
5550
|
} catch (err) {
|
|
4758
|
-
console.warn(`[
|
|
5551
|
+
console.warn(`[rango] buildEnv dispose failed: ${err.message}`);
|
|
4759
5552
|
}
|
|
4760
5553
|
s.buildEnvDispose = null;
|
|
4761
5554
|
}
|
|
4762
5555
|
s.resolvedBuildEnv = void 0;
|
|
5556
|
+
delete globalThis[BUILD_ENV_GLOBAL_KEY];
|
|
4763
5557
|
}
|
|
4764
5558
|
function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
4765
5559
|
const s = createDiscoveryState(entryPath, opts);
|
|
@@ -4781,17 +5575,16 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4781
5575
|
viteCommand = config.command;
|
|
4782
5576
|
viteMode = config.mode;
|
|
4783
5577
|
s.userResolveAlias = config.resolve.alias;
|
|
5578
|
+
s.userRunnerConfig = pickForwardedRunnerConfig(config);
|
|
5579
|
+
s.userResolvePlugins = selectForwardableResolvePlugins(
|
|
5580
|
+
config.plugins
|
|
5581
|
+
);
|
|
4784
5582
|
if (!s.resolvedEntryPath && opts?.routerPathRef?.path) {
|
|
4785
5583
|
s.resolvedEntryPath = opts.routerPathRef.path;
|
|
4786
5584
|
}
|
|
4787
5585
|
if (!s.resolvedEntryPath) {
|
|
4788
|
-
const
|
|
4789
|
-
|
|
4790
|
-
if (typeof entries === "string") {
|
|
4791
|
-
s.resolvedEntryPath = entries;
|
|
4792
|
-
} else if (Array.isArray(entries) && entries.length > 0) {
|
|
4793
|
-
s.resolvedEntryPath = entries[0];
|
|
4794
|
-
}
|
|
5586
|
+
const entry = resolveRscEntryFromConfig(config);
|
|
5587
|
+
if (entry) s.resolvedEntryPath = entry;
|
|
4795
5588
|
}
|
|
4796
5589
|
if (opts?.staticRouteTypesGeneration !== false) {
|
|
4797
5590
|
s.cachedRouterFiles = findRouterFiles(s.projectRoot, s.scanFilter);
|
|
@@ -4815,6 +5608,9 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4815
5608
|
const discoveryPromise = new Promise((resolve10) => {
|
|
4816
5609
|
resolveDiscovery = resolve10;
|
|
4817
5610
|
});
|
|
5611
|
+
const gate = createDiscoveryGate(s, debugDiscovery);
|
|
5612
|
+
const beginDiscoveryGate = gate.beginGate;
|
|
5613
|
+
const resolveDiscoveryGate = gate.resolveGate;
|
|
4818
5614
|
const getDevServerOrigin = () => server.resolvedUrls?.local?.[0]?.replace(/\/$/, "") || `http://localhost:${server.config.server.port || 5173}`;
|
|
4819
5615
|
let prerenderTempServer = null;
|
|
4820
5616
|
let prerenderNodeRegistry = null;
|
|
@@ -4827,74 +5623,241 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4827
5623
|
releaseBuildEnv(s).catch(() => {
|
|
4828
5624
|
});
|
|
4829
5625
|
});
|
|
5626
|
+
async function importEntryAndRegistry(tempRscEnv) {
|
|
5627
|
+
const flagAlreadySet = !!globalThis.__rscRouterDiscoveryActive;
|
|
5628
|
+
if (!flagAlreadySet) {
|
|
5629
|
+
globalThis.__rscRouterDiscoveryActive = true;
|
|
5630
|
+
}
|
|
5631
|
+
try {
|
|
5632
|
+
debugDiscovery?.(
|
|
5633
|
+
"importEntryAndRegistry: importing entry (flag=%s)",
|
|
5634
|
+
globalThis.__rscRouterDiscoveryActive ?? false
|
|
5635
|
+
);
|
|
5636
|
+
await tempRscEnv.runner.import(s.resolvedEntryPath);
|
|
5637
|
+
debugDiscovery?.(
|
|
5638
|
+
"importEntryAndRegistry: entry import OK, fetching RouterRegistry"
|
|
5639
|
+
);
|
|
5640
|
+
const serverMod = await tempRscEnv.runner.import(
|
|
5641
|
+
"@rangojs/router/server"
|
|
5642
|
+
);
|
|
5643
|
+
prerenderNodeRegistry = serverMod.RouterRegistry;
|
|
5644
|
+
debugDiscovery?.(
|
|
5645
|
+
"importEntryAndRegistry: registry size=%d",
|
|
5646
|
+
prerenderNodeRegistry?.size ?? 0
|
|
5647
|
+
);
|
|
5648
|
+
} finally {
|
|
5649
|
+
if (!flagAlreadySet) {
|
|
5650
|
+
delete globalThis.__rscRouterDiscoveryActive;
|
|
5651
|
+
debugDiscovery?.(
|
|
5652
|
+
"importEntryAndRegistry: cleared __rscRouterDiscoveryActive"
|
|
5653
|
+
);
|
|
5654
|
+
}
|
|
5655
|
+
}
|
|
5656
|
+
}
|
|
4830
5657
|
async function getOrCreateTempServer() {
|
|
4831
|
-
if (
|
|
4832
|
-
|
|
5658
|
+
if (prerenderTempServer) {
|
|
5659
|
+
const existingEnv = prerenderTempServer.environments?.rsc;
|
|
5660
|
+
if (existingEnv?.runner) {
|
|
5661
|
+
if (prerenderNodeRegistry) {
|
|
5662
|
+
debugDiscovery?.(
|
|
5663
|
+
"getOrCreateTempServer: cached temp runner reused"
|
|
5664
|
+
);
|
|
5665
|
+
return existingEnv;
|
|
5666
|
+
}
|
|
5667
|
+
debugDiscovery?.(
|
|
5668
|
+
"getOrCreateTempServer: server alive but registry missing \u2014 re-importing"
|
|
5669
|
+
);
|
|
5670
|
+
try {
|
|
5671
|
+
await importEntryAndRegistry(existingEnv);
|
|
5672
|
+
return existingEnv;
|
|
5673
|
+
} catch (err) {
|
|
5674
|
+
debugDiscovery?.(
|
|
5675
|
+
"getOrCreateTempServer: reuse import failed (%s) \u2014 closing orphan and creating fresh",
|
|
5676
|
+
err?.message ?? String(err)
|
|
5677
|
+
);
|
|
5678
|
+
await prerenderTempServer.close().catch(() => {
|
|
5679
|
+
});
|
|
5680
|
+
prerenderTempServer = null;
|
|
5681
|
+
prerenderNodeRegistry = null;
|
|
5682
|
+
}
|
|
5683
|
+
} else {
|
|
5684
|
+
debugDiscovery?.(
|
|
5685
|
+
"getOrCreateTempServer: existing server has no rsc.runner \u2014 closing and recreating"
|
|
5686
|
+
);
|
|
5687
|
+
await prerenderTempServer.close().catch(() => {
|
|
5688
|
+
});
|
|
5689
|
+
prerenderTempServer = null;
|
|
5690
|
+
prerenderNodeRegistry = null;
|
|
5691
|
+
}
|
|
4833
5692
|
}
|
|
5693
|
+
debugDiscovery?.(
|
|
5694
|
+
"getOrCreateTempServer: creating new temp server, entry=%s",
|
|
5695
|
+
s.resolvedEntryPath ?? "(unset)"
|
|
5696
|
+
);
|
|
4834
5697
|
try {
|
|
4835
5698
|
prerenderTempServer = await createTempRscServer(s, {
|
|
4836
5699
|
cacheDir: "node_modules/.vite_prerender"
|
|
4837
5700
|
});
|
|
4838
5701
|
const tempRscEnv = prerenderTempServer.environments?.rsc;
|
|
4839
5702
|
if (tempRscEnv?.runner) {
|
|
4840
|
-
await tempRscEnv
|
|
4841
|
-
const serverMod = await tempRscEnv.runner.import(
|
|
4842
|
-
"@rangojs/router/server"
|
|
4843
|
-
);
|
|
4844
|
-
prerenderNodeRegistry = serverMod.RouterRegistry;
|
|
5703
|
+
await importEntryAndRegistry(tempRscEnv);
|
|
4845
5704
|
return tempRscEnv;
|
|
4846
5705
|
}
|
|
5706
|
+
debugDiscovery?.(
|
|
5707
|
+
"getOrCreateTempServer: tempRscEnv.runner unavailable"
|
|
5708
|
+
);
|
|
4847
5709
|
} catch (err) {
|
|
4848
|
-
|
|
4849
|
-
|
|
5710
|
+
debugDiscovery?.(
|
|
5711
|
+
"getOrCreateTempServer: FAILED message=%s",
|
|
5712
|
+
err.message
|
|
4850
5713
|
);
|
|
5714
|
+
console.warn(`[rango] Failed to create temp runner: ${err.message}`);
|
|
4851
5715
|
}
|
|
4852
5716
|
return null;
|
|
4853
5717
|
}
|
|
5718
|
+
async function clearTempRegistries(tempRscEnv) {
|
|
5719
|
+
try {
|
|
5720
|
+
const serverMod = await tempRscEnv.runner.import(
|
|
5721
|
+
"@rangojs/router/server"
|
|
5722
|
+
);
|
|
5723
|
+
if (typeof serverMod?.RouterRegistry?.clear === "function") {
|
|
5724
|
+
serverMod.RouterRegistry.clear();
|
|
5725
|
+
}
|
|
5726
|
+
if (typeof serverMod?.HostRouterRegistry?.clear === "function") {
|
|
5727
|
+
serverMod.HostRouterRegistry.clear();
|
|
5728
|
+
}
|
|
5729
|
+
debugDiscovery?.(
|
|
5730
|
+
"clearTempRegistries: cleared RouterRegistry + HostRouterRegistry"
|
|
5731
|
+
);
|
|
5732
|
+
} catch (err) {
|
|
5733
|
+
debugDiscovery?.(
|
|
5734
|
+
"clearTempRegistries: import @rangojs/router/server failed (%s)",
|
|
5735
|
+
err?.message ?? String(err)
|
|
5736
|
+
);
|
|
5737
|
+
}
|
|
5738
|
+
}
|
|
5739
|
+
async function refreshTempRscEnv() {
|
|
5740
|
+
let tempRscEnv = await getOrCreateTempServer();
|
|
5741
|
+
if (!tempRscEnv) return null;
|
|
5742
|
+
const envGraph = tempRscEnv.moduleGraph;
|
|
5743
|
+
const serverGraph = prerenderTempServer?.moduleGraph;
|
|
5744
|
+
const target = envGraph?.invalidateAll ? envGraph : serverGraph?.invalidateAll ? serverGraph : null;
|
|
5745
|
+
if (!target) {
|
|
5746
|
+
debugDiscovery?.(
|
|
5747
|
+
"refreshTempRscEnv: invalidateAll unavailable on env+server graphs, falling back to close+recreate"
|
|
5748
|
+
);
|
|
5749
|
+
if (prerenderTempServer) {
|
|
5750
|
+
await prerenderTempServer.close().catch(() => {
|
|
5751
|
+
});
|
|
5752
|
+
prerenderTempServer = null;
|
|
5753
|
+
prerenderNodeRegistry = null;
|
|
5754
|
+
}
|
|
5755
|
+
return await getOrCreateTempServer();
|
|
5756
|
+
}
|
|
5757
|
+
debugDiscovery?.(
|
|
5758
|
+
"refreshTempRscEnv: invalidating module graph (%s)",
|
|
5759
|
+
envGraph?.invalidateAll ? "env" : "server"
|
|
5760
|
+
);
|
|
5761
|
+
target.invalidateAll();
|
|
5762
|
+
prerenderNodeRegistry = null;
|
|
5763
|
+
await clearTempRegistries(tempRscEnv);
|
|
5764
|
+
await importEntryAndRegistry(tempRscEnv);
|
|
5765
|
+
return tempRscEnv;
|
|
5766
|
+
}
|
|
4854
5767
|
const discover = async () => {
|
|
5768
|
+
const discoverStart = performance.now();
|
|
4855
5769
|
const rscEnv = server.environments?.rsc;
|
|
4856
5770
|
if (!rscEnv?.runner) {
|
|
5771
|
+
debugDiscovery?.(
|
|
5772
|
+
"dev: cloudflare path start, __rscRouterDiscoveryActive=%s",
|
|
5773
|
+
globalThis.__rscRouterDiscoveryActive ?? false
|
|
5774
|
+
);
|
|
4857
5775
|
s.devServerOrigin = getDevServerOrigin();
|
|
4858
5776
|
try {
|
|
4859
|
-
await
|
|
4860
|
-
|
|
5777
|
+
await timed(
|
|
5778
|
+
debugDiscovery,
|
|
5779
|
+
"acquireBuildEnv",
|
|
5780
|
+
() => acquireBuildEnv(s, viteCommand, viteMode)
|
|
5781
|
+
);
|
|
5782
|
+
const tempRscEnv = await timed(
|
|
5783
|
+
debugDiscovery,
|
|
5784
|
+
"getOrCreateTempServer",
|
|
5785
|
+
() => getOrCreateTempServer()
|
|
5786
|
+
);
|
|
4861
5787
|
if (tempRscEnv) {
|
|
4862
|
-
await
|
|
4863
|
-
|
|
5788
|
+
await timed(
|
|
5789
|
+
debugDiscovery,
|
|
5790
|
+
"discoverRouters (cloudflare)",
|
|
5791
|
+
() => discoverRouters(s, tempRscEnv)
|
|
5792
|
+
);
|
|
5793
|
+
timedSync(
|
|
5794
|
+
debugDiscovery,
|
|
5795
|
+
"writeRouteTypesFiles",
|
|
5796
|
+
() => writeRouteTypesFiles(s)
|
|
5797
|
+
);
|
|
4864
5798
|
}
|
|
4865
5799
|
} catch (err) {
|
|
4866
5800
|
console.warn(
|
|
4867
|
-
`[
|
|
5801
|
+
`[rango] Cloudflare dev discovery failed: ${err.message}
|
|
4868
5802
|
${err.stack}`
|
|
4869
5803
|
);
|
|
4870
5804
|
}
|
|
5805
|
+
debugDiscovery?.(
|
|
5806
|
+
"dev discovery done (%sms)",
|
|
5807
|
+
(performance.now() - discoverStart).toFixed(1)
|
|
5808
|
+
);
|
|
4871
5809
|
resolveDiscovery();
|
|
4872
5810
|
return;
|
|
4873
5811
|
}
|
|
4874
5812
|
try {
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
5813
|
+
debugDiscovery?.("dev: node path start");
|
|
5814
|
+
await timed(
|
|
5815
|
+
debugDiscovery,
|
|
5816
|
+
"acquireBuildEnv",
|
|
5817
|
+
() => acquireBuildEnv(s, viteCommand, viteMode)
|
|
5818
|
+
);
|
|
5819
|
+
const serverMod = await timed(
|
|
5820
|
+
debugDiscovery,
|
|
5821
|
+
"import @rangojs/router/server",
|
|
5822
|
+
() => rscEnv.runner.import("@rangojs/router/server")
|
|
4878
5823
|
);
|
|
4879
5824
|
if (serverMod?.setManifestReadyPromise) {
|
|
4880
5825
|
serverMod.setManifestReadyPromise(discoveryPromise);
|
|
4881
5826
|
}
|
|
4882
|
-
await
|
|
5827
|
+
await timed(
|
|
5828
|
+
debugDiscovery,
|
|
5829
|
+
"discoverRouters",
|
|
5830
|
+
() => discoverRouters(s, rscEnv)
|
|
5831
|
+
);
|
|
4883
5832
|
s.devServerOrigin = getDevServerOrigin();
|
|
4884
|
-
|
|
4885
|
-
|
|
5833
|
+
timedSync(
|
|
5834
|
+
debugDiscovery,
|
|
5835
|
+
"writeRouteTypesFiles",
|
|
5836
|
+
() => writeRouteTypesFiles(s)
|
|
5837
|
+
);
|
|
5838
|
+
await timed(
|
|
5839
|
+
debugDiscovery,
|
|
5840
|
+
"propagateDiscoveryState",
|
|
5841
|
+
() => propagateDiscoveryState(rscEnv)
|
|
5842
|
+
);
|
|
4886
5843
|
} catch (err) {
|
|
4887
5844
|
console.warn(
|
|
4888
|
-
`[
|
|
5845
|
+
`[rango] Router discovery failed: ${err.message}
|
|
4889
5846
|
${err.stack}`
|
|
4890
5847
|
);
|
|
4891
5848
|
} finally {
|
|
5849
|
+
debugDiscovery?.(
|
|
5850
|
+
"dev discovery done (%sms)",
|
|
5851
|
+
(performance.now() - discoverStart).toFixed(1)
|
|
5852
|
+
);
|
|
4892
5853
|
resolveDiscovery();
|
|
4893
5854
|
}
|
|
4894
5855
|
};
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
5856
|
+
beginDiscoveryGate();
|
|
5857
|
+
setTimeout(
|
|
5858
|
+
() => discover().then(resolveDiscoveryGate, resolveDiscoveryGate),
|
|
5859
|
+
0
|
|
5860
|
+
);
|
|
4898
5861
|
let mainRegistry = null;
|
|
4899
5862
|
const propagateDiscoveryState = async (rscEnv) => {
|
|
4900
5863
|
const serverMod = await rscEnv.runner.import("@rangojs/router/server");
|
|
@@ -4912,29 +5875,35 @@ ${err.stack}`
|
|
|
4912
5875
|
if (s.mergedRouteTrie && serverMod.setRouteTrie) {
|
|
4913
5876
|
serverMod.setRouteTrie(s.mergedRouteTrie);
|
|
4914
5877
|
}
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
}
|
|
4925
|
-
if (serverMod.setRouterPrecomputedEntries) {
|
|
4926
|
-
for (const [routerId, entries] of s.perRouterPrecomputedMap) {
|
|
4927
|
-
serverMod.setRouterPrecomputedEntries(routerId, entries);
|
|
4928
|
-
}
|
|
5878
|
+
const perRouterSetters = [
|
|
5879
|
+
[s.perRouterManifestDataMap, "setRouterManifest"],
|
|
5880
|
+
[s.perRouterTrieMap, "setRouterTrie"],
|
|
5881
|
+
[s.perRouterPrecomputedMap, "setRouterPrecomputedEntries"]
|
|
5882
|
+
];
|
|
5883
|
+
for (const [map, fn] of perRouterSetters) {
|
|
5884
|
+
const setter = serverMod[fn];
|
|
5885
|
+
if (typeof setter !== "function") continue;
|
|
5886
|
+
for (const [routerId, value] of map) setter(routerId, value);
|
|
4929
5887
|
}
|
|
4930
5888
|
};
|
|
4931
5889
|
server.middlewares.use("/__rsc_prerender", async (req, res) => {
|
|
5890
|
+
const reqStart = debugDev ? performance.now() : 0;
|
|
5891
|
+
const logResult = (status, note) => {
|
|
5892
|
+
debugDev?.(
|
|
5893
|
+
"/__rsc_prerender %s -> %d %s (%sms)",
|
|
5894
|
+
req.url,
|
|
5895
|
+
status,
|
|
5896
|
+
note,
|
|
5897
|
+
(performance.now() - reqStart).toFixed(1)
|
|
5898
|
+
);
|
|
5899
|
+
};
|
|
4932
5900
|
if (s.discoveryDone) await s.discoveryDone;
|
|
4933
5901
|
const url = new URL(req.url || "/", "http://localhost");
|
|
4934
5902
|
const pathname = url.searchParams.get("pathname");
|
|
4935
5903
|
if (!pathname) {
|
|
4936
5904
|
res.statusCode = 400;
|
|
4937
5905
|
res.end("Missing pathname");
|
|
5906
|
+
logResult(400, "missing pathname");
|
|
4938
5907
|
return;
|
|
4939
5908
|
}
|
|
4940
5909
|
const rscEnv = server.environments?.rsc;
|
|
@@ -4948,10 +5917,11 @@ ${err.stack}`
|
|
|
4948
5917
|
registry = serverMod.RouterRegistry ?? null;
|
|
4949
5918
|
} catch (err) {
|
|
4950
5919
|
console.warn(
|
|
4951
|
-
`[
|
|
5920
|
+
`[rango] Dev prerender module refresh failed: ${err.message}`
|
|
4952
5921
|
);
|
|
4953
5922
|
res.statusCode = 500;
|
|
4954
5923
|
res.end(`Prerender handler error: ${err.message}`);
|
|
5924
|
+
logResult(500, "module refresh failed");
|
|
4955
5925
|
return;
|
|
4956
5926
|
}
|
|
4957
5927
|
} else {
|
|
@@ -4966,6 +5936,7 @@ ${err.stack}`
|
|
|
4966
5936
|
if (!registry || registry.size === 0) {
|
|
4967
5937
|
res.statusCode = 503;
|
|
4968
5938
|
res.end("Prerender runner not available");
|
|
5939
|
+
logResult(503, "no registry");
|
|
4969
5940
|
return;
|
|
4970
5941
|
}
|
|
4971
5942
|
const wantIntercept = url.searchParams.get("intercept") === "1";
|
|
@@ -5000,15 +5971,17 @@ ${err.stack}`
|
|
|
5000
5971
|
payload = { segments: result.segments, handles: result.handles };
|
|
5001
5972
|
}
|
|
5002
5973
|
res.end(JSON.stringify(payload));
|
|
5974
|
+
logResult(200, `match ${result.routeName}`);
|
|
5003
5975
|
return;
|
|
5004
5976
|
} catch (err) {
|
|
5005
5977
|
console.warn(
|
|
5006
|
-
`[
|
|
5978
|
+
`[rango] Dev prerender failed for ${pathname}: ${err.message}`
|
|
5007
5979
|
);
|
|
5008
5980
|
}
|
|
5009
5981
|
}
|
|
5010
5982
|
res.statusCode = 404;
|
|
5011
5983
|
res.end("No prerender match");
|
|
5984
|
+
logResult(404, "no match");
|
|
5012
5985
|
});
|
|
5013
5986
|
if (opts?.staticRouteTypesGeneration !== false) {
|
|
5014
5987
|
const isGeneratedRouteFile = (filePath) => filePath.endsWith(".gen.ts") && (filePath.includes("named-routes.gen.ts") || filePath.includes("urls.gen.ts"));
|
|
@@ -5028,59 +6001,185 @@ ${err.stack}`
|
|
|
5028
6001
|
return true;
|
|
5029
6002
|
};
|
|
5030
6003
|
let routeChangeTimer;
|
|
5031
|
-
let runtimeRediscoveryInProgress = false;
|
|
5032
6004
|
const refreshRuntimeDiscovery = async () => {
|
|
5033
6005
|
const rscEnv = server.environments?.rsc;
|
|
5034
|
-
|
|
5035
|
-
|
|
6006
|
+
const hasMainRunner = !!rscEnv?.runner;
|
|
6007
|
+
if (!hasMainRunner && s.perRouterManifests.length === 0) return;
|
|
6008
|
+
await gate.runRefreshCycle(async () => {
|
|
6009
|
+
const hmrStart = performance.now();
|
|
6010
|
+
try {
|
|
6011
|
+
if (hasMainRunner) {
|
|
6012
|
+
await timed(
|
|
6013
|
+
debugDiscovery,
|
|
6014
|
+
"hmr discoverRouters",
|
|
6015
|
+
() => discoverRouters(s, rscEnv)
|
|
6016
|
+
);
|
|
6017
|
+
timedSync(
|
|
6018
|
+
debugDiscovery,
|
|
6019
|
+
"hmr writeRouteTypesFiles",
|
|
6020
|
+
() => writeRouteTypesFiles(s)
|
|
6021
|
+
);
|
|
6022
|
+
await timed(
|
|
6023
|
+
debugDiscovery,
|
|
6024
|
+
"hmr propagateDiscoveryState",
|
|
6025
|
+
() => propagateDiscoveryState(rscEnv)
|
|
6026
|
+
);
|
|
6027
|
+
} else {
|
|
6028
|
+
const tempRscEnv = await timed(
|
|
6029
|
+
debugDiscovery,
|
|
6030
|
+
"hmr refreshTempRscEnv (cloudflare)",
|
|
6031
|
+
() => refreshTempRscEnv()
|
|
6032
|
+
);
|
|
6033
|
+
if (!tempRscEnv) {
|
|
6034
|
+
throw new Error(
|
|
6035
|
+
"temp runner unavailable for cloudflare HMR rediscovery"
|
|
6036
|
+
);
|
|
6037
|
+
}
|
|
6038
|
+
await timed(
|
|
6039
|
+
debugDiscovery,
|
|
6040
|
+
"hmr discoverRouters (cloudflare)",
|
|
6041
|
+
() => discoverRouters(s, tempRscEnv)
|
|
6042
|
+
);
|
|
6043
|
+
timedSync(
|
|
6044
|
+
debugDiscovery,
|
|
6045
|
+
"hmr writeRouteTypesFiles",
|
|
6046
|
+
() => writeRouteTypesFiles(s)
|
|
6047
|
+
);
|
|
6048
|
+
}
|
|
6049
|
+
if (s.lastDiscoveryError) {
|
|
6050
|
+
debugDiscovery?.(
|
|
6051
|
+
"hmr: cleared lastDiscoveryError (%s) after successful rediscovery",
|
|
6052
|
+
s.lastDiscoveryError.message
|
|
6053
|
+
);
|
|
6054
|
+
s.lastDiscoveryError = null;
|
|
6055
|
+
}
|
|
6056
|
+
if (rscEnv && !rscEnv.runner) forceCloudflareWorkerReload(rscEnv);
|
|
6057
|
+
} catch (err) {
|
|
6058
|
+
s.lastDiscoveryError = {
|
|
6059
|
+
message: err?.message ?? String(err),
|
|
6060
|
+
at: Date.now()
|
|
6061
|
+
};
|
|
6062
|
+
console.warn(
|
|
6063
|
+
`[rango] Runtime re-discovery failed: ${err.message}`
|
|
6064
|
+
);
|
|
6065
|
+
debugDiscovery?.(
|
|
6066
|
+
"hmr: lastDiscoveryError set (%s) \u2014 manifest preserved at last-good; recovery mode active (any in-scan source change will trigger rediscovery)",
|
|
6067
|
+
err?.message
|
|
6068
|
+
);
|
|
6069
|
+
} finally {
|
|
6070
|
+
debugDiscovery?.(
|
|
6071
|
+
"hmr re-discovery done (%sms)",
|
|
6072
|
+
(performance.now() - hmrStart).toFixed(1)
|
|
6073
|
+
);
|
|
6074
|
+
}
|
|
6075
|
+
});
|
|
6076
|
+
};
|
|
6077
|
+
const forceCloudflareWorkerReload = (rscEnv) => {
|
|
6078
|
+
if (!rscEnv?.hot) return;
|
|
5036
6079
|
try {
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
6080
|
+
const graph = rscEnv.moduleGraph;
|
|
6081
|
+
if (graph?.invalidateAll) {
|
|
6082
|
+
graph.invalidateAll();
|
|
6083
|
+
debugDiscovery?.("hmr: invalidated workerd rsc module graph");
|
|
6084
|
+
}
|
|
6085
|
+
rscEnv.hot.send({ type: "full-reload" });
|
|
6086
|
+
debugDiscovery?.(
|
|
6087
|
+
"hmr: forced workerd rsc env reload (full-reload)"
|
|
6088
|
+
);
|
|
5040
6089
|
} catch (err) {
|
|
5041
|
-
|
|
5042
|
-
|
|
6090
|
+
debugDiscovery?.(
|
|
6091
|
+
"hmr: workerd reload failed: %s",
|
|
6092
|
+
err?.message ?? err
|
|
5043
6093
|
);
|
|
5044
|
-
} finally {
|
|
5045
|
-
runtimeRediscoveryInProgress = false;
|
|
5046
6094
|
}
|
|
5047
6095
|
};
|
|
5048
6096
|
const scheduleRouteRegeneration = () => {
|
|
5049
6097
|
clearTimeout(routeChangeTimer);
|
|
5050
6098
|
routeChangeTimer = setTimeout(() => {
|
|
5051
6099
|
routeChangeTimer = void 0;
|
|
6100
|
+
const regenStart = debugDiscovery ? performance.now() : 0;
|
|
6101
|
+
const rscEnv = server.environments?.rsc;
|
|
6102
|
+
const skipStaticWrite = !rscEnv?.runner && s.perRouterManifests.length > 0;
|
|
5052
6103
|
try {
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
6104
|
+
if (skipStaticWrite) {
|
|
6105
|
+
debugDiscovery?.(
|
|
6106
|
+
"watcher: skipping static write (cloudflare HMR \u2014 runtime rediscovery owns gen file)"
|
|
6107
|
+
);
|
|
6108
|
+
} else {
|
|
6109
|
+
writeCombinedRouteTypesWithTracking(s);
|
|
6110
|
+
if (s.perRouterManifests.length > 0) {
|
|
6111
|
+
supplementGenFilesWithRuntimeRoutes(s);
|
|
6112
|
+
}
|
|
5056
6113
|
}
|
|
5057
6114
|
} catch (err) {
|
|
5058
|
-
console.error(
|
|
5059
|
-
`[rsc-router] Route regeneration error: ${err.message}`
|
|
5060
|
-
);
|
|
6115
|
+
console.error(`[rango] Route regeneration error: ${err.message}`);
|
|
5061
6116
|
}
|
|
6117
|
+
debugDiscovery?.(
|
|
6118
|
+
"watcher: regenerated gen files (%sms)",
|
|
6119
|
+
(performance.now() - regenStart).toFixed(1)
|
|
6120
|
+
);
|
|
5062
6121
|
if (s.perRouterManifests.length > 0) {
|
|
5063
6122
|
refreshRuntimeDiscovery().catch((err) => {
|
|
5064
6123
|
console.warn(
|
|
5065
|
-
`[
|
|
6124
|
+
`[rango] Runtime re-discovery error: ${err.message}`
|
|
5066
6125
|
);
|
|
6126
|
+
resolveDiscoveryGate();
|
|
5067
6127
|
});
|
|
5068
6128
|
}
|
|
5069
6129
|
}, 100);
|
|
5070
6130
|
};
|
|
5071
6131
|
const handleRouteFileChange = (filePath) => {
|
|
5072
6132
|
if (maybeHandleGeneratedRouteFileMutation(filePath)) return;
|
|
5073
|
-
if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx") && !filePath.endsWith(".js") && !filePath.endsWith(".jsx"))
|
|
6133
|
+
if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx") && !filePath.endsWith(".js") && !filePath.endsWith(".jsx")) {
|
|
6134
|
+
if (s.lastDiscoveryError) {
|
|
6135
|
+
debugDiscovery?.(
|
|
6136
|
+
"watcher: skip non-source %s [LASTERR %s]",
|
|
6137
|
+
filePath,
|
|
6138
|
+
s.lastDiscoveryError.message
|
|
6139
|
+
);
|
|
6140
|
+
}
|
|
6141
|
+
return;
|
|
6142
|
+
}
|
|
6143
|
+
if (s.scanFilter && !s.scanFilter(filePath)) {
|
|
6144
|
+
if (s.lastDiscoveryError) {
|
|
6145
|
+
debugDiscovery?.(
|
|
6146
|
+
"watcher: skip scan-filter %s [LASTERR %s]",
|
|
6147
|
+
filePath,
|
|
6148
|
+
s.lastDiscoveryError.message
|
|
6149
|
+
);
|
|
6150
|
+
}
|
|
5074
6151
|
return;
|
|
5075
|
-
|
|
6152
|
+
}
|
|
6153
|
+
const inRecoveryMode = !!s.lastDiscoveryError;
|
|
5076
6154
|
try {
|
|
5077
6155
|
const source = readFileSync6(filePath, "utf-8");
|
|
5078
6156
|
const trimmed = source.trimStart();
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
if (
|
|
6157
|
+
const isUseClient = trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'");
|
|
6158
|
+
if (!inRecoveryMode && isUseClient) return;
|
|
6159
|
+
let hasUrls = source.includes("urls(");
|
|
6160
|
+
let hasCreateRouter = /\bcreateRouter\s*[<(]/.test(source);
|
|
6161
|
+
if (hasUrls) hasUrls = firstCodeMatchIndex(source, /urls\(/g) >= 0;
|
|
6162
|
+
if (hasCreateRouter) {
|
|
6163
|
+
hasCreateRouter = firstCodeMatchIndex(source, /\bcreateRouter\s*[<(]/g) >= 0;
|
|
6164
|
+
}
|
|
6165
|
+
if (!inRecoveryMode && !hasUrls && !hasCreateRouter) return;
|
|
6166
|
+
if (inRecoveryMode) {
|
|
6167
|
+
debugDiscovery?.(
|
|
6168
|
+
"watcher: recovery rediscovery for %s (urls=%s, router=%s, useClient=%s) [LASTERR %s]",
|
|
6169
|
+
filePath,
|
|
6170
|
+
hasUrls,
|
|
6171
|
+
hasCreateRouter,
|
|
6172
|
+
isUseClient,
|
|
6173
|
+
s.lastDiscoveryError.message
|
|
6174
|
+
);
|
|
6175
|
+
} else {
|
|
6176
|
+
debugDiscovery?.(
|
|
6177
|
+
"watcher: %s matches (urls=%s, router=%s)",
|
|
6178
|
+
filePath,
|
|
6179
|
+
hasUrls,
|
|
6180
|
+
hasCreateRouter
|
|
6181
|
+
);
|
|
6182
|
+
}
|
|
5084
6183
|
if (hasCreateRouter) {
|
|
5085
6184
|
const nestedRouterConflict = findNestedRouterConflict([
|
|
5086
6185
|
...s.cachedRouterFiles ?? [],
|
|
@@ -5094,8 +6193,19 @@ ${err.stack}`
|
|
|
5094
6193
|
}
|
|
5095
6194
|
s.cachedRouterFiles = void 0;
|
|
5096
6195
|
}
|
|
6196
|
+
if (s.perRouterManifests.length > 0) {
|
|
6197
|
+
gate.noteRouteEvent();
|
|
6198
|
+
}
|
|
5097
6199
|
scheduleRouteRegeneration();
|
|
5098
|
-
} catch {
|
|
6200
|
+
} catch (readErr) {
|
|
6201
|
+
if (s.lastDiscoveryError) {
|
|
6202
|
+
debugDiscovery?.(
|
|
6203
|
+
"watcher: read error %s: %s [LASTERR %s]",
|
|
6204
|
+
filePath,
|
|
6205
|
+
readErr?.message,
|
|
6206
|
+
s.lastDiscoveryError.message
|
|
6207
|
+
);
|
|
6208
|
+
}
|
|
5099
6209
|
}
|
|
5100
6210
|
};
|
|
5101
6211
|
server.watcher.on("add", handleRouteFileChange);
|
|
@@ -5113,19 +6223,35 @@ ${err.stack}`
|
|
|
5113
6223
|
// The manifest data is stored for the virtual module's load hook.
|
|
5114
6224
|
async buildStart() {
|
|
5115
6225
|
if (!s.isBuildMode) return;
|
|
5116
|
-
if (s.mergedRouteManifest !== null)
|
|
6226
|
+
if (s.mergedRouteManifest !== null) {
|
|
6227
|
+
debugDiscovery?.(
|
|
6228
|
+
"build: skip (already discovered, env=%s)",
|
|
6229
|
+
this.environment?.name ?? "?"
|
|
6230
|
+
);
|
|
6231
|
+
return;
|
|
6232
|
+
}
|
|
6233
|
+
const buildStartTime = performance.now();
|
|
6234
|
+
debugDiscovery?.("build: start (env=%s)", this.environment?.name ?? "?");
|
|
5117
6235
|
resetStagedBuildAssets(s.projectRoot);
|
|
5118
6236
|
s.prerenderManifestEntries = null;
|
|
5119
6237
|
s.staticManifestEntries = null;
|
|
5120
|
-
await
|
|
6238
|
+
await timed(
|
|
6239
|
+
debugDiscovery,
|
|
6240
|
+
"build acquireBuildEnv",
|
|
6241
|
+
() => acquireBuildEnv(s, viteCommand, viteMode)
|
|
6242
|
+
);
|
|
5121
6243
|
let tempServer = null;
|
|
5122
6244
|
globalThis.__rscRouterDiscoveryActive = true;
|
|
5123
6245
|
try {
|
|
5124
|
-
tempServer = await
|
|
6246
|
+
tempServer = await timed(
|
|
6247
|
+
debugDiscovery,
|
|
6248
|
+
"build createTempRscServer",
|
|
6249
|
+
() => createTempRscServer(s, { forceBuild: true })
|
|
6250
|
+
);
|
|
5125
6251
|
const rscEnv = tempServer.environments?.rsc;
|
|
5126
6252
|
if (!rscEnv?.runner) {
|
|
5127
6253
|
console.warn(
|
|
5128
|
-
"[
|
|
6254
|
+
"[rango] RSC environment runner not available during build, skipping manifest generation"
|
|
5129
6255
|
);
|
|
5130
6256
|
return;
|
|
5131
6257
|
}
|
|
@@ -5135,8 +6261,16 @@ ${err.stack}`
|
|
|
5135
6261
|
if (tempIdsPlugin?.api?.staticHandlerModules) {
|
|
5136
6262
|
s.resolvedStaticModules = tempIdsPlugin.api.staticHandlerModules;
|
|
5137
6263
|
}
|
|
5138
|
-
await
|
|
5139
|
-
|
|
6264
|
+
await timed(
|
|
6265
|
+
debugDiscovery,
|
|
6266
|
+
"build discoverRouters",
|
|
6267
|
+
() => discoverRouters(s, rscEnv)
|
|
6268
|
+
);
|
|
6269
|
+
timedSync(
|
|
6270
|
+
debugDiscovery,
|
|
6271
|
+
"build writeRouteTypesFiles",
|
|
6272
|
+
() => writeRouteTypesFiles(s)
|
|
6273
|
+
);
|
|
5140
6274
|
} catch (err) {
|
|
5141
6275
|
const sourceFile = err.stack?.split("\n").find(
|
|
5142
6276
|
(line) => line.includes(s.projectRoot) && !line.includes("node_modules")
|
|
@@ -5149,15 +6283,52 @@ ${err.stack}`
|
|
|
5149
6283
|
${err.stack}` : null
|
|
5150
6284
|
].filter(Boolean).join("\n");
|
|
5151
6285
|
throw new Error(
|
|
5152
|
-
`[
|
|
5153
|
-
${details}
|
|
6286
|
+
`[rango] Build-time router discovery failed:
|
|
6287
|
+
${details}`,
|
|
6288
|
+
{ cause: err }
|
|
5154
6289
|
);
|
|
5155
6290
|
} finally {
|
|
5156
6291
|
delete globalThis.__rscRouterDiscoveryActive;
|
|
5157
6292
|
if (tempServer) {
|
|
5158
|
-
await
|
|
6293
|
+
await timed(
|
|
6294
|
+
debugDiscovery,
|
|
6295
|
+
"build tempServer.close",
|
|
6296
|
+
() => tempServer.close()
|
|
6297
|
+
);
|
|
5159
6298
|
}
|
|
5160
6299
|
await releaseBuildEnv(s);
|
|
6300
|
+
debugDiscovery?.(
|
|
6301
|
+
"build discovery done (%sms)",
|
|
6302
|
+
(performance.now() - buildStartTime).toFixed(1)
|
|
6303
|
+
);
|
|
6304
|
+
}
|
|
6305
|
+
},
|
|
6306
|
+
// Suppress vite's HMR cascade for our own gen-file writes.
|
|
6307
|
+
//
|
|
6308
|
+
// After every cf HMR cycle, refreshTempRscEnv → writeRouteTypesFiles
|
|
6309
|
+
// writes the configured gen files (default `router.named-routes.gen.ts`,
|
|
6310
|
+
// but the source filenames and gen suffix are user-configurable). The
|
|
6311
|
+
// chokidar watcher then fires twice independently: our
|
|
6312
|
+
// `handleRouteFileChange` (already short-circuited by
|
|
6313
|
+
// `consumeSelfGenWrite` inside `maybeHandleGeneratedRouteFileMutation`),
|
|
6314
|
+
// AND vite's own HMR pipeline (which invalidates the gen file's
|
|
6315
|
+
// importers and triggers a second workerd full reload — visible to the
|
|
6316
|
+
// user as a duplicate "[Rango] HMR: version changed" on the client).
|
|
6317
|
+
//
|
|
6318
|
+
// `peekSelfGenWrite` is the authoritative filter: its map only contains
|
|
6319
|
+
// paths that `markSelfGenWrite` has registered, so it natively works
|
|
6320
|
+
// for any configured gen-file name. It is non-consuming so the chokidar
|
|
6321
|
+
// handler that fires later can still consume the same entry. Returning
|
|
6322
|
+
// [] tells vite "no modules invalidated by this change" — safe because
|
|
6323
|
+
// `s.perRouterManifests` is already up-to-date (the write that just
|
|
6324
|
+
// happened is the consequence of our just-completed rediscovery).
|
|
6325
|
+
handleHotUpdate(ctx) {
|
|
6326
|
+
if (peekSelfGenWrite(s, ctx.file)) {
|
|
6327
|
+
debugDiscovery?.(
|
|
6328
|
+
"handleHotUpdate: suppressing self-write HMR cascade for %s",
|
|
6329
|
+
ctx.file
|
|
6330
|
+
);
|
|
6331
|
+
return [];
|
|
5161
6332
|
}
|
|
5162
6333
|
},
|
|
5163
6334
|
// Virtual module: provides the pre-generated route manifest as a JS module
|
|
@@ -5174,17 +6345,36 @@ ${details}`
|
|
|
5174
6345
|
async load(id) {
|
|
5175
6346
|
if (id === "\0" + VIRTUAL_ROUTES_MANIFEST_ID) {
|
|
5176
6347
|
if (s.discoveryDone) {
|
|
5177
|
-
await
|
|
6348
|
+
await timed(
|
|
6349
|
+
debugRoutes,
|
|
6350
|
+
"await discoveryDone (manifest)",
|
|
6351
|
+
() => s.discoveryDone
|
|
6352
|
+
);
|
|
5178
6353
|
}
|
|
5179
|
-
|
|
6354
|
+
const code = await timed(
|
|
6355
|
+
debugRoutes,
|
|
6356
|
+
"generateRoutesManifestModule",
|
|
6357
|
+
() => generateRoutesManifestModule(s)
|
|
6358
|
+
);
|
|
6359
|
+
debugRoutes?.("manifest module emitted (%d bytes)", code?.length ?? 0);
|
|
6360
|
+
return code;
|
|
5180
6361
|
}
|
|
5181
6362
|
const perRouterPrefix = "\0" + VIRTUAL_ROUTES_MANIFEST_ID + "/";
|
|
5182
6363
|
if (id.startsWith(perRouterPrefix)) {
|
|
5183
6364
|
if (s.discoveryDone) {
|
|
5184
|
-
await
|
|
6365
|
+
await timed(
|
|
6366
|
+
debugRoutes,
|
|
6367
|
+
"await discoveryDone (per-router)",
|
|
6368
|
+
() => s.discoveryDone
|
|
6369
|
+
);
|
|
5185
6370
|
}
|
|
5186
6371
|
const routerId = id.slice(perRouterPrefix.length);
|
|
5187
|
-
|
|
6372
|
+
const code = await timed(
|
|
6373
|
+
debugRoutes,
|
|
6374
|
+
`generatePerRouterModule ${routerId}`,
|
|
6375
|
+
() => generatePerRouterModule(s, routerId)
|
|
6376
|
+
);
|
|
6377
|
+
return code;
|
|
5188
6378
|
}
|
|
5189
6379
|
return null;
|
|
5190
6380
|
},
|
|
@@ -5192,14 +6382,20 @@ ${details}`
|
|
|
5192
6382
|
// Used by closeBundle for handler code eviction and prerender data injection.
|
|
5193
6383
|
generateBundle(_options, bundle) {
|
|
5194
6384
|
if (this.environment?.name !== "rsc") return;
|
|
6385
|
+
const genStart = debugBuild ? performance.now() : 0;
|
|
5195
6386
|
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
5196
6387
|
if (chunk.type === "chunk" && chunk.isEntry) {
|
|
5197
6388
|
s.rscEntryFileName = fileName;
|
|
5198
6389
|
break;
|
|
5199
6390
|
}
|
|
5200
6391
|
}
|
|
5201
|
-
if (!s.resolvedPrerenderModules?.size && !s.resolvedStaticModules?.size)
|
|
6392
|
+
if (!s.resolvedPrerenderModules?.size && !s.resolvedStaticModules?.size) {
|
|
6393
|
+
debugBuild?.(
|
|
6394
|
+
"generateBundle (rsc): no handlers to scan (%sms)",
|
|
6395
|
+
(performance.now() - genStart).toFixed(1)
|
|
6396
|
+
);
|
|
5202
6397
|
return;
|
|
6398
|
+
}
|
|
5203
6399
|
s.handlerChunkInfoMap.clear();
|
|
5204
6400
|
s.staticHandlerChunkInfoMap.clear();
|
|
5205
6401
|
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
@@ -5243,6 +6439,13 @@ ${details}`
|
|
|
5243
6439
|
}
|
|
5244
6440
|
}
|
|
5245
6441
|
}
|
|
6442
|
+
debugBuild?.(
|
|
6443
|
+
"generateBundle (rsc): scanned %d chunks, %d prerender chunk(s), %d static chunk(s) (%sms)",
|
|
6444
|
+
Object.keys(bundle).length,
|
|
6445
|
+
s.handlerChunkInfoMap.size,
|
|
6446
|
+
s.staticHandlerChunkInfoMap.size,
|
|
6447
|
+
(performance.now() - genStart).toFixed(1)
|
|
6448
|
+
);
|
|
5246
6449
|
},
|
|
5247
6450
|
// Build-time pre-rendering: evict handler code and inject collected prerender data.
|
|
5248
6451
|
// Collection now happens in-process during discoverRouters() via RSC runner.
|
|
@@ -5253,29 +6456,45 @@ ${details}`
|
|
|
5253
6456
|
async handler() {
|
|
5254
6457
|
if (!s.isBuildMode) return;
|
|
5255
6458
|
if (this.environment && this.environment.name !== "rsc") return;
|
|
5256
|
-
|
|
6459
|
+
timedSync(
|
|
6460
|
+
debugBuild,
|
|
6461
|
+
"closeBundle postprocessBundle",
|
|
6462
|
+
() => postprocessBundle(s)
|
|
6463
|
+
);
|
|
5257
6464
|
}
|
|
5258
6465
|
}
|
|
5259
6466
|
};
|
|
5260
6467
|
}
|
|
5261
6468
|
|
|
5262
6469
|
// src/vite/rango.ts
|
|
6470
|
+
var debugConfig = createRangoDebugger(NS.config);
|
|
5263
6471
|
async function rango(options) {
|
|
6472
|
+
const rangoStart = performance.now();
|
|
5264
6473
|
const resolvedOptions = options ?? { preset: "node" };
|
|
5265
6474
|
const preset = resolvedOptions.preset ?? "node";
|
|
5266
6475
|
const showBanner = resolvedOptions.banner ?? true;
|
|
6476
|
+
const clientChunksOption = resolvedOptions.clientChunks ?? true;
|
|
6477
|
+
const useBuiltInClientChunks = clientChunksOption === true;
|
|
6478
|
+
const clientChunkCtx = useBuiltInClientChunks ? { fallbackRefs: /* @__PURE__ */ new Set() } : void 0;
|
|
6479
|
+
const clientChunks = resolveClientChunks(clientChunksOption, clientChunkCtx);
|
|
6480
|
+
debugConfig?.("rango(%s) setup start", preset);
|
|
5267
6481
|
const plugins = [];
|
|
5268
|
-
const rangoAliases = getPackageAliases();
|
|
6482
|
+
const rangoAliases = { ...getPackageAliases(), ...getVendorAliases() };
|
|
5269
6483
|
const excludeDeps = [
|
|
5270
6484
|
...getExcludeDeps(),
|
|
5271
|
-
//
|
|
5272
|
-
//
|
|
5273
|
-
// .
|
|
6485
|
+
// plugin-rsc itself injects these into the client env's
|
|
6486
|
+
// optimizeDeps.include, which overrides exclude for the dep's own
|
|
6487
|
+
// pre-bundle entry. What exclude still controls is how *other*
|
|
6488
|
+
// pre-bundled deps treat imports of these specs (external vs inlined)
|
|
6489
|
+
// via esbuildCjsExternalPlugin. The cjs-to-esm transform in
|
|
6490
|
+
// plugins/cjs-to-esm.ts is the fallback for strict-pnpm consumers,
|
|
6491
|
+
// where client.browser's bare include fails to resolve and Vite ends up
|
|
6492
|
+
// serving the raw CJS file at dev-serve time.
|
|
5274
6493
|
"@vitejs/plugin-rsc/browser",
|
|
5275
|
-
// Keep the browser RSDW client out of Vite's dep optimizer so our
|
|
5276
|
-
// cjs-to-esm transform can patch the real file.
|
|
5277
6494
|
"@vitejs/plugin-rsc/vendor/react-server-dom/client.browser"
|
|
5278
6495
|
];
|
|
6496
|
+
const pkg = getPublishedPackageName();
|
|
6497
|
+
const nested = (spec) => `${pkg} > ${spec}`;
|
|
5279
6498
|
const routerRef = { path: void 0 };
|
|
5280
6499
|
const prerenderEnabled = true;
|
|
5281
6500
|
if (preset === "cloudflare") {
|
|
@@ -5293,10 +6512,18 @@ async function rango(options) {
|
|
|
5293
6512
|
// This ensures the same Context instance is used by both browser entry and RSC proxy modules
|
|
5294
6513
|
optimizeDeps: {
|
|
5295
6514
|
exclude: excludeDeps,
|
|
5296
|
-
|
|
6515
|
+
rolldownOptions: sharedRolldownOptions
|
|
5297
6516
|
},
|
|
5298
6517
|
resolve: {
|
|
5299
|
-
alias: rangoAliases
|
|
6518
|
+
alias: rangoAliases,
|
|
6519
|
+
// Force a single React/React-DOM copy across all three RSC
|
|
6520
|
+
// environments. RSC requires exactly one react/react-dom instance
|
|
6521
|
+
// per environment runtime; consumer install topologies (pnpm
|
|
6522
|
+
// strict layout, experimental React pins, third-party "use client"
|
|
6523
|
+
// packages) can otherwise resolve duplicate copies, causing
|
|
6524
|
+
// "Invalid hook call" / lost context. Child environments inherit
|
|
6525
|
+
// this root dedupe, and Vite merges it with any consumer dedupe.
|
|
6526
|
+
dedupe: ["react", "react-dom"]
|
|
5300
6527
|
},
|
|
5301
6528
|
build: {
|
|
5302
6529
|
rollupOptions: { onwarn }
|
|
@@ -5305,6 +6532,14 @@ async function rango(options) {
|
|
|
5305
6532
|
client: {
|
|
5306
6533
|
build: {
|
|
5307
6534
|
rollupOptions: {
|
|
6535
|
+
// FILE_NAME_CONFLICT (and any other client-build warning) is
|
|
6536
|
+
// emitted by the CLIENT environment build, which consults THIS
|
|
6537
|
+
// env's onwarn -- Vite 8's environment builds do NOT propagate
|
|
6538
|
+
// the top-level build.rollupOptions.onwarn into the client env.
|
|
6539
|
+
// Wire it here so the suppression runs where the conflicts
|
|
6540
|
+
// originate (the top-level handler is invoked 0x for these; the
|
|
6541
|
+
// client-env handler is invoked for all of them).
|
|
6542
|
+
onwarn,
|
|
5308
6543
|
output: {
|
|
5309
6544
|
manualChunks: getManualChunks
|
|
5310
6545
|
}
|
|
@@ -5313,9 +6548,9 @@ async function rango(options) {
|
|
|
5313
6548
|
// Pre-bundle rsc-html-stream to prevent discovery during first request
|
|
5314
6549
|
// Exclude rsc-router modules to ensure same Context instance
|
|
5315
6550
|
optimizeDeps: {
|
|
5316
|
-
include: ["rsc-html-stream/client"],
|
|
6551
|
+
include: [nested("rsc-html-stream/client")],
|
|
5317
6552
|
exclude: excludeDeps,
|
|
5318
|
-
|
|
6553
|
+
rolldownOptions: sharedRolldownOptions
|
|
5319
6554
|
}
|
|
5320
6555
|
},
|
|
5321
6556
|
ssr: {
|
|
@@ -5323,10 +6558,6 @@ async function rango(options) {
|
|
|
5323
6558
|
build: {
|
|
5324
6559
|
outDir: "./dist/rsc/ssr"
|
|
5325
6560
|
},
|
|
5326
|
-
resolve: {
|
|
5327
|
-
// Ensure single React instance in SSR child environment
|
|
5328
|
-
dedupe: ["react", "react-dom"]
|
|
5329
|
-
},
|
|
5330
6561
|
// Pre-bundle SSR entry and React for proper module linking with childEnvironments
|
|
5331
6562
|
// All deps must be listed to avoid late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
5332
6563
|
optimizeDeps: {
|
|
@@ -5338,11 +6569,13 @@ async function rango(options) {
|
|
|
5338
6569
|
"react-dom/static.edge",
|
|
5339
6570
|
"react/jsx-runtime",
|
|
5340
6571
|
"react/jsx-dev-runtime",
|
|
5341
|
-
"rsc-html-stream/server",
|
|
5342
|
-
|
|
6572
|
+
nested("rsc-html-stream/server"),
|
|
6573
|
+
nested(
|
|
6574
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
|
|
6575
|
+
)
|
|
5343
6576
|
],
|
|
5344
6577
|
exclude: excludeDeps,
|
|
5345
|
-
|
|
6578
|
+
rolldownOptions: sharedRolldownOptions
|
|
5346
6579
|
}
|
|
5347
6580
|
},
|
|
5348
6581
|
rsc: {
|
|
@@ -5354,10 +6587,12 @@ async function rango(options) {
|
|
|
5354
6587
|
"react",
|
|
5355
6588
|
"react/jsx-runtime",
|
|
5356
6589
|
"react/jsx-dev-runtime",
|
|
5357
|
-
|
|
6590
|
+
nested(
|
|
6591
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
6592
|
+
)
|
|
5358
6593
|
],
|
|
5359
6594
|
exclude: excludeDeps,
|
|
5360
|
-
|
|
6595
|
+
rolldownOptions: sharedRolldownOptions
|
|
5361
6596
|
}
|
|
5362
6597
|
}
|
|
5363
6598
|
}
|
|
@@ -5375,7 +6610,8 @@ async function rango(options) {
|
|
|
5375
6610
|
plugins.push(
|
|
5376
6611
|
rsc({
|
|
5377
6612
|
entries: finalEntries,
|
|
5378
|
-
serverHandler: false
|
|
6613
|
+
serverHandler: false,
|
|
6614
|
+
clientChunks
|
|
5379
6615
|
})
|
|
5380
6616
|
);
|
|
5381
6617
|
plugins.push(clientRefDedup());
|
|
@@ -5393,7 +6629,7 @@ async function rango(options) {
|
|
|
5393
6629
|
const list = candidates.map(
|
|
5394
6630
|
(f) => " - " + (f.startsWith(root) ? f.slice(root.length + 1) : f)
|
|
5395
6631
|
).join("\n");
|
|
5396
|
-
throw new Error(`[
|
|
6632
|
+
throw new Error(`[rango] Multiple routers found:
|
|
5397
6633
|
${list}`);
|
|
5398
6634
|
}
|
|
5399
6635
|
}
|
|
@@ -5412,18 +6648,34 @@ ${list}`);
|
|
|
5412
6648
|
return {
|
|
5413
6649
|
optimizeDeps: {
|
|
5414
6650
|
exclude: excludeDeps,
|
|
5415
|
-
|
|
6651
|
+
rolldownOptions: sharedRolldownOptions
|
|
5416
6652
|
},
|
|
5417
6653
|
build: {
|
|
5418
6654
|
rollupOptions: { onwarn }
|
|
5419
6655
|
},
|
|
5420
6656
|
resolve: {
|
|
5421
|
-
alias: rangoAliases
|
|
6657
|
+
alias: rangoAliases,
|
|
6658
|
+
// Force a single React/React-DOM copy across all three RSC
|
|
6659
|
+
// environments. RSC requires exactly one react/react-dom instance
|
|
6660
|
+
// per environment runtime; consumer install topologies (pnpm
|
|
6661
|
+
// strict layout, experimental React pins, third-party "use client"
|
|
6662
|
+
// packages) can otherwise resolve duplicate copies, causing
|
|
6663
|
+
// "Invalid hook call" / lost context. Child environments inherit
|
|
6664
|
+
// this root dedupe, and Vite merges it with any consumer dedupe.
|
|
6665
|
+
dedupe: ["react", "react-dom"]
|
|
5422
6666
|
},
|
|
5423
6667
|
environments: {
|
|
5424
6668
|
client: {
|
|
5425
6669
|
build: {
|
|
5426
6670
|
rollupOptions: {
|
|
6671
|
+
// FILE_NAME_CONFLICT (and any other client-build warning) is
|
|
6672
|
+
// emitted by the CLIENT environment build, which consults THIS
|
|
6673
|
+
// env's onwarn -- Vite 8's environment builds do NOT propagate
|
|
6674
|
+
// the top-level build.rollupOptions.onwarn into the client env.
|
|
6675
|
+
// Wire it here so the suppression runs where the conflicts
|
|
6676
|
+
// originate (the top-level handler is invoked 0x for these; the
|
|
6677
|
+
// client-env handler is invoked for all of them).
|
|
6678
|
+
onwarn,
|
|
5427
6679
|
output: {
|
|
5428
6680
|
manualChunks: getManualChunks
|
|
5429
6681
|
}
|
|
@@ -5435,10 +6687,10 @@ ${list}`);
|
|
|
5435
6687
|
"react-dom",
|
|
5436
6688
|
"react/jsx-runtime",
|
|
5437
6689
|
"react/jsx-dev-runtime",
|
|
5438
|
-
"rsc-html-stream/client"
|
|
6690
|
+
nested("rsc-html-stream/client")
|
|
5439
6691
|
],
|
|
5440
6692
|
exclude: excludeDeps,
|
|
5441
|
-
|
|
6693
|
+
rolldownOptions: sharedRolldownOptions,
|
|
5442
6694
|
entries: [VIRTUAL_IDS.browser]
|
|
5443
6695
|
}
|
|
5444
6696
|
},
|
|
@@ -5452,10 +6704,12 @@ ${list}`);
|
|
|
5452
6704
|
"react-dom/static.edge",
|
|
5453
6705
|
"react/jsx-runtime",
|
|
5454
6706
|
"react/jsx-dev-runtime",
|
|
5455
|
-
|
|
6707
|
+
nested(
|
|
6708
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
|
|
6709
|
+
)
|
|
5456
6710
|
],
|
|
5457
6711
|
exclude: excludeDeps,
|
|
5458
|
-
|
|
6712
|
+
rolldownOptions: sharedRolldownOptions
|
|
5459
6713
|
}
|
|
5460
6714
|
},
|
|
5461
6715
|
rsc: {
|
|
@@ -5465,9 +6719,11 @@ ${list}`);
|
|
|
5465
6719
|
"react",
|
|
5466
6720
|
"react/jsx-runtime",
|
|
5467
6721
|
"react/jsx-dev-runtime",
|
|
5468
|
-
|
|
6722
|
+
nested(
|
|
6723
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
6724
|
+
)
|
|
5469
6725
|
],
|
|
5470
|
-
|
|
6726
|
+
rolldownOptions: sharedRolldownOptions
|
|
5471
6727
|
}
|
|
5472
6728
|
}
|
|
5473
6729
|
}
|
|
@@ -5484,7 +6740,7 @@ ${list}`);
|
|
|
5484
6740
|
if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
|
|
5485
6741
|
hasWarnedDuplicate = true;
|
|
5486
6742
|
console.warn(
|
|
5487
|
-
"[
|
|
6743
|
+
"[rango] Duplicate @vitejs/plugin-rsc detected. Remove rsc() from your vite config \u2014 rango() includes it automatically."
|
|
5488
6744
|
);
|
|
5489
6745
|
}
|
|
5490
6746
|
}
|
|
@@ -5493,7 +6749,8 @@ ${list}`);
|
|
|
5493
6749
|
plugins.push(performanceTracksPlugin());
|
|
5494
6750
|
plugins.push(
|
|
5495
6751
|
rsc({
|
|
5496
|
-
entries: finalEntries
|
|
6752
|
+
entries: finalEntries,
|
|
6753
|
+
clientChunks
|
|
5497
6754
|
})
|
|
5498
6755
|
);
|
|
5499
6756
|
plugins.push(clientRefDedup());
|
|
@@ -5532,9 +6789,16 @@ ${list}`);
|
|
|
5532
6789
|
routerPathRef: discoveryRouterRef,
|
|
5533
6790
|
enableBuildPrerender: prerenderEnabled,
|
|
5534
6791
|
buildEnv: options?.buildEnv,
|
|
5535
|
-
preset
|
|
6792
|
+
preset,
|
|
6793
|
+
clientChunkCtx
|
|
5536
6794
|
})
|
|
5537
6795
|
);
|
|
6796
|
+
debugConfig?.(
|
|
6797
|
+
"rango(%s) setup done: %d plugin(s) (%sms)",
|
|
6798
|
+
preset,
|
|
6799
|
+
plugins.length,
|
|
6800
|
+
(performance.now() - rangoStart).toFixed(1)
|
|
6801
|
+
);
|
|
5538
6802
|
return plugins;
|
|
5539
6803
|
}
|
|
5540
6804
|
|
|
@@ -5545,7 +6809,7 @@ function poke() {
|
|
|
5545
6809
|
apply: "serve",
|
|
5546
6810
|
configureServer(server) {
|
|
5547
6811
|
const stdin = process.stdin;
|
|
5548
|
-
const
|
|
6812
|
+
const debug11 = process.env.RANGO_POKE_DEBUG === "1";
|
|
5549
6813
|
const triggerReload = (source) => {
|
|
5550
6814
|
server.hot.send({ type: "full-reload", path: "*" });
|
|
5551
6815
|
server.config.logger.info(` browser reload (${source})`, {
|
|
@@ -5578,7 +6842,7 @@ function poke() {
|
|
|
5578
6842
|
lines.pop();
|
|
5579
6843
|
return lines;
|
|
5580
6844
|
};
|
|
5581
|
-
if (
|
|
6845
|
+
if (debug11) {
|
|
5582
6846
|
server.config.logger.info(
|
|
5583
6847
|
` poke debug enabled (isTTY=${stdin.isTTY ? "yes" : "no"}, isRaw=${stdin.isTTY ? stdin.isRaw ? "yes" : "no" : "n/a"})`,
|
|
5584
6848
|
{ timestamp: true }
|
|
@@ -5591,7 +6855,7 @@ function poke() {
|
|
|
5591
6855
|
);
|
|
5592
6856
|
}
|
|
5593
6857
|
const onData = (data) => {
|
|
5594
|
-
if (
|
|
6858
|
+
if (debug11) {
|
|
5595
6859
|
server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
|
|
5596
6860
|
timestamp: true
|
|
5597
6861
|
});
|