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