@rangojs/router 0.0.0-experimental.19 → 0.0.0-experimental.1fa245e2
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/{CLAUDE.md → AGENTS.md} +4 -0
- package/README.md +122 -30
- package/dist/bin/rango.js +245 -63
- package/dist/vite/index.js +859 -418
- package/package.json +3 -3
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +32 -0
- package/skills/caching/SKILL.md +49 -8
- package/skills/document-cache/SKILL.md +2 -2
- package/skills/hooks/SKILL.md +33 -31
- package/skills/host-router/SKILL.md +218 -0
- package/skills/links/SKILL.md +3 -1
- package/skills/loader/SKILL.md +72 -22
- package/skills/middleware/SKILL.md +2 -0
- package/skills/parallel/SKILL.md +126 -0
- package/skills/prerender/SKILL.md +112 -70
- package/skills/rango/SKILL.md +0 -1
- package/skills/route/SKILL.md +34 -4
- package/skills/router-setup/SKILL.md +95 -5
- package/skills/typesafety/SKILL.md +35 -23
- package/src/__internal.ts +92 -0
- package/src/bin/rango.ts +18 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +5 -0
- package/src/browser/link-interceptor.ts +4 -0
- package/src/browser/navigation-bridge.ts +114 -18
- package/src/browser/navigation-client.ts +126 -44
- package/src/browser/navigation-store.ts +43 -8
- package/src/browser/navigation-transaction.ts +11 -9
- package/src/browser/partial-update.ts +80 -15
- package/src/browser/prefetch/cache.ts +166 -27
- package/src/browser/prefetch/fetch.ts +52 -39
- package/src/browser/prefetch/policy.ts +6 -0
- package/src/browser/prefetch/queue.ts +92 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/react/Link.tsx +70 -14
- package/src/browser/react/NavigationProvider.tsx +40 -4
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/use-handle.ts +9 -58
- package/src/browser/react/use-router.ts +21 -8
- package/src/browser/rsc-router.tsx +143 -59
- package/src/browser/scroll-restoration.ts +41 -42
- package/src/browser/segment-reconciler.ts +6 -1
- package/src/browser/server-action-bridge.ts +454 -436
- package/src/browser/types.ts +60 -5
- package/src/build/generate-manifest.ts +6 -6
- package/src/build/generate-route-types.ts +5 -0
- package/src/build/route-trie.ts +19 -3
- package/src/build/route-types/include-resolution.ts +8 -1
- package/src/build/route-types/router-processing.ts +346 -87
- package/src/build/route-types/scan-filter.ts +8 -1
- package/src/cache/cache-runtime.ts +15 -11
- package/src/cache/cache-scope.ts +48 -7
- package/src/cache/cf/cf-cache-store.ts +453 -11
- package/src/cache/cf/index.ts +5 -1
- package/src/cache/document-cache.ts +17 -7
- package/src/cache/index.ts +1 -0
- package/src/cache/taint.ts +55 -0
- package/src/client.rsc.tsx +2 -1
- package/src/client.tsx +3 -102
- package/src/context-var.ts +72 -2
- package/src/debug.ts +2 -2
- package/src/handle.ts +40 -0
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/host/index.ts +0 -3
- package/src/index.rsc.ts +8 -37
- package/src/index.ts +40 -66
- package/src/prerender/store.ts +57 -15
- package/src/prerender.ts +138 -77
- package/src/reverse.ts +22 -1
- package/src/route-definition/dsl-helpers.ts +73 -25
- package/src/route-definition/helpers-types.ts +10 -6
- package/src/route-definition/index.ts +3 -3
- package/src/route-definition/redirect.ts +11 -3
- package/src/route-definition/resolve-handler-use.ts +149 -0
- package/src/route-map-builder.ts +7 -1
- package/src/route-types.ts +11 -0
- package/src/router/content-negotiation.ts +100 -1
- package/src/router/find-match.ts +4 -2
- package/src/router/handler-context.ts +108 -25
- package/src/router/intercept-resolution.ts +11 -4
- package/src/router/lazy-includes.ts +4 -1
- package/src/router/loader-resolution.ts +123 -11
- package/src/router/logging.ts +5 -2
- package/src/router/manifest.ts +9 -3
- package/src/router/match-api.ts +125 -190
- package/src/router/match-middleware/background-revalidation.ts +30 -2
- package/src/router/match-middleware/cache-lookup.ts +88 -16
- package/src/router/match-middleware/cache-store.ts +53 -10
- package/src/router/match-middleware/intercept-resolution.ts +9 -7
- package/src/router/match-middleware/segment-resolution.ts +61 -5
- package/src/router/match-result.ts +22 -15
- package/src/router/metrics.ts +238 -13
- package/src/router/middleware-types.ts +53 -12
- package/src/router/middleware.ts +172 -85
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +20 -5
- package/src/router/prerender-match.ts +114 -10
- package/src/router/preview-match.ts +30 -102
- package/src/router/request-classification.ts +310 -0
- package/src/router/revalidation.ts +27 -7
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +6 -1
- package/src/router/router-interfaces.ts +50 -5
- package/src/router/router-options.ts +50 -19
- package/src/router/segment-resolution/fresh.ts +200 -19
- package/src/router/segment-resolution/helpers.ts +30 -25
- package/src/router/segment-resolution/loader-cache.ts +1 -0
- package/src/router/segment-resolution/revalidation.ts +429 -301
- package/src/router/segment-wrappers.ts +2 -0
- package/src/router/trie-matching.ts +20 -2
- package/src/router/types.ts +1 -0
- package/src/router.ts +88 -15
- package/src/rsc/handler.ts +546 -359
- package/src/rsc/index.ts +0 -20
- package/src/rsc/manifest-init.ts +5 -1
- package/src/rsc/progressive-enhancement.ts +25 -8
- package/src/rsc/rsc-rendering.ts +35 -43
- package/src/rsc/server-action.ts +16 -10
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +10 -1
- package/src/search-params.ts +16 -13
- package/src/segment-system.tsx +140 -4
- package/src/server/context.ts +148 -16
- package/src/server/loader-registry.ts +9 -8
- package/src/server/request-context.ts +182 -34
- package/src/server.ts +6 -0
- package/src/ssr/index.tsx +4 -0
- package/src/static-handler.ts +18 -6
- package/src/theme/index.ts +4 -13
- package/src/types/cache-types.ts +4 -4
- package/src/types/handler-context.ts +149 -49
- package/src/types/loader-types.ts +36 -9
- package/src/types/route-config.ts +17 -8
- package/src/types/route-entry.ts +8 -1
- package/src/types/segments.ts +2 -5
- package/src/urls/path-helper-types.ts +9 -2
- package/src/urls/path-helper.ts +48 -13
- package/src/urls/pattern-types.ts +12 -0
- package/src/urls/response-types.ts +16 -6
- package/src/use-loader.tsx +73 -4
- package/src/vite/discovery/bundle-postprocess.ts +61 -89
- package/src/vite/discovery/discover-routers.ts +23 -5
- package/src/vite/discovery/prerender-collection.ts +48 -15
- package/src/vite/discovery/state.ts +17 -13
- package/src/vite/index.ts +8 -3
- package/src/vite/plugin-types.ts +51 -79
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/expose-action-id.ts +1 -3
- package/src/vite/plugins/performance-tracks.ts +88 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/version-plugin.ts +13 -1
- package/src/vite/rango.ts +174 -211
- package/src/vite/router-discovery.ts +169 -42
- package/src/vite/utils/banner.ts +3 -3
- package/src/vite/utils/prerender-utils.ts +78 -0
- package/src/vite/utils/shared-utils.ts +3 -2
- package/skills/testing/SKILL.md +0 -226
- package/src/route-definition/route-function.ts +0 -119
|
@@ -10,9 +10,12 @@ import type { Plugin } from "vite";
|
|
|
10
10
|
import { createServer as createViteServer } from "vite";
|
|
11
11
|
import { resolve } from "node:path";
|
|
12
12
|
import { readFileSync } from "node:fs";
|
|
13
|
+
import { createRequire } from "node:module";
|
|
14
|
+
import { pathToFileURL } from "node:url";
|
|
13
15
|
import {
|
|
16
|
+
formatNestedRouterConflictError,
|
|
17
|
+
findNestedRouterConflict,
|
|
14
18
|
findRouterFiles,
|
|
15
|
-
createScanFilter,
|
|
16
19
|
} from "../build/generate-route-types.js";
|
|
17
20
|
import { createVersionPlugin } from "./plugins/version-plugin.js";
|
|
18
21
|
import { createVirtualStubPlugin } from "./plugins/virtual-stub-plugin.js";
|
|
@@ -40,6 +43,7 @@ import {
|
|
|
40
43
|
generatePerRouterModule,
|
|
41
44
|
} from "./discovery/virtual-module-codegen.js";
|
|
42
45
|
import { postprocessBundle } from "./discovery/bundle-postprocess.js";
|
|
46
|
+
import { resetStagedBuildAssets } from "./utils/prerender-utils.js";
|
|
43
47
|
|
|
44
48
|
export { VIRTUAL_ROUTES_MANIFEST_ID };
|
|
45
49
|
|
|
@@ -92,6 +96,105 @@ async function createTempRscServer(
|
|
|
92
96
|
});
|
|
93
97
|
}
|
|
94
98
|
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// Build-Time Env Resolution
|
|
101
|
+
// ============================================================================
|
|
102
|
+
|
|
103
|
+
import type {
|
|
104
|
+
BuildEnvOption,
|
|
105
|
+
BuildEnvFactoryContext,
|
|
106
|
+
BuildEnvResult,
|
|
107
|
+
} from "./plugin-types.js";
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Resolve the buildEnv option into a concrete { env, dispose? } result.
|
|
111
|
+
* Handles all four input shapes: false, "auto", factory, plain object.
|
|
112
|
+
*/
|
|
113
|
+
async function resolveBuildEnv(
|
|
114
|
+
option: BuildEnvOption | undefined,
|
|
115
|
+
factoryCtx: BuildEnvFactoryContext,
|
|
116
|
+
): Promise<BuildEnvResult | null> {
|
|
117
|
+
if (!option) return null;
|
|
118
|
+
|
|
119
|
+
if (option === "auto") {
|
|
120
|
+
if (factoryCtx.preset !== "cloudflare") {
|
|
121
|
+
throw new Error(
|
|
122
|
+
'[rsc-router] buildEnv: "auto" is only supported with preset: "cloudflare". ' +
|
|
123
|
+
"Use a factory function or plain object for other presets.",
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
// Resolve wrangler from the user's project root (not the router package)
|
|
128
|
+
const userRequire = createRequire(
|
|
129
|
+
resolve(factoryCtx.root, "package.json"),
|
|
130
|
+
);
|
|
131
|
+
const wranglerPath = userRequire.resolve("wrangler");
|
|
132
|
+
const { getPlatformProxy } = (await import(
|
|
133
|
+
pathToFileURL(wranglerPath).href
|
|
134
|
+
)) as {
|
|
135
|
+
getPlatformProxy: (opts?: any) => Promise<any>;
|
|
136
|
+
};
|
|
137
|
+
const proxy = await getPlatformProxy();
|
|
138
|
+
return {
|
|
139
|
+
env: proxy.env as Record<string, unknown>,
|
|
140
|
+
dispose: proxy.dispose,
|
|
141
|
+
};
|
|
142
|
+
} catch (err: any) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
'[rsc-router] buildEnv: "auto" requires wrangler to be installed.\n' +
|
|
145
|
+
`Install it with: pnpm add -D wrangler\n${err.message}`,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (typeof option === "function") {
|
|
151
|
+
return await option(factoryCtx);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Plain object
|
|
155
|
+
return { env: option };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Acquire build-time env bindings and store on discovery state.
|
|
160
|
+
* Returns true if env was acquired, false if buildEnv is disabled.
|
|
161
|
+
*/
|
|
162
|
+
async function acquireBuildEnv(
|
|
163
|
+
s: DiscoveryState,
|
|
164
|
+
command: "serve" | "build",
|
|
165
|
+
mode: string,
|
|
166
|
+
): Promise<boolean> {
|
|
167
|
+
const option = s.opts?.buildEnv;
|
|
168
|
+
if (!option) return false;
|
|
169
|
+
|
|
170
|
+
const result = await resolveBuildEnv(option, {
|
|
171
|
+
root: s.projectRoot,
|
|
172
|
+
mode,
|
|
173
|
+
command,
|
|
174
|
+
preset: s.opts?.preset ?? "node",
|
|
175
|
+
});
|
|
176
|
+
if (!result) return false;
|
|
177
|
+
|
|
178
|
+
s.resolvedBuildEnv = result.env;
|
|
179
|
+
s.buildEnvDispose = result.dispose ?? null;
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Release build-time env resources and clear state.
|
|
185
|
+
*/
|
|
186
|
+
async function releaseBuildEnv(s: DiscoveryState): Promise<void> {
|
|
187
|
+
if (s.buildEnvDispose) {
|
|
188
|
+
try {
|
|
189
|
+
await s.buildEnvDispose();
|
|
190
|
+
} catch (err: any) {
|
|
191
|
+
console.warn(`[rsc-router] buildEnv dispose failed: ${err.message}`);
|
|
192
|
+
}
|
|
193
|
+
s.buildEnvDispose = null;
|
|
194
|
+
}
|
|
195
|
+
s.resolvedBuildEnv = undefined;
|
|
196
|
+
}
|
|
197
|
+
|
|
95
198
|
/**
|
|
96
199
|
* Plugin that discovers router instances at dev/build time via the RSC environment.
|
|
97
200
|
*
|
|
@@ -109,6 +212,8 @@ export function createRouterDiscoveryPlugin(
|
|
|
109
212
|
opts?: PluginOptions,
|
|
110
213
|
): Plugin {
|
|
111
214
|
const s = createDiscoveryState(entryPath, opts);
|
|
215
|
+
let viteCommand: "serve" | "build" = "build";
|
|
216
|
+
let viteMode = "production";
|
|
112
217
|
|
|
113
218
|
return {
|
|
114
219
|
name: "@rangojs/router:discovery",
|
|
@@ -119,32 +224,20 @@ export function createRouterDiscoveryPlugin(
|
|
|
119
224
|
__RANGO_DEBUG__: JSON.stringify(!!process.env.INTERNAL_RANGO_DEBUG),
|
|
120
225
|
},
|
|
121
226
|
};
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
manualChunks(id: string) {
|
|
129
|
-
if (s.resolvedPrerenderModules?.has(id)) {
|
|
130
|
-
return "__prerender-handlers";
|
|
131
|
-
}
|
|
132
|
-
if (s.resolvedStaticModules?.has(id)) {
|
|
133
|
-
return "__static-handlers";
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
}
|
|
227
|
+
// Prerender/static handler modules are bundled naturally with the
|
|
228
|
+
// rest of the RSC entry. A previous design forced them into dedicated
|
|
229
|
+
// __prerender-handlers / __static-handlers chunks via manualChunks,
|
|
230
|
+
// but Rollup hoisted all shared dependencies into those chunks,
|
|
231
|
+
// inflating them to ~1 MB with active runtime code. Handler code is
|
|
232
|
+
// evicted in closeBundle regardless of which chunk it lands in.
|
|
142
233
|
return config;
|
|
143
234
|
},
|
|
144
235
|
|
|
145
236
|
configResolved(config) {
|
|
146
237
|
s.projectRoot = config.root;
|
|
147
238
|
s.isBuildMode = config.command === "build";
|
|
239
|
+
viteCommand = config.command as "serve" | "build";
|
|
240
|
+
viteMode = config.mode;
|
|
148
241
|
// Capture user's resolve aliases for the temp server
|
|
149
242
|
s.userResolveAlias = config.resolve.alias;
|
|
150
243
|
// Node preset: pick up auto-discovered router path from the config() hook.
|
|
@@ -165,13 +258,6 @@ export function createRouterDiscoveryPlugin(
|
|
|
165
258
|
s.resolvedEntryPath = entries[0];
|
|
166
259
|
}
|
|
167
260
|
}
|
|
168
|
-
// Compile include/exclude patterns into a scan filter
|
|
169
|
-
if (opts?.include || opts?.exclude) {
|
|
170
|
-
s.scanFilter = createScanFilter(s.projectRoot, {
|
|
171
|
-
include: opts.include,
|
|
172
|
-
exclude: opts.exclude,
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
261
|
// Generate combined named-routes.gen.ts from static source parsing.
|
|
176
262
|
// Runs before the dev server starts so the gen file exists immediately for IDE.
|
|
177
263
|
// In build mode, the runtime discovery in buildStart produces the definitive
|
|
@@ -222,12 +308,13 @@ export function createRouterDiscoveryPlugin(
|
|
|
222
308
|
let prerenderTempServer: any = null;
|
|
223
309
|
let prerenderNodeRegistry: Map<string, any> | null = null;
|
|
224
310
|
|
|
225
|
-
// Clean up the temporary server when the dev server shuts down
|
|
311
|
+
// Clean up the temporary server and build env when the dev server shuts down
|
|
226
312
|
server.httpServer?.on("close", () => {
|
|
227
313
|
if (prerenderTempServer) {
|
|
228
314
|
prerenderTempServer.close().catch(() => {});
|
|
229
315
|
prerenderTempServer = null;
|
|
230
316
|
}
|
|
317
|
+
releaseBuildEnv(s).catch(() => {});
|
|
231
318
|
});
|
|
232
319
|
|
|
233
320
|
async function getOrCreateTempServer(): Promise<any | null> {
|
|
@@ -267,6 +354,9 @@ export function createRouterDiscoveryPlugin(
|
|
|
267
354
|
// Create a temp Node.js server to run runtime discovery and generate
|
|
268
355
|
// named route types (static parser can't resolve factory calls).
|
|
269
356
|
try {
|
|
357
|
+
// Acquire build-time env bindings for dev prerender
|
|
358
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
359
|
+
|
|
270
360
|
const tempRscEnv = await getOrCreateTempServer();
|
|
271
361
|
if (tempRscEnv) {
|
|
272
362
|
await discoverRouters(s, tempRscEnv);
|
|
@@ -283,6 +373,9 @@ export function createRouterDiscoveryPlugin(
|
|
|
283
373
|
}
|
|
284
374
|
|
|
285
375
|
try {
|
|
376
|
+
// Acquire build-time env bindings for dev prerender (Node.js path)
|
|
377
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
378
|
+
|
|
286
379
|
// Set the readiness gate BEFORE discovery so early requests
|
|
287
380
|
// block until manifest is populated
|
|
288
381
|
const serverMod = await rscEnv.runner.import(
|
|
@@ -418,6 +511,8 @@ export function createRouterDiscoveryPlugin(
|
|
|
418
511
|
{},
|
|
419
512
|
undefined,
|
|
420
513
|
wantPassthrough,
|
|
514
|
+
s.resolvedBuildEnv,
|
|
515
|
+
true, // devMode: check getParams for passthrough routes
|
|
421
516
|
);
|
|
422
517
|
if (!result) continue;
|
|
423
518
|
if (result.passthrough) continue;
|
|
@@ -559,6 +654,16 @@ export function createRouterDiscoveryPlugin(
|
|
|
559
654
|
if (!hasUrls && !hasCreateRouter) return;
|
|
560
655
|
// Invalidate cache when a router file changes (new router added/removed)
|
|
561
656
|
if (hasCreateRouter) {
|
|
657
|
+
const nestedRouterConflict = findNestedRouterConflict([
|
|
658
|
+
...(s.cachedRouterFiles ?? []),
|
|
659
|
+
resolve(filePath),
|
|
660
|
+
]);
|
|
661
|
+
if (nestedRouterConflict) {
|
|
662
|
+
server.config.logger.error(
|
|
663
|
+
formatNestedRouterConflictError(nestedRouterConflict),
|
|
664
|
+
);
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
562
667
|
s.cachedRouterFiles = undefined;
|
|
563
668
|
}
|
|
564
669
|
scheduleRouteRegeneration();
|
|
@@ -592,6 +697,12 @@ export function createRouterDiscoveryPlugin(
|
|
|
592
697
|
if (!s.isBuildMode) return;
|
|
593
698
|
// Only run once across environment builds
|
|
594
699
|
if (s.mergedRouteManifest !== null) return;
|
|
700
|
+
resetStagedBuildAssets(s.projectRoot);
|
|
701
|
+
s.prerenderManifestEntries = null;
|
|
702
|
+
s.staticManifestEntries = null;
|
|
703
|
+
|
|
704
|
+
// Acquire build-time env bindings if configured
|
|
705
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
595
706
|
|
|
596
707
|
let tempServer: any = null;
|
|
597
708
|
// Signal to user-space code (e.g. reverse.ts) that build-time discovery
|
|
@@ -651,6 +762,7 @@ export function createRouterDiscoveryPlugin(
|
|
|
651
762
|
if (tempServer) {
|
|
652
763
|
await tempServer.close();
|
|
653
764
|
}
|
|
765
|
+
await releaseBuildEnv(s);
|
|
654
766
|
}
|
|
655
767
|
},
|
|
656
768
|
|
|
@@ -711,33 +823,40 @@ export function createRouterDiscoveryPlugin(
|
|
|
711
823
|
if (!s.resolvedPrerenderModules?.size && !s.resolvedStaticModules?.size)
|
|
712
824
|
return;
|
|
713
825
|
|
|
826
|
+
// Clear maps at the start of each RSC generateBundle pass.
|
|
827
|
+
// Vite 6 multi-environment builds run RSC twice (analysis + production);
|
|
828
|
+
// clearing prevents stale/duplicate records from the analysis pass.
|
|
829
|
+
s.handlerChunkInfoMap.clear();
|
|
830
|
+
s.staticHandlerChunkInfoMap.clear();
|
|
831
|
+
|
|
714
832
|
for (const [fileName, chunk] of Object.entries(bundle) as [
|
|
715
833
|
string,
|
|
716
834
|
any,
|
|
717
835
|
][]) {
|
|
718
836
|
if (chunk.type !== "chunk") continue;
|
|
719
837
|
|
|
720
|
-
//
|
|
721
|
-
if (
|
|
722
|
-
fileName.includes("__prerender-handlers") &&
|
|
723
|
-
s.resolvedPrerenderModules?.size
|
|
724
|
-
) {
|
|
838
|
+
// Scan all chunks for handler exports (handlers may land in any chunk)
|
|
839
|
+
if (s.resolvedPrerenderModules?.size) {
|
|
725
840
|
const handlers = extractHandlerExportsFromChunk(
|
|
726
841
|
chunk.code,
|
|
727
842
|
s.resolvedPrerenderModules,
|
|
728
843
|
"Prerender",
|
|
729
|
-
|
|
844
|
+
false,
|
|
730
845
|
);
|
|
731
846
|
if (handlers.length > 0) {
|
|
732
|
-
|
|
847
|
+
const existing = s.handlerChunkInfoMap.get(fileName);
|
|
848
|
+
if (existing) {
|
|
849
|
+
existing.exports.push(...handlers);
|
|
850
|
+
} else {
|
|
851
|
+
s.handlerChunkInfoMap.set(fileName, {
|
|
852
|
+
fileName,
|
|
853
|
+
exports: handlers,
|
|
854
|
+
});
|
|
855
|
+
}
|
|
733
856
|
}
|
|
734
857
|
}
|
|
735
858
|
|
|
736
|
-
|
|
737
|
-
if (
|
|
738
|
-
fileName.includes("__static-handlers") &&
|
|
739
|
-
s.resolvedStaticModules?.size
|
|
740
|
-
) {
|
|
859
|
+
if (s.resolvedStaticModules?.size) {
|
|
741
860
|
const handlers = extractHandlerExportsFromChunk(
|
|
742
861
|
chunk.code,
|
|
743
862
|
s.resolvedStaticModules,
|
|
@@ -745,7 +864,15 @@ export function createRouterDiscoveryPlugin(
|
|
|
745
864
|
false,
|
|
746
865
|
);
|
|
747
866
|
if (handlers.length > 0) {
|
|
748
|
-
|
|
867
|
+
const existing = s.staticHandlerChunkInfoMap.get(fileName);
|
|
868
|
+
if (existing) {
|
|
869
|
+
existing.exports.push(...handlers);
|
|
870
|
+
} else {
|
|
871
|
+
s.staticHandlerChunkInfoMap.set(fileName, {
|
|
872
|
+
fileName,
|
|
873
|
+
exports: handlers,
|
|
874
|
+
});
|
|
875
|
+
}
|
|
749
876
|
}
|
|
750
877
|
}
|
|
751
878
|
}
|
package/src/vite/utils/banner.ts
CHANGED
|
@@ -23,11 +23,11 @@ ${dim} ╱${reset} ${bold}╔═╗${reset}${dim} * ╱
|
|
|
23
23
|
${dim} ${reset}${bold}║ ║${reset} ${bold}╔═╗${reset}${dim} * ✧. ╱${reset}
|
|
24
24
|
${dim} ${reset}${bold}╔╗ ║ ║ ║ ║${reset}${dim} * ╱${reset}
|
|
25
25
|
${dim} ${reset}${bold}║║ ║ ║ ║ ║ ╦═╗╔═╗╔╗╔╔═╗╔═╗${reset}${dim} ✧ ✦${reset}
|
|
26
|
-
${dim}
|
|
26
|
+
${dim} ${reset}${bold}║║ ║ ╠═╝ ║ ╠╦╝╠═╣║║║║ ╦║ ║${reset}${dim} * ✧${reset}
|
|
27
27
|
${dim} ${reset}${bold}║╚═╝ ╔═══╝ ╩╚═╩ ╩╝╚╝╚═╝╚═╝${reset}${dim} ✦ . *${reset}
|
|
28
28
|
${dim} ${reset}${bold}╚══╗ ║${reset}${dim} * RSC Wrangler ✧ ✦${reset}
|
|
29
|
-
${dim} * ${reset}${bold}║
|
|
30
|
-
${bold}
|
|
29
|
+
${dim} * ${reset}${bold}║ ║${reset}${dim} * ✧. ╱${reset}
|
|
30
|
+
${dim} ${reset}${bold}═══╝ ╚════${reset}${dim} ✦ *${reset}
|
|
31
31
|
|
|
32
32
|
v${version} · ${preset} · ${mode}
|
|
33
33
|
`;
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
copyFileSync,
|
|
4
|
+
existsSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
rmSync,
|
|
7
|
+
statSync,
|
|
8
|
+
writeFileSync,
|
|
9
|
+
} from "node:fs";
|
|
10
|
+
import { resolve } from "node:path";
|
|
11
|
+
|
|
1
12
|
/**
|
|
2
13
|
* Escape special RegExp characters in a string for safe interpolation
|
|
3
14
|
* into new RegExp() patterns.
|
|
@@ -20,6 +31,7 @@ export function encodePathParam(value: unknown): string {
|
|
|
20
31
|
/**
|
|
21
32
|
* Substitute route params into a pattern, stripping constraint and optional
|
|
22
33
|
* syntax (:param(a|b)? -> value). Also handles wildcard params (*key).
|
|
34
|
+
* Optional params not present in `params` are removed from the output.
|
|
23
35
|
*/
|
|
24
36
|
export function substituteRouteParams(
|
|
25
37
|
pattern: string,
|
|
@@ -27,6 +39,9 @@ export function substituteRouteParams(
|
|
|
27
39
|
encode: (value: string) => string = encodeURIComponent,
|
|
28
40
|
): string {
|
|
29
41
|
let result = pattern;
|
|
42
|
+
let hadOmittedOptional = false;
|
|
43
|
+
|
|
44
|
+
// First pass: substitute provided params
|
|
30
45
|
for (const [key, value] of Object.entries(params)) {
|
|
31
46
|
const escaped = escapeRegExp(key);
|
|
32
47
|
result = result.replace(
|
|
@@ -35,6 +50,20 @@ export function substituteRouteParams(
|
|
|
35
50
|
);
|
|
36
51
|
result = result.replace(`*${key}`, encode(value));
|
|
37
52
|
}
|
|
53
|
+
|
|
54
|
+
// Second pass: strip remaining optional param placeholders not in params
|
|
55
|
+
result = result.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\([^)]*\))?\?/g, () => {
|
|
56
|
+
hadOmittedOptional = true;
|
|
57
|
+
return "";
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Clean up slashes from omitted optional segments
|
|
61
|
+
if (hadOmittedOptional) {
|
|
62
|
+
const hadTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
|
|
63
|
+
result = result.replace(/\/\/+/g, "/").replace(/\/+$/, "") || "/";
|
|
64
|
+
if (hadTrailingSlash && !result.endsWith("/")) result += "/";
|
|
65
|
+
}
|
|
66
|
+
|
|
38
67
|
return result;
|
|
39
68
|
}
|
|
40
69
|
|
|
@@ -127,3 +156,52 @@ export function notifyOnError(
|
|
|
127
156
|
break; // Only notify the first router with onError
|
|
128
157
|
}
|
|
129
158
|
}
|
|
159
|
+
|
|
160
|
+
function getStagedAssetDir(projectRoot: string): string {
|
|
161
|
+
return resolve(projectRoot, "node_modules/.rangojs-router-build/rsc-assets");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function resetStagedBuildAssets(projectRoot: string): void {
|
|
165
|
+
rmSync(getStagedAssetDir(projectRoot), { recursive: true, force: true });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function stageBuildAssetModule(
|
|
169
|
+
projectRoot: string,
|
|
170
|
+
prefix: "__pr" | "__st",
|
|
171
|
+
exportValue: string,
|
|
172
|
+
): string {
|
|
173
|
+
const stagedDir = getStagedAssetDir(projectRoot);
|
|
174
|
+
mkdirSync(stagedDir, { recursive: true });
|
|
175
|
+
|
|
176
|
+
const contentHash = createHash("sha256")
|
|
177
|
+
.update(exportValue)
|
|
178
|
+
.digest("hex")
|
|
179
|
+
.slice(0, 8);
|
|
180
|
+
const fileName = `${prefix}-${contentHash}.js`;
|
|
181
|
+
const filePath = resolve(stagedDir, fileName);
|
|
182
|
+
|
|
183
|
+
if (!existsSync(filePath)) {
|
|
184
|
+
writeFileSync(filePath, `export default ${exportValue};\n`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return fileName;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function copyStagedBuildAssets(
|
|
191
|
+
projectRoot: string,
|
|
192
|
+
fileNames: Iterable<string>,
|
|
193
|
+
): number {
|
|
194
|
+
const stagedDir = getStagedAssetDir(projectRoot);
|
|
195
|
+
const distAssetsDir = resolve(projectRoot, "dist/rsc/assets");
|
|
196
|
+
mkdirSync(distAssetsDir, { recursive: true });
|
|
197
|
+
|
|
198
|
+
let totalBytes = 0;
|
|
199
|
+
for (const fileName of new Set(fileNames)) {
|
|
200
|
+
const stagedPath = resolve(stagedDir, fileName);
|
|
201
|
+
const distPath = resolve(distAssetsDir, fileName);
|
|
202
|
+
copyFileSync(stagedPath, distPath);
|
|
203
|
+
totalBytes += statSync(stagedPath).size;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return totalBytes;
|
|
207
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
2
|
import * as Vite from "vite";
|
|
3
3
|
import { getPublishedPackageName } from "./package-resolution.js";
|
|
4
|
+
import { performanceTracksOptimizeDepsPlugin } from "../plugins/performance-tracks.js";
|
|
4
5
|
import {
|
|
5
6
|
VIRTUAL_ENTRY_BROWSER,
|
|
6
7
|
VIRTUAL_ENTRY_SSR,
|
|
@@ -35,9 +36,9 @@ const versionEsbuildPlugin = {
|
|
|
35
36
|
* Includes the version stub plugin for all environments.
|
|
36
37
|
*/
|
|
37
38
|
export const sharedEsbuildOptions: {
|
|
38
|
-
plugins:
|
|
39
|
+
plugins: any[];
|
|
39
40
|
} = {
|
|
40
|
-
plugins: [versionEsbuildPlugin],
|
|
41
|
+
plugins: [versionEsbuildPlugin, performanceTracksOptimizeDepsPlugin()],
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
/**
|