@rangojs/router 0.0.0-experimental.107 → 0.0.0-experimental.109
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 +4 -4
- package/dist/bin/rango.js +16 -16
- package/dist/vite/index.js +146 -150
- package/package.json +6 -6
- package/skills/hooks/SKILL.md +2 -0
- package/skills/links/SKILL.md +13 -1
- package/skills/loader/SKILL.md +1 -1
- package/skills/middleware/SKILL.md +3 -3
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/prerender/SKILL.md +13 -13
- package/skills/rango/SKILL.md +9 -0
- package/skills/response-routes/SKILL.md +58 -9
- package/skills/router-setup/SKILL.md +3 -3
- package/skills/typesafety/SKILL.md +273 -31
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +117 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/react/location-state-shared.ts +3 -3
- package/src/browser/react/use-handle.ts +17 -9
- package/src/browser/rsc-router.tsx +14 -14
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/build/generate-manifest.ts +3 -3
- 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 +3 -3
- package/src/build/route-types/router-processing.ts +4 -4
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/client.tsx +4 -7
- package/src/errors.ts +1 -1
- package/src/handle.ts +2 -2
- package/src/href-client.ts +136 -19
- package/src/index.rsc.ts +4 -4
- package/src/index.ts +2 -2
- package/src/loader.rsc.ts +1 -1
- package/src/loader.ts +1 -1
- package/src/prerender.ts +4 -4
- package/src/route-definition/dsl-helpers.ts +2 -2
- package/src/route-definition/helpers-types.ts +2 -2
- package/src/router/error-handling.ts +1 -1
- package/src/router/lazy-includes.ts +2 -2
- package/src/router/metrics.ts +1 -1
- package/src/router/middleware-types.ts +1 -1
- package/src/router/prerender-match.ts +1 -1
- package/src/router/router-interfaces.ts +34 -28
- package/src/router/router-options.ts +1 -1
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +2 -2
- package/src/router/segment-resolution/revalidation.ts +2 -2
- package/src/router.ts +13 -16
- package/src/rsc/handler-context.ts +2 -2
- package/src/rsc/index.ts +1 -1
- package/src/rsc/types.ts +2 -2
- package/src/search-params.ts +4 -4
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +16 -16
- package/src/static-handler.ts +1 -1
- package/src/types/global-namespace.ts +39 -26
- package/src/types/handler-context.ts +3 -3
- package/src/urls/path-helper-types.ts +2 -2
- package/src/urls/pattern-types.ts +34 -0
- package/src/urls/type-extraction.ts +6 -1
- package/src/use-loader.tsx +6 -4
- package/src/vite/discovery/bundle-postprocess.ts +6 -6
- package/src/vite/discovery/discover-routers.ts +3 -3
- package/src/vite/discovery/discovery-errors.ts +1 -1
- package/src/vite/discovery/prerender-collection.ts +19 -25
- package/src/vite/discovery/route-types-writer.ts +3 -3
- package/src/vite/discovery/state.ts +4 -4
- package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -1
- package/src/vite/plugins/expose-action-id.ts +2 -2
- package/src/vite/plugins/expose-id-utils.ts +12 -8
- package/src/vite/plugins/expose-ids/export-analysis.ts +33 -9
- package/src/vite/plugins/expose-internal-ids.ts +1 -1
- package/src/vite/plugins/performance-tracks.ts +12 -16
- package/src/vite/plugins/use-cache-transform.ts +1 -1
- package/src/vite/plugins/version-plugin.ts +2 -2
- package/src/vite/plugins/virtual-entries.ts +2 -2
- package/src/vite/rango.ts +11 -11
- package/src/vite/router-discovery.ts +26 -29
- package/src/vite/utils/ast-handler-extract.ts +15 -15
- package/src/vite/utils/bundle-analysis.ts +4 -2
- package/src/vite/utils/forward-user-plugins.ts +46 -17
- package/src/vite/utils/shared-utils.ts +26 -22
|
@@ -103,7 +103,7 @@ function ensureCloudflareProtocolLoaderRegistered(): void {
|
|
|
103
103
|
// register() requires Node 18.19+ / 20.6+. Older Node still has the
|
|
104
104
|
// Vite transform as primary defense.
|
|
105
105
|
console.warn(
|
|
106
|
-
`[
|
|
106
|
+
`[rango] Could not register Node ESM loader hook for cloudflare:* imports (${err?.message ?? err}). Falling back to Vite transform only.`,
|
|
107
107
|
);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
@@ -141,9 +141,8 @@ async function createTempRscServer(
|
|
|
141
141
|
const resolveConfig = runnerConfig?.resolve ?? {
|
|
142
142
|
alias: state.userResolveAlias,
|
|
143
143
|
};
|
|
144
|
-
const
|
|
145
|
-
jsx: "automatic",
|
|
146
|
-
jsxImportSource: "react",
|
|
144
|
+
const oxcConfig = runnerConfig?.oxc ?? {
|
|
145
|
+
jsx: { runtime: "automatic", importSource: "react" },
|
|
147
146
|
};
|
|
148
147
|
return createViteServer({
|
|
149
148
|
root: state.projectRoot,
|
|
@@ -153,7 +152,7 @@ async function createTempRscServer(
|
|
|
153
152
|
logLevel: "silent",
|
|
154
153
|
resolve: resolveConfig,
|
|
155
154
|
...(runnerConfig?.define ? { define: runnerConfig.define } : {}),
|
|
156
|
-
|
|
155
|
+
oxc: oxcConfig as any,
|
|
157
156
|
...(options.cacheDir && { cacheDir: options.cacheDir }),
|
|
158
157
|
plugins: [
|
|
159
158
|
rsc({
|
|
@@ -203,7 +202,7 @@ async function resolveBuildEnv(
|
|
|
203
202
|
if (option === "auto") {
|
|
204
203
|
if (factoryCtx.preset !== "cloudflare") {
|
|
205
204
|
throw new Error(
|
|
206
|
-
'[
|
|
205
|
+
'[rango] buildEnv: "auto" is only supported with preset: "cloudflare". ' +
|
|
207
206
|
"Use a factory function or plain object for other presets.",
|
|
208
207
|
);
|
|
209
208
|
}
|
|
@@ -225,7 +224,7 @@ async function resolveBuildEnv(
|
|
|
225
224
|
};
|
|
226
225
|
} catch (err: any) {
|
|
227
226
|
throw new Error(
|
|
228
|
-
'[
|
|
227
|
+
'[rango] buildEnv: "auto" requires wrangler to be installed.\n' +
|
|
229
228
|
`Install it with: pnpm add -D wrangler\n${err.message}`,
|
|
230
229
|
);
|
|
231
230
|
}
|
|
@@ -277,7 +276,7 @@ async function releaseBuildEnv(s: DiscoveryState): Promise<void> {
|
|
|
277
276
|
try {
|
|
278
277
|
await s.buildEnvDispose();
|
|
279
278
|
} catch (err: any) {
|
|
280
|
-
console.warn(`[
|
|
279
|
+
console.warn(`[rango] buildEnv dispose failed: ${err.message}`);
|
|
281
280
|
}
|
|
282
281
|
s.buildEnvDispose = null;
|
|
283
282
|
}
|
|
@@ -330,12 +329,14 @@ export function createRouterDiscoveryPlugin(
|
|
|
330
329
|
viteMode = config.mode;
|
|
331
330
|
// Capture user's resolve aliases for the temp server
|
|
332
331
|
s.userResolveAlias = config.resolve.alias;
|
|
333
|
-
// Capture the data-only resolution config (resolve.*, define,
|
|
334
|
-
//
|
|
335
|
-
//
|
|
336
|
-
// Without this,
|
|
337
|
-
//
|
|
338
|
-
//
|
|
332
|
+
// Capture the data-only resolution config (resolve.*, define, oxc) and
|
|
333
|
+
// the user's resolution plugins (resolveId/load) so the discovery temp
|
|
334
|
+
// server resolves modules the same way the real environment does.
|
|
335
|
+
// Without this, both flavors of user resolution are absent during
|
|
336
|
+
// discovery/prerender/static rendering even though they apply at request
|
|
337
|
+
// time: third-party resolvers (e.g. vite-tsconfig-paths, forwarded as
|
|
338
|
+
// plugins) and Vite 8's native resolve.tsconfigPaths (forwarded in the
|
|
339
|
+
// data slice). See utils/forward-user-plugins.ts.
|
|
339
340
|
s.userRunnerConfig = pickForwardedRunnerConfig(config);
|
|
340
341
|
s.userResolvePlugins = selectForwardableResolvePlugins(
|
|
341
342
|
config.plugins as any,
|
|
@@ -543,9 +544,7 @@ export function createRouterDiscoveryPlugin(
|
|
|
543
544
|
"getOrCreateTempServer: FAILED message=%s",
|
|
544
545
|
err.message,
|
|
545
546
|
);
|
|
546
|
-
console.warn(
|
|
547
|
-
`[rsc-router] Failed to create temp runner: ${err.message}`,
|
|
548
|
-
);
|
|
547
|
+
console.warn(`[rango] Failed to create temp runner: ${err.message}`);
|
|
549
548
|
}
|
|
550
549
|
return null;
|
|
551
550
|
}
|
|
@@ -684,7 +683,7 @@ export function createRouterDiscoveryPlugin(
|
|
|
684
683
|
}
|
|
685
684
|
} catch (err: any) {
|
|
686
685
|
console.warn(
|
|
687
|
-
`[
|
|
686
|
+
`[rango] Cloudflare dev discovery failed: ${err.message}\n${err.stack}`,
|
|
688
687
|
);
|
|
689
688
|
}
|
|
690
689
|
|
|
@@ -736,7 +735,7 @@ export function createRouterDiscoveryPlugin(
|
|
|
736
735
|
);
|
|
737
736
|
} catch (err: any) {
|
|
738
737
|
console.warn(
|
|
739
|
-
`[
|
|
738
|
+
`[rango] Router discovery failed: ${err.message}\n${err.stack}`,
|
|
740
739
|
);
|
|
741
740
|
} finally {
|
|
742
741
|
debugDiscovery?.(
|
|
@@ -851,7 +850,7 @@ export function createRouterDiscoveryPlugin(
|
|
|
851
850
|
registry = serverMod.RouterRegistry ?? null;
|
|
852
851
|
} catch (err: any) {
|
|
853
852
|
console.warn(
|
|
854
|
-
`[
|
|
853
|
+
`[rango] Dev prerender module refresh failed: ${err.message}`,
|
|
855
854
|
);
|
|
856
855
|
res.statusCode = 500;
|
|
857
856
|
res.end(`Prerender handler error: ${err.message}`);
|
|
@@ -917,7 +916,7 @@ export function createRouterDiscoveryPlugin(
|
|
|
917
916
|
return;
|
|
918
917
|
} catch (err: any) {
|
|
919
918
|
console.warn(
|
|
920
|
-
`[
|
|
919
|
+
`[rango] Dev prerender failed for ${pathname}: ${err.message}`,
|
|
921
920
|
);
|
|
922
921
|
}
|
|
923
922
|
}
|
|
@@ -1031,7 +1030,7 @@ export function createRouterDiscoveryPlugin(
|
|
|
1031
1030
|
at: Date.now(),
|
|
1032
1031
|
};
|
|
1033
1032
|
console.warn(
|
|
1034
|
-
`[
|
|
1033
|
+
`[rango] Runtime re-discovery failed: ${err.message}`,
|
|
1035
1034
|
);
|
|
1036
1035
|
debugDiscovery?.(
|
|
1037
1036
|
"hmr: lastDiscoveryError set (%s) — manifest preserved at last-good; recovery mode active (any in-scan source change will trigger rediscovery)",
|
|
@@ -1074,9 +1073,7 @@ export function createRouterDiscoveryPlugin(
|
|
|
1074
1073
|
}
|
|
1075
1074
|
}
|
|
1076
1075
|
} catch (err: any) {
|
|
1077
|
-
console.error(
|
|
1078
|
-
`[rsc-router] Route regeneration error: ${err.message}`,
|
|
1079
|
-
);
|
|
1076
|
+
console.error(`[rango] Route regeneration error: ${err.message}`);
|
|
1080
1077
|
}
|
|
1081
1078
|
debugDiscovery?.(
|
|
1082
1079
|
"watcher: regenerated gen files (%sms)",
|
|
@@ -1088,7 +1085,7 @@ export function createRouterDiscoveryPlugin(
|
|
|
1088
1085
|
if (s.perRouterManifests.length > 0) {
|
|
1089
1086
|
refreshRuntimeDiscovery().catch((err: any) => {
|
|
1090
1087
|
console.warn(
|
|
1091
|
-
`[
|
|
1088
|
+
`[rango] Runtime re-discovery error: ${err.message}`,
|
|
1092
1089
|
);
|
|
1093
1090
|
// Even on error, unblock the gate so workerd's reload
|
|
1094
1091
|
// doesn't hang indefinitely against the previous manifest.
|
|
@@ -1259,7 +1256,7 @@ export function createRouterDiscoveryPlugin(
|
|
|
1259
1256
|
const rscEnv = (tempServer.environments as any)?.rsc;
|
|
1260
1257
|
if (!rscEnv?.runner) {
|
|
1261
1258
|
console.warn(
|
|
1262
|
-
"[
|
|
1259
|
+
"[rango] RSC environment runner not available during build, skipping manifest generation",
|
|
1263
1260
|
);
|
|
1264
1261
|
return;
|
|
1265
1262
|
}
|
|
@@ -1302,7 +1299,7 @@ export function createRouterDiscoveryPlugin(
|
|
|
1302
1299
|
.filter(Boolean)
|
|
1303
1300
|
.join("\n");
|
|
1304
1301
|
throw new Error(
|
|
1305
|
-
`[
|
|
1302
|
+
`[rango] Build-time router discovery failed:\n${details}`,
|
|
1306
1303
|
{ cause: err },
|
|
1307
1304
|
);
|
|
1308
1305
|
} finally {
|
|
@@ -1330,7 +1327,7 @@ export function createRouterDiscoveryPlugin(
|
|
|
1330
1327
|
// `consumeSelfGenWrite` inside `maybeHandleGeneratedRouteFileMutation`),
|
|
1331
1328
|
// AND vite's own HMR pipeline (which invalidates the gen file's
|
|
1332
1329
|
// importers and triggers a second workerd full reload — visible to the
|
|
1333
|
-
// user as a duplicate "[
|
|
1330
|
+
// user as a duplicate "[Rango] HMR: version changed" on the client).
|
|
1334
1331
|
//
|
|
1335
1332
|
// `peekSelfGenWrite` is the authoritative filter: its map only contains
|
|
1336
1333
|
// paths that `markSelfGenWrite` has registered, so it natively works
|
|
@@ -48,7 +48,7 @@ function findImportInsertionPos(
|
|
|
48
48
|
): number {
|
|
49
49
|
let program: ProgramNode;
|
|
50
50
|
try {
|
|
51
|
-
program = parseAst(code, {
|
|
51
|
+
program = parseAst(code, { lang: "tsx" });
|
|
52
52
|
} catch {
|
|
53
53
|
return 0;
|
|
54
54
|
}
|
|
@@ -127,7 +127,7 @@ export function findHandlerCalls(
|
|
|
127
127
|
): HandlerCallSite[] {
|
|
128
128
|
let program: ProgramNode;
|
|
129
129
|
try {
|
|
130
|
-
program = parseAst(code, {
|
|
130
|
+
program = parseAst(code, { lang: "tsx" });
|
|
131
131
|
} catch {
|
|
132
132
|
return [];
|
|
133
133
|
}
|
|
@@ -239,7 +239,7 @@ export function getImportedLocalNames(
|
|
|
239
239
|
parseAst: (code: string, options?: any) => ProgramNode,
|
|
240
240
|
): Set<string> {
|
|
241
241
|
try {
|
|
242
|
-
const program = parseAst(code, {
|
|
242
|
+
const program = parseAst(code, { lang: "tsx" });
|
|
243
243
|
return getImportedLocalNamesFromProgram(program, importedName);
|
|
244
244
|
} catch {
|
|
245
245
|
return new Set<string>();
|
|
@@ -256,7 +256,7 @@ export function extractImportDeclarations(
|
|
|
256
256
|
): string[] {
|
|
257
257
|
let program: ProgramNode;
|
|
258
258
|
try {
|
|
259
|
-
program = parseAst(code, {
|
|
259
|
+
program = parseAst(code, { lang: "tsx" });
|
|
260
260
|
} catch {
|
|
261
261
|
return [];
|
|
262
262
|
}
|
|
@@ -380,7 +380,7 @@ export function extractModuleLevelDeclarations(
|
|
|
380
380
|
): string[] {
|
|
381
381
|
let program: ProgramNode;
|
|
382
382
|
try {
|
|
383
|
-
program = parseAst(code, {
|
|
383
|
+
program = parseAst(code, { lang: "tsx" });
|
|
384
384
|
} catch {
|
|
385
385
|
return [];
|
|
386
386
|
}
|
|
@@ -468,19 +468,19 @@ export function transformInlineHandlers(
|
|
|
468
468
|
handlerNames,
|
|
469
469
|
);
|
|
470
470
|
|
|
471
|
-
// Track line occurrences for same-line collision handling
|
|
472
|
-
const lineCounts = new Map<number, number>();
|
|
473
|
-
|
|
474
471
|
// Collect all import statements to prepend
|
|
475
472
|
const importStatements: string[] = [];
|
|
476
473
|
|
|
477
|
-
for (const site of inlineSites) {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
474
|
+
for (const [siteIndex, site] of inlineSites.entries()) {
|
|
475
|
+
// Key the extracted handler on its source-order index (per fnName), NOT its
|
|
476
|
+
// line number. The id flows into BOTH the export name and the virtual module
|
|
477
|
+
// path (which hashId hashes for the runtime $$id), and line numbers shift
|
|
478
|
+
// between the prerender and production build contexts. The index is invariant
|
|
479
|
+
// to those shifts, keeping the prerender manifest key == the runtime id.
|
|
480
|
+
const hash = hashInlineId(filePath, fnName, siteIndex);
|
|
482
481
|
const exportName = `__sh_${hash}`;
|
|
483
|
-
const
|
|
482
|
+
const idSuffix = `${filePath}:${fnName}:${siteIndex}`;
|
|
483
|
+
const virtualId = `\0${virtualPrefix}${idSuffix}`;
|
|
484
484
|
|
|
485
485
|
// Extract the full handler call expression text
|
|
486
486
|
const handlerCode = code.slice(site.callStart, site.callEnd);
|
|
@@ -498,7 +498,7 @@ export function transformInlineHandlers(
|
|
|
498
498
|
s.overwrite(site.callStart, site.callEnd, exportName);
|
|
499
499
|
|
|
500
500
|
// Build the import specifier for this virtual module
|
|
501
|
-
const importId = `${virtualPrefix}${
|
|
501
|
+
const importId = `${virtualPrefix}${idSuffix}`;
|
|
502
502
|
importStatements.push(`import { ${exportName} } from "${importId}";`);
|
|
503
503
|
}
|
|
504
504
|
|
|
@@ -59,7 +59,7 @@ export function extractHandlerExportsFromChunk(
|
|
|
59
59
|
if (detectPassthrough) {
|
|
60
60
|
const eFnName = escapeRegExp(fnName);
|
|
61
61
|
const callStartRe = new RegExp(
|
|
62
|
-
`const\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`,
|
|
62
|
+
`(?:const|let|var)\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`,
|
|
63
63
|
);
|
|
64
64
|
const callStart = callStartRe.exec(chunkCode);
|
|
65
65
|
if (callStart) {
|
|
@@ -98,8 +98,10 @@ export function evictHandlerCode(
|
|
|
98
98
|
if (passthrough) continue;
|
|
99
99
|
|
|
100
100
|
const eName = escapeRegExp(name);
|
|
101
|
+
// Match const/let/var: Rolldown (Vite 8) emits top-level bindings in the
|
|
102
|
+
// non-minified RSC bundle as `var`, whereas Rollup used `const`.
|
|
101
103
|
const callStartRe = new RegExp(
|
|
102
|
-
`const\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`,
|
|
104
|
+
`(?:const|let|var)\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`,
|
|
103
105
|
);
|
|
104
106
|
const startMatch = callStartRe.exec(modified);
|
|
105
107
|
if (!startMatch) continue;
|
|
@@ -4,14 +4,20 @@
|
|
|
4
4
|
* The discovery temp server (createTempRscServer) runs the user's handler
|
|
5
5
|
* graph through a throwaway Node Vite server built with `configFile: false`.
|
|
6
6
|
* Without help, that server only sees a fixed Rango-owned plugin set, so any
|
|
7
|
-
* user resolution
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* user resolution is absent during discovery, prerender, and static handler
|
|
8
|
+
* rendering — even though it applies at request time. Two flavors of user
|
|
9
|
+
* resolution must be carried across:
|
|
10
|
+
*
|
|
11
|
+
* - Third-party resolveId plugins (e.g. vite-tsconfig-paths) — forwarded as
|
|
12
|
+
* plugin instances, see selectForwardableResolvePlugins.
|
|
13
|
+
* - Native config-driven resolution, including Vite 8's built-in
|
|
14
|
+
* `resolve.tsconfigPaths` (which supersedes vite-tsconfig-paths) — forwarded
|
|
15
|
+
* as the data slice, see pickForwardedRunnerConfig.
|
|
10
16
|
*
|
|
11
17
|
* These helpers extract the resolution-relevant slice of the user's resolved
|
|
12
|
-
* config (resolve.*, define,
|
|
13
|
-
*
|
|
14
|
-
*
|
|
18
|
+
* config (resolve.*, define, oxc) and forward the user's resolution plugins
|
|
19
|
+
* into the temp server so discovery resolves modules the same way the real
|
|
20
|
+
* environment does.
|
|
15
21
|
*/
|
|
16
22
|
|
|
17
23
|
import type { Plugin, ResolvedConfig, UserConfig } from "vite";
|
|
@@ -120,22 +126,31 @@ export function selectForwardableResolvePlugins(
|
|
|
120
126
|
/**
|
|
121
127
|
* The resolution-relevant slice of the user's resolved config that is plain
|
|
122
128
|
* data (no plugin re-execution): everything under `resolve` that influences
|
|
123
|
-
* how specifiers map to files, plus `define` and `
|
|
129
|
+
* how specifiers map to files, plus `define` and `oxc` so transforms and
|
|
124
130
|
* compile-time constants match request time.
|
|
125
131
|
*/
|
|
126
132
|
export interface ForwardedRunnerConfig {
|
|
127
133
|
resolve: UserConfig["resolve"];
|
|
128
134
|
define: UserConfig["define"];
|
|
129
|
-
|
|
135
|
+
oxc: UserConfig["oxc"];
|
|
130
136
|
}
|
|
131
137
|
|
|
132
138
|
/**
|
|
133
139
|
* Extract the data-only config slice to mirror into the discovery temp server.
|
|
134
140
|
* `alias` is included here so callers no longer need to thread it separately.
|
|
135
141
|
*
|
|
136
|
-
* `
|
|
137
|
-
*
|
|
138
|
-
*
|
|
142
|
+
* `tsconfigPaths` is forwarded so Vite 8's native tsconfig `paths` resolution
|
|
143
|
+
* (a top-level `resolve` flag, off by default) reaches the temp server. The
|
|
144
|
+
* server is created with `configFile: false` and an explicit, allowlisted
|
|
145
|
+
* resolve slice, so a flag that is not copied here is simply absent during
|
|
146
|
+
* discovery — which would make path-aliased imports fail at prerender/static
|
|
147
|
+
* time the same way unforwarded resolveId plugins did (issue #500).
|
|
148
|
+
*
|
|
149
|
+
* `oxc` keeps the user's options but always pins the RSC-required JSX runtime
|
|
150
|
+
* (automatic, react), since the temp server compiles the handler graph as
|
|
151
|
+
* React server components regardless of the user's app-level JSX config. Vite 8
|
|
152
|
+
* replaced the deprecated `esbuild` transform option with `oxc`, so we read and
|
|
153
|
+
* forward `oxc` exclusively — no `esbuild` field is touched.
|
|
139
154
|
*/
|
|
140
155
|
export function pickForwardedRunnerConfig(
|
|
141
156
|
config: ResolvedConfig,
|
|
@@ -149,16 +164,30 @@ export function pickForwardedRunnerConfig(
|
|
|
149
164
|
if (r.extensions !== undefined) resolve.extensions = r.extensions;
|
|
150
165
|
if (r.preserveSymlinks !== undefined)
|
|
151
166
|
resolve.preserveSymlinks = r.preserveSymlinks;
|
|
167
|
+
if (r.tsconfigPaths !== undefined) resolve.tsconfigPaths = r.tsconfigPaths;
|
|
152
168
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
169
|
+
// Pin the RSC JSX runtime on top of the user's oxc options. The user's
|
|
170
|
+
// jsx sub-options (e.g. `development`) are preserved when present; only
|
|
171
|
+
// `runtime`/`importSource` are forced to the values the RSC compile needs.
|
|
172
|
+
const userOxc = config.oxc;
|
|
173
|
+
const userJsx =
|
|
174
|
+
userOxc &&
|
|
175
|
+
typeof userOxc === "object" &&
|
|
176
|
+
typeof userOxc.jsx === "object" &&
|
|
177
|
+
userOxc.jsx !== null
|
|
178
|
+
? userOxc.jsx
|
|
179
|
+
: {};
|
|
180
|
+
const oxc: UserConfig["oxc"] =
|
|
181
|
+
userOxc && typeof userOxc === "object"
|
|
182
|
+
? {
|
|
183
|
+
...userOxc,
|
|
184
|
+
jsx: { ...userJsx, runtime: "automatic", importSource: "react" },
|
|
185
|
+
}
|
|
186
|
+
: { jsx: { runtime: "automatic", importSource: "react" } };
|
|
158
187
|
|
|
159
188
|
return {
|
|
160
189
|
resolve,
|
|
161
190
|
define: config.define,
|
|
162
|
-
|
|
191
|
+
oxc,
|
|
163
192
|
};
|
|
164
193
|
}
|
|
@@ -6,39 +6,40 @@ import {
|
|
|
6
6
|
VIRTUAL_ENTRY_BROWSER,
|
|
7
7
|
VIRTUAL_ENTRY_SSR,
|
|
8
8
|
getVirtualEntryRSC,
|
|
9
|
+
getVirtualVersionContent,
|
|
9
10
|
VIRTUAL_IDS,
|
|
10
11
|
} from "../plugins/virtual-entries.js";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* Rolldown plugin to provide the version virtual module during dependency
|
|
15
|
+
* optimization. Vite 8 optimizes deps with Rolldown (a Rollup-style plugin
|
|
16
|
+
* pipeline that is separate from the main plugin set), so this is a
|
|
17
|
+
* resolveId/load plugin under optimizeDeps.rolldownOptions. Any dep pulled into
|
|
18
|
+
* optimization that imports the version virtual module gets a "dev" stub here;
|
|
19
|
+
* the real VERSION is injected into runtime modules by the version plugin.
|
|
16
20
|
*/
|
|
17
|
-
const
|
|
21
|
+
const versionRolldownPlugin = {
|
|
18
22
|
name: "@rangojs/router-version",
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
loader: "js",
|
|
29
|
-
}),
|
|
30
|
-
);
|
|
23
|
+
resolveId(id: string): string | undefined {
|
|
24
|
+
if (id === VIRTUAL_IDS.version) return "\0" + VIRTUAL_IDS.version;
|
|
25
|
+
return undefined;
|
|
26
|
+
},
|
|
27
|
+
load(id: string): string | undefined {
|
|
28
|
+
if (id === "\0" + VIRTUAL_IDS.version) {
|
|
29
|
+
return getVirtualVersionContent("dev");
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
31
32
|
},
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
|
-
* Shared
|
|
36
|
-
* Includes the version stub plugin
|
|
36
|
+
* Shared Rolldown options for dependency optimization (Vite 8).
|
|
37
|
+
* Includes the version stub plugin and the performance-tracks RSDW patch.
|
|
37
38
|
*/
|
|
38
|
-
export const
|
|
39
|
+
export const sharedRolldownOptions: {
|
|
39
40
|
plugins: any[];
|
|
40
41
|
} = {
|
|
41
|
-
plugins: [
|
|
42
|
+
plugins: [versionRolldownPlugin, performanceTracksOptimizeDepsPlugin()],
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
/**
|
|
@@ -108,7 +109,9 @@ export function createVirtualEntriesPlugin(
|
|
|
108
109
|
* - "use client" directives: handled by the RSC plugin, not relevant to Rollup
|
|
109
110
|
* - sourcemap errors: caused by "use client" directive at line 1:0 confusing sourcemap resolution
|
|
110
111
|
* - sourcemap incomplete: plugins that transform without generating sourcemaps (router + RSC plugin)
|
|
111
|
-
* - dynamic/static mixed imports: expected for router internals (e.g. request-context, cache-scope)
|
|
112
|
+
* - dynamic/static mixed imports: expected for router internals (e.g. request-context, cache-scope).
|
|
113
|
+
* Under Rolldown (Vite 8) this surfaces as the INEFFECTIVE_DYNAMIC_IMPORT code emitted directly
|
|
114
|
+
* by the bundler, rather than the vite:reporter message handled below (Rollup/Vite 7 shape).
|
|
112
115
|
* - empty bundle: @vitejs/plugin-rsc scan build (step 1/5) produces an empty "index" chunk
|
|
113
116
|
* because the RSC entry is fully externalized during client-reference analysis
|
|
114
117
|
*/
|
|
@@ -119,7 +122,8 @@ export function onwarn(
|
|
|
119
122
|
if (
|
|
120
123
|
warning.code === "MODULE_LEVEL_DIRECTIVE" ||
|
|
121
124
|
warning.code === "SOURCEMAP_ERROR" ||
|
|
122
|
-
warning.code === "EMPTY_BUNDLE"
|
|
125
|
+
warning.code === "EMPTY_BUNDLE" ||
|
|
126
|
+
warning.code === "INEFFECTIVE_DYNAMIC_IMPORT"
|
|
123
127
|
) {
|
|
124
128
|
return;
|
|
125
129
|
}
|