@rangojs/router 0.0.0-experimental.122 → 0.0.0-experimental.125
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/dist/bin/rango.js +10 -6
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +55 -48
- package/package.json +61 -21
- package/skills/caching/SKILL.md +2 -1
- package/skills/hooks/SKILL.md +40 -29
- package/skills/host-router/SKILL.md +16 -2
- package/skills/intercept/SKILL.md +4 -2
- package/skills/layout/SKILL.md +11 -6
- package/skills/loader/SKILL.md +6 -2
- package/skills/middleware/SKILL.md +4 -2
- package/skills/migrate-nextjs/SKILL.md +3 -1
- package/skills/parallel/SKILL.md +9 -4
- package/skills/rango/SKILL.md +12 -0
- package/skills/route/SKILL.md +10 -2
- package/skills/testing/SKILL.md +129 -0
- package/skills/testing/bindings.md +89 -0
- package/skills/testing/cache-prerender.md +98 -0
- package/skills/testing/client-components.md +122 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +89 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +118 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +120 -0
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +1 -1
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +1 -83
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/navigation-bridge.ts +14 -1
- package/src/browser/navigation-client.ts +14 -1
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +26 -51
- package/src/browser/navigation-transaction.ts +0 -32
- package/src/browser/partial-update.ts +1 -83
- package/src/browser/prefetch/cache.ts +6 -45
- package/src/browser/prefetch/fetch.ts +7 -0
- package/src/browser/prefetch/queue.ts +6 -3
- package/src/browser/rango-state.ts +157 -99
- package/src/browser/react/Link.tsx +0 -2
- package/src/browser/react/NavigationProvider.tsx +2 -1
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +0 -2
- package/src/browser/react/index.ts +0 -51
- package/src/browser/react/location-state-shared.ts +0 -13
- package/src/browser/react/location-state.ts +0 -1
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +0 -5
- package/src/browser/react/use-link-status.ts +0 -4
- package/src/browser/react/use-navigation.ts +0 -3
- package/src/browser/react/use-params.ts +0 -2
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +0 -13
- package/src/browser/rsc-router.tsx +12 -4
- package/src/browser/server-action-bridge.ts +77 -15
- package/src/browser/types.ts +7 -2
- package/src/browser/validate-redirect-origin.ts +4 -5
- package/src/build/route-trie.ts +3 -0
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/router-processing.ts +0 -8
- package/src/cache/cache-policy.ts +0 -54
- package/src/cache/cache-runtime.ts +27 -24
- package/src/cache/cache-scope.ts +0 -27
- package/src/cache/cache-tag.ts +0 -37
- package/src/cache/cf/cf-cache-store.ts +94 -46
- package/src/cache/cf/index.ts +0 -24
- package/src/cache/document-cache.ts +11 -36
- package/src/cache/handle-snapshot.ts +0 -40
- package/src/cache/index.ts +0 -27
- package/src/cache/memory-segment-store.ts +2 -48
- package/src/cache/profile-registry.ts +7 -3
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +0 -16
- package/src/cache/types.ts +0 -98
- package/src/client.rsc.tsx +1 -22
- package/src/client.tsx +14 -38
- package/src/component-utils.ts +19 -0
- package/src/deps/ssr.ts +0 -1
- package/src/handle.ts +28 -18
- package/src/handles/MetaTags.tsx +0 -14
- package/src/handles/meta.ts +0 -39
- package/src/host/cookie-handler.ts +0 -36
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +6 -0
- package/src/host/pattern-matcher.ts +7 -50
- package/src/host/router.ts +1 -65
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +6 -2
- package/src/href-client.ts +0 -4
- package/src/index.rsc.ts +42 -3
- package/src/index.ts +31 -1
- package/src/internal-debug.ts +2 -4
- package/src/loader.rsc.ts +19 -9
- package/src/loader.ts +12 -4
- package/src/network-error-thrower.tsx +1 -6
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +10 -11
- package/src/prerender/store.ts +23 -30
- package/src/prerender.ts +58 -3
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +1 -44
- package/src/route-definition/dsl-helpers.ts +7 -19
- package/src/route-definition/helpers-types.ts +3 -3
- package/src/route-definition/redirect.ts +11 -1
- package/src/route-map-builder.ts +0 -16
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +0 -13
- package/src/router/error-handling.ts +12 -16
- package/src/router/find-match.ts +4 -30
- package/src/router/intercept-resolution.ts +10 -1
- package/src/router/lazy-includes.ts +1 -57
- package/src/router/loader-resolution.ts +3 -2
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +1 -25
- package/src/router/match-api.ts +0 -20
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +57 -58
- package/src/router/match-middleware/background-revalidation.ts +0 -7
- package/src/router/match-middleware/cache-lookup.ts +1 -54
- package/src/router/match-middleware/cache-store.ts +0 -31
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -21
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +1 -52
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-cookies.ts +0 -13
- package/src/router/middleware-types.ts +0 -115
- package/src/router/middleware.ts +7 -30
- package/src/router/navigation-snapshot.ts +0 -51
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +1 -33
- package/src/router/prerender-match.ts +33 -45
- package/src/router/request-classification.ts +1 -38
- package/src/router/revalidation.ts +5 -58
- package/src/router/router-context.ts +0 -26
- package/src/router/router-interfaces.ts +7 -0
- package/src/router/router-options.ts +30 -0
- package/src/router/segment-resolution/fresh.ts +25 -57
- package/src/router/segment-resolution/helpers.ts +34 -0
- package/src/router/segment-resolution/loader-cache.ts +10 -13
- package/src/router/segment-resolution/revalidation.ts +5 -42
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution.ts +4 -1
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/telemetry-otel.ts +0 -20
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/trie-matching.ts +63 -40
- package/src/router/types.ts +1 -63
- package/src/router/url-params.ts +0 -5
- package/src/router.ts +40 -9
- package/src/rsc/handler.ts +14 -2
- package/src/rsc/helpers.ts +34 -0
- package/src/rsc/origin-guard.ts +0 -12
- package/src/rsc/progressive-enhancement.ts +4 -1
- package/src/rsc/rsc-rendering.ts +4 -7
- package/src/rsc/runtime-warnings.ts +14 -0
- package/src/rsc/server-action.ts +30 -28
- package/src/rsc/types.ts +2 -1
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +0 -16
- package/src/segment-loader-promise.ts +14 -2
- package/src/segment-system.tsx +79 -88
- package/src/server/cookie-store.ts +52 -1
- package/src/server/handle-store.ts +7 -24
- package/src/server/loader-registry.ts +5 -24
- package/src/server/request-context.ts +74 -77
- package/src/ssr/index.tsx +14 -14
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +119 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +581 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +127 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +186 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +98 -0
- package/src/testing/internal/context.ts +348 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +311 -0
- package/src/testing/render-route.tsx +504 -0
- package/src/testing/run-loader.ts +378 -0
- package/src/testing/run-middleware.ts +205 -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 +305 -0
- package/src/theme/ThemeProvider.tsx +0 -52
- package/src/theme/ThemeScript.tsx +0 -6
- package/src/theme/constants.ts +0 -12
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +0 -14
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/error-types.ts +25 -89
- package/src/types/global-namespace.ts +15 -15
- package/src/types/handler-context.ts +16 -13
- package/src/types/index.ts +0 -10
- package/src/types/request-scope.ts +0 -19
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +0 -13
- package/src/urls/include-helper.ts +0 -4
- package/src/urls/index.ts +0 -6
- package/src/urls/path-helper-types.ts +2 -2
- package/src/urls/path-helper.ts +0 -54
- package/src/urls/urls-function.ts +0 -13
- package/src/use-loader.tsx +0 -186
- package/src/vite/discovery/bundle-postprocess.ts +2 -1
- package/src/vite/discovery/discover-routers.ts +6 -7
- package/src/vite/discovery/virtual-module-codegen.ts +1 -11
- package/src/vite/plugin-types.ts +3 -1
- package/src/vite/plugins/cjs-to-esm.ts +0 -11
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +0 -10
- package/src/vite/plugins/cloudflare-protocol-stub.ts +0 -20
- package/src/vite/plugins/expose-action-id.ts +2 -73
- package/src/vite/plugins/expose-id-utils.ts +0 -55
- package/src/vite/plugins/expose-ids/export-analysis.ts +0 -38
- package/src/vite/plugins/expose-ids/handler-transform.ts +0 -15
- package/src/vite/plugins/expose-ids/loader-transform.ts +0 -15
- package/src/vite/plugins/expose-ids/router-transform.ts +0 -13
- package/src/vite/plugins/expose-internal-ids.ts +10 -0
- package/src/vite/plugins/performance-tracks.ts +0 -3
- package/src/vite/plugins/use-cache-transform.ts +0 -36
- package/src/vite/plugins/version-injector.ts +0 -20
- package/src/vite/plugins/version-plugin.ts +1 -49
- package/src/vite/plugins/virtual-entries.ts +0 -15
- package/src/vite/rango.ts +1 -108
- package/src/vite/router-discovery.ts +2 -1
- package/src/vite/utils/ast-handler-extract.ts +0 -16
- package/src/vite/utils/bundle-analysis.ts +6 -13
- package/src/vite/utils/client-chunks.ts +0 -6
- package/src/vite/utils/forward-user-plugins.ts +0 -22
- package/src/vite/utils/manifest-utils.ts +0 -4
- package/src/vite/utils/package-resolution.ts +1 -73
- package/src/vite/utils/prerender-utils.ts +0 -35
- package/src/vite/utils/shared-utils.ts +3 -35
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
package/src/vite/rango.ts
CHANGED
|
@@ -66,18 +66,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
66
66
|
const resolvedOptions: RangoOptions = options ?? { preset: "node" };
|
|
67
67
|
const preset = resolvedOptions.preset ?? "node";
|
|
68
68
|
const showBanner = resolvedOptions.banner ?? true;
|
|
69
|
-
// Client-chunking strategy (per-route/per-feature splitting of the browser
|
|
70
|
-
// bundle). Defaults to the built-in directory strategy (`true`) pre-1.0; pass
|
|
71
|
-
// `clientChunks: false` to opt out. Resolved once and forwarded to
|
|
72
|
-
// @vitejs/plugin-rsc in both presets. The built-in strategy only splits where it
|
|
73
|
-
// recognizes a route structure, so this default is a no-op for flat / host-split
|
|
74
|
-
// apps and never duplicates the shared runtime.
|
|
75
69
|
const clientChunksOption = resolvedOptions.clientChunks ?? true;
|
|
76
|
-
// Shared context the built-in strategy reads at build time: the production
|
|
77
|
-
// hashes of registered error/notFound fallback modules (-> app-fallback).
|
|
78
|
-
// Populated by the discovery plugin in buildStart, before the client build
|
|
79
|
-
// invokes the strategy. Only wired when the built-in strategy is active; a
|
|
80
|
-
// custom function owns its own grouping.
|
|
81
70
|
const useBuiltInClientChunks = clientChunksOption === true;
|
|
82
71
|
const clientChunkCtx: ClientChunkContext | undefined = useBuiltInClientChunks
|
|
83
72
|
? { fallbackRefs: new Set<string>() }
|
|
@@ -124,14 +113,8 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
124
113
|
const prerenderEnabled = true;
|
|
125
114
|
|
|
126
115
|
if (preset === "cloudflare") {
|
|
127
|
-
// Cloudflare preset: configure entries for cloudflare worker setup
|
|
128
|
-
// Router is not needed here - worker.rsc.tsx imports it directly
|
|
129
|
-
|
|
130
|
-
// Dynamically import @vitejs/plugin-rsc
|
|
131
116
|
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
132
117
|
|
|
133
|
-
// Only client and ssr entries - rsc entry is handled by cloudflare plugin
|
|
134
|
-
// Always use virtual modules for cloudflare preset
|
|
135
118
|
const finalEntries: { client: string; ssr: string } = {
|
|
136
119
|
client: VIRTUAL_IDS.browser,
|
|
137
120
|
ssr: VIRTUAL_IDS.ssr,
|
|
@@ -142,10 +125,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
142
125
|
enforce: "pre",
|
|
143
126
|
|
|
144
127
|
config() {
|
|
145
|
-
// Configure environments for cloudflare deployment
|
|
146
128
|
return {
|
|
147
|
-
// Exclude rsc-router modules from optimization to prevent module duplication
|
|
148
|
-
// This ensures the same Context instance is used by both browser entry and RSC proxy modules
|
|
149
129
|
optimizeDeps: {
|
|
150
130
|
exclude: excludeDeps,
|
|
151
131
|
rolldownOptions: sharedRolldownOptions,
|
|
@@ -168,21 +148,12 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
168
148
|
client: {
|
|
169
149
|
build: {
|
|
170
150
|
rollupOptions: {
|
|
171
|
-
// FILE_NAME_CONFLICT (and any other client-build warning) is
|
|
172
|
-
// emitted by the CLIENT environment build, which consults THIS
|
|
173
|
-
// env's onwarn -- Vite 8's environment builds do NOT propagate
|
|
174
|
-
// the top-level build.rollupOptions.onwarn into the client env.
|
|
175
|
-
// Wire it here so the suppression runs where the conflicts
|
|
176
|
-
// originate (the top-level handler is invoked 0x for these; the
|
|
177
|
-
// client-env handler is invoked for all of them).
|
|
178
151
|
onwarn,
|
|
179
152
|
output: {
|
|
180
153
|
manualChunks: getManualChunks,
|
|
181
154
|
},
|
|
182
155
|
},
|
|
183
156
|
},
|
|
184
|
-
// Pre-bundle rsc-html-stream to prevent discovery during first request
|
|
185
|
-
// Exclude rsc-router modules to ensure same Context instance
|
|
186
157
|
optimizeDeps: {
|
|
187
158
|
include: [nested("rsc-html-stream/client")],
|
|
188
159
|
exclude: excludeDeps,
|
|
@@ -190,12 +161,9 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
190
161
|
},
|
|
191
162
|
},
|
|
192
163
|
ssr: {
|
|
193
|
-
// Build SSR inside RSC directory so wrangler can deploy self-contained dist/rsc
|
|
194
164
|
build: {
|
|
195
165
|
outDir: "./dist/rsc/ssr",
|
|
196
166
|
},
|
|
197
|
-
// Pre-bundle SSR entry and React for proper module linking with childEnvironments
|
|
198
|
-
// All deps must be listed to avoid late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
199
167
|
optimizeDeps: {
|
|
200
168
|
entries: [finalEntries.ssr],
|
|
201
169
|
include: [
|
|
@@ -215,10 +183,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
215
183
|
},
|
|
216
184
|
},
|
|
217
185
|
rsc: {
|
|
218
|
-
// RSC environment needs exclude list and esbuild options
|
|
219
|
-
// Exclude rsc-router modules to prevent createContext in RSC environment
|
|
220
186
|
optimizeDeps: {
|
|
221
|
-
// Pre-bundle all RSC deps to prevent late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
222
187
|
include: [
|
|
223
188
|
"react",
|
|
224
189
|
"react/jsx-runtime",
|
|
@@ -249,13 +214,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
249
214
|
});
|
|
250
215
|
|
|
251
216
|
plugins.push(createVirtualEntriesPlugin(finalEntries));
|
|
252
|
-
|
|
253
|
-
// Dev-only: RSDW client patch for React Performance Tracks
|
|
254
217
|
plugins.push(performanceTracksPlugin());
|
|
255
|
-
|
|
256
|
-
// Add RSC plugin with cloudflare-specific options
|
|
257
|
-
// Note: loadModuleDevProxy should NOT be used with childEnvironments
|
|
258
|
-
// since SSR runs in workerd alongside RSC
|
|
259
218
|
plugins.push(
|
|
260
219
|
rsc({
|
|
261
220
|
entries: finalEntries,
|
|
@@ -263,13 +222,8 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
263
222
|
clientChunks,
|
|
264
223
|
}) as PluginOption,
|
|
265
224
|
);
|
|
266
|
-
|
|
267
|
-
// Deduplicate client references from third-party packages in dev mode.
|
|
268
|
-
// Prevents module duplication when server components import "use client"
|
|
269
|
-
// packages that are also imported directly by client components.
|
|
270
225
|
plugins.push(clientRefDedup());
|
|
271
226
|
} else {
|
|
272
|
-
// Auto-discover router using Vite's resolved root (not process.cwd())
|
|
273
227
|
plugins.push({
|
|
274
228
|
name: "@rangojs/router:auto-discover",
|
|
275
229
|
config(userConfig) {
|
|
@@ -292,18 +246,15 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
292
246
|
.join("\n");
|
|
293
247
|
throw new Error(`[rango] Multiple routers found:\n${list}`);
|
|
294
248
|
}
|
|
295
|
-
// 0 found: routerRef.path stays undefined, warn at startup via discovery plugin
|
|
296
249
|
},
|
|
297
250
|
});
|
|
298
251
|
|
|
299
|
-
// Always use virtual entries for client, ssr, and rsc
|
|
300
252
|
const finalEntries = {
|
|
301
253
|
client: VIRTUAL_IDS.browser,
|
|
302
254
|
ssr: VIRTUAL_IDS.ssr,
|
|
303
255
|
rsc: VIRTUAL_IDS.rsc,
|
|
304
256
|
};
|
|
305
257
|
|
|
306
|
-
// Dynamically import @vitejs/plugin-rsc
|
|
307
258
|
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
308
259
|
|
|
309
260
|
let hasWarnedDuplicate = false;
|
|
@@ -336,13 +287,6 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
336
287
|
client: {
|
|
337
288
|
build: {
|
|
338
289
|
rollupOptions: {
|
|
339
|
-
// FILE_NAME_CONFLICT (and any other client-build warning) is
|
|
340
|
-
// emitted by the CLIENT environment build, which consults THIS
|
|
341
|
-
// env's onwarn -- Vite 8's environment builds do NOT propagate
|
|
342
|
-
// the top-level build.rollupOptions.onwarn into the client env.
|
|
343
|
-
// Wire it here so the suppression runs where the conflicts
|
|
344
|
-
// originate (the top-level handler is invoked 0x for these; the
|
|
345
|
-
// client-env handler is invoked for all of them).
|
|
346
290
|
onwarn,
|
|
347
291
|
output: {
|
|
348
292
|
manualChunks: getManualChunks,
|
|
@@ -423,36 +367,17 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
423
367
|
},
|
|
424
368
|
});
|
|
425
369
|
|
|
426
|
-
// Add virtual entries plugin (RSC entry generated lazily from routerRef)
|
|
427
370
|
plugins.push(createVirtualEntriesPlugin(finalEntries, routerRef));
|
|
428
|
-
|
|
429
|
-
// Dev-only: RSDW client patch for React Performance Tracks
|
|
430
371
|
plugins.push(performanceTracksPlugin());
|
|
431
|
-
|
|
432
372
|
plugins.push(
|
|
433
373
|
rsc({
|
|
434
374
|
entries: finalEntries,
|
|
435
375
|
clientChunks,
|
|
436
376
|
}) as PluginOption,
|
|
437
377
|
);
|
|
438
|
-
|
|
439
|
-
// Deduplicate client references from third-party packages in dev mode.
|
|
440
|
-
// Prevents module duplication when server components import "use client"
|
|
441
|
-
// packages that are also imported directly by client components.
|
|
442
378
|
plugins.push(clientRefDedup());
|
|
443
379
|
}
|
|
444
380
|
|
|
445
|
-
// Fix HMR for "use client" components.
|
|
446
|
-
//
|
|
447
|
-
// @vitejs/plugin-rsc's hotUpdate returns undefined for "use client" files
|
|
448
|
-
// in the RSC environment. Vite then tries to propagate through the RSC
|
|
449
|
-
// module graph, but the proxy module has no import.meta.hot.accept()
|
|
450
|
-
// boundary, causing a full page reload. The client env would handle it
|
|
451
|
-
// fine via React Refresh, but the RSC env's full-reload arrives first.
|
|
452
|
-
//
|
|
453
|
-
// Fix: in the RSC env, return [] for "use client" files to signal
|
|
454
|
-
// "handled, nothing to propagate". The client env is left alone so
|
|
455
|
-
// React Refresh processes the update normally.
|
|
456
381
|
plugins.push({
|
|
457
382
|
name: "@rangojs/router:client-component-hmr",
|
|
458
383
|
hotUpdate(ctx) {
|
|
@@ -476,59 +401,27 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
476
401
|
trimmed.startsWith('"use client"') ||
|
|
477
402
|
trimmed.startsWith("'use client'")
|
|
478
403
|
) {
|
|
479
|
-
// Consume the update in RSC/SSR envs. The proxy module was already
|
|
480
|
-
// re-transformed by the RSC plugin's hotUpdate. Without this, Vite
|
|
481
|
-
// tries to propagate through the RSC/SSR module graph where the proxy
|
|
482
|
-
// has no import.meta.hot.accept() boundary, triggering a full reload.
|
|
483
|
-
// The actual component update is handled by React Refresh in the
|
|
484
|
-
// client environment.
|
|
485
404
|
return [];
|
|
486
405
|
}
|
|
487
|
-
} catch {
|
|
488
|
-
// File deleted/moved during HMR, let default handling proceed
|
|
489
|
-
}
|
|
406
|
+
} catch {}
|
|
490
407
|
},
|
|
491
408
|
});
|
|
492
409
|
|
|
493
410
|
plugins.push(exposeActionId());
|
|
494
|
-
|
|
495
|
-
// "use cache" directive transform (enforce: "post"):
|
|
496
|
-
// Wraps exports with registerCachedFunction() for function-level caching.
|
|
497
411
|
plugins.push(useCacheTransform());
|
|
498
|
-
|
|
499
|
-
// Consolidated plugin for create* ID injection (enforce: "post"):
|
|
500
|
-
// loaders, handles, location state, and prerender handlers.
|
|
501
412
|
plugins.push(exposeInternalIds());
|
|
502
|
-
|
|
503
|
-
// Router ID injection runs at normal priority (no enforce) to avoid
|
|
504
|
-
// changing Vite's dep optimization timing.
|
|
505
413
|
plugins.push(exposeRouterId());
|
|
506
|
-
|
|
507
|
-
// Add version virtual module plugin for cache invalidation
|
|
508
414
|
plugins.push(createVersionPlugin());
|
|
509
415
|
|
|
510
|
-
// Entry path for discovery: user-specified value (if any) or undefined.
|
|
511
|
-
// Auto-discovered path is passed separately via routerRef.
|
|
512
|
-
// Cloudflare preset: deferred to configResolved (read from resolved Vite env config).
|
|
513
416
|
const discoveryEntryPath =
|
|
514
417
|
preset !== "cloudflare" ? routerRef.path : undefined;
|
|
515
|
-
// Ref for deferred auto-discovery (node preset only, undefined for cloudflare)
|
|
516
418
|
const discoveryRouterRef = preset !== "cloudflare" ? routerRef : undefined;
|
|
517
419
|
|
|
518
|
-
// Version injector: auto-injects VERSION and routes-manifest into the RSC entry.
|
|
519
|
-
// For cloudflare preset, the entry is resolved lazily in configResolved.
|
|
520
|
-
// For node preset, the virtual entry already includes these imports.
|
|
521
420
|
if (preset === "cloudflare") {
|
|
522
421
|
plugins.push(createVersionInjectorPlugin(undefined));
|
|
523
422
|
}
|
|
524
423
|
|
|
525
|
-
// Transform CJS vendor files to ESM for browser compatibility
|
|
526
|
-
// optimizeDeps.include doesn't work because the file is loaded after initial optimization
|
|
527
424
|
plugins.push(createCjsToEsmPlugin());
|
|
528
|
-
|
|
529
|
-
// Router discovery plugin for build-time manifest generation.
|
|
530
|
-
// For cloudflare, the entry is resolved lazily in configResolved from the RSC environment.
|
|
531
|
-
// For node, discoveryRouterRef provides the auto-discovered path when not user-specified.
|
|
532
425
|
plugins.push(
|
|
533
426
|
createRouterDiscoveryPlugin(discoveryEntryPath, {
|
|
534
427
|
routerPathRef: discoveryRouterRef,
|
|
@@ -424,7 +424,8 @@ export function createRouterDiscoveryPlugin(
|
|
|
424
424
|
releaseBuildEnv(s).catch(() => {});
|
|
425
425
|
});
|
|
426
426
|
|
|
427
|
-
// Mirror the build-path contract (
|
|
427
|
+
// Mirror the build-path contract (the buildStart hook below, which sets
|
|
428
|
+
// __rscRouterDiscoveryActive before running user modules):
|
|
428
429
|
// set __rscRouterDiscoveryActive before running user modules so any
|
|
429
430
|
// module-level router.reverse() calls return a placeholder instead
|
|
430
431
|
// of throwing. The temp Vite server's module runner has its own
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import type MagicString from "magic-string";
|
|
2
2
|
import { hashInlineId, buildExportMap } from "../plugins/expose-id-utils.js";
|
|
3
3
|
|
|
4
|
-
// ---------------------------------------------------------------------------
|
|
5
|
-
// Types
|
|
6
|
-
// ---------------------------------------------------------------------------
|
|
7
|
-
|
|
8
4
|
/** Minimal ESTree Program node — avoids importing from `rollup` (not a direct dep). */
|
|
9
5
|
interface ProgramNode {
|
|
10
6
|
type: "Program";
|
|
@@ -70,10 +66,6 @@ function findImportInsertionPos(
|
|
|
70
66
|
return insertionPos;
|
|
71
67
|
}
|
|
72
68
|
|
|
73
|
-
// ---------------------------------------------------------------------------
|
|
74
|
-
// AST walking helper
|
|
75
|
-
// ---------------------------------------------------------------------------
|
|
76
|
-
|
|
77
69
|
/**
|
|
78
70
|
* Recursively walk an ESTree AST node, calling `enter` on each node.
|
|
79
71
|
* Parent is passed for context.
|
|
@@ -111,10 +103,6 @@ function walkNode(
|
|
|
111
103
|
ancestors.pop();
|
|
112
104
|
}
|
|
113
105
|
|
|
114
|
-
// ---------------------------------------------------------------------------
|
|
115
|
-
// AST analysis
|
|
116
|
-
// ---------------------------------------------------------------------------
|
|
117
|
-
|
|
118
106
|
/**
|
|
119
107
|
* Parse the file with Vite's parseAst and find all calls to `fnName`.
|
|
120
108
|
* Distinguishes between `export const X = fnName(...)` (exportInfo set)
|
|
@@ -426,10 +414,6 @@ export function extractModuleLevelDeclarations(
|
|
|
426
414
|
return declarations;
|
|
427
415
|
}
|
|
428
416
|
|
|
429
|
-
// ---------------------------------------------------------------------------
|
|
430
|
-
// Transform
|
|
431
|
-
// ---------------------------------------------------------------------------
|
|
432
|
-
|
|
433
417
|
/**
|
|
434
418
|
* Transform inline handler calls by extracting them into virtual modules.
|
|
435
419
|
* Only processes inline calls (exportInfo === null); export const calls are
|
|
@@ -5,9 +5,7 @@ import {
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Find matching close paren in bundled code using depth counting.
|
|
8
|
-
* Uses skipStringOrComment
|
|
9
|
-
* template literal ${...} expressions, comments, and nested strings.
|
|
10
|
-
* Returns the position after the closing paren, or -1 if unmatched.
|
|
8
|
+
* Uses skipStringOrComment to correctly handle template literals, comments, and nested strings.
|
|
11
9
|
* @internal Exported for testing only.
|
|
12
10
|
*/
|
|
13
11
|
export function findMatchingParenInBundle(
|
|
@@ -30,9 +28,8 @@ export function findMatchingParenInBundle(
|
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
/**
|
|
33
|
-
* Scan a bundled chunk for handler exports
|
|
34
|
-
*
|
|
35
|
-
* @internal Exported for testing only.
|
|
31
|
+
* Scan a bundled chunk for handler exports and extract their names + $$id values.
|
|
32
|
+
* Optionally detects passthrough flag. @internal Exported for testing only.
|
|
36
33
|
*/
|
|
37
34
|
export function extractHandlerExportsFromChunk(
|
|
38
35
|
chunkCode: string,
|
|
@@ -67,7 +64,7 @@ export function extractHandlerExportsFromChunk(
|
|
|
67
64
|
const closePos = findMatchingParenInBundle(chunkCode, afterOpen);
|
|
68
65
|
if (closePos !== -1) {
|
|
69
66
|
const callBody = chunkCode.slice(callStart.index, closePos);
|
|
70
|
-
isPassthrough = /passthrough\s*:\s*(!0|true)/.test(callBody);
|
|
67
|
+
isPassthrough = /passthrough\s*:\s*(!0|true)/.test(callBody); // !0 is minified true
|
|
71
68
|
}
|
|
72
69
|
}
|
|
73
70
|
}
|
|
@@ -79,9 +76,8 @@ export function extractHandlerExportsFromChunk(
|
|
|
79
76
|
}
|
|
80
77
|
|
|
81
78
|
/**
|
|
82
|
-
* Evict handler code from a bundled chunk, replacing full
|
|
83
|
-
*
|
|
84
|
-
* and bytes saved, or null if no changes were made.
|
|
79
|
+
* Evict handler code from a bundled chunk, replacing full call expressions with stubs.
|
|
80
|
+
* Returns the modified code and bytes saved, or null if no changes were made.
|
|
85
81
|
* @internal Exported for testing only.
|
|
86
82
|
*/
|
|
87
83
|
export function evictHandlerCode(
|
|
@@ -110,13 +106,11 @@ export function evictHandlerCode(
|
|
|
110
106
|
const closePos = findMatchingParenInBundle(modified, afterOpen);
|
|
111
107
|
if (closePos === -1) continue;
|
|
112
108
|
|
|
113
|
-
// Skip trailing whitespace and optional semicolon
|
|
114
109
|
let rangeEnd = closePos;
|
|
115
110
|
while (rangeEnd < modified.length && /\s/.test(modified[rangeEnd]))
|
|
116
111
|
rangeEnd++;
|
|
117
112
|
if (modified[rangeEnd] === ";") rangeEnd++;
|
|
118
113
|
|
|
119
|
-
// Validate: matched range must contain the expected handlerId
|
|
120
114
|
const matched = modified.slice(startMatch.index, rangeEnd);
|
|
121
115
|
if (!matched.includes(handlerId)) continue;
|
|
122
116
|
|
|
@@ -124,7 +118,6 @@ export function evictHandlerCode(
|
|
|
124
118
|
modified =
|
|
125
119
|
modified.slice(0, startMatch.index) + stub + modified.slice(rangeEnd);
|
|
126
120
|
|
|
127
|
-
// Remove the now-redundant $$id assignment line.
|
|
128
121
|
modified = modified.replace(
|
|
129
122
|
new RegExp(`\\n${eName}\\.\\$\\$id\\s*=\\s*"[^"]+";`),
|
|
130
123
|
"",
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
// Resolution of the public `clientChunks` option into the callback shape that
|
|
2
|
-
// @vitejs/plugin-rsc expects. See plugin-types.ts (ClientChunks) and
|
|
3
|
-
// docs/client-chunking.md for the contract. The mechanism: a distinct returned
|
|
4
|
-
// name yields a distinct, dynamically-imported client chunk, independent of how
|
|
5
|
-
// the RSC/server build chunked the importing modules.
|
|
6
|
-
|
|
7
1
|
import type { ClientChunkMeta, ClientChunks } from "../plugin-types.js";
|
|
8
2
|
import { createRangoDebugger, NS } from "../debug.js";
|
|
9
3
|
import { hashRefKey } from "../plugins/client-ref-hashing.js";
|
|
@@ -1,25 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Discovery Runner Config Parity
|
|
3
|
-
*
|
|
4
|
-
* The discovery temp server (createTempRscServer) runs the user's handler
|
|
5
|
-
* graph through a throwaway Node Vite server built with `configFile: false`.
|
|
6
|
-
* Without help, that server only sees a fixed Rango-owned plugin set, so any
|
|
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.
|
|
16
|
-
*
|
|
17
|
-
* These helpers extract the resolution-relevant slice of the user's resolved
|
|
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.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
1
|
import type { Plugin, ResolvedConfig, UserConfig } from "vite";
|
|
24
2
|
|
|
25
3
|
/**
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
// Pure prefix-tree walks live in the build layer so runtime code can consume
|
|
2
|
-
// them without importing from vite/. Re-exported here for the vite-side
|
|
3
|
-
// callers (discover-routers, virtual-module-codegen) that already import them
|
|
4
|
-
// from this module.
|
|
5
1
|
export {
|
|
6
2
|
flattenLeafEntries,
|
|
7
3
|
buildRouteToStaticPrefix,
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Package Resolution Utilities
|
|
3
|
-
*
|
|
4
|
-
* Handles detection of workspace vs npm install context and generates
|
|
5
|
-
* appropriate aliases and exclude lists for Vite configuration.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
1
|
import { existsSync } from "node:fs";
|
|
9
2
|
import { createRequire } from "node:module";
|
|
10
3
|
import { resolve } from "node:path";
|
|
@@ -17,44 +10,20 @@ const require = createRequire(import.meta.url);
|
|
|
17
10
|
*/
|
|
18
11
|
const VIRTUAL_PACKAGE_NAME = "@rangojs/router";
|
|
19
12
|
|
|
20
|
-
/**
|
|
21
|
-
* Get the published package name (e.g., "@rangojs/router")
|
|
22
|
-
*/
|
|
23
13
|
export function getPublishedPackageName(): string {
|
|
24
14
|
return packageJson.name;
|
|
25
15
|
}
|
|
26
16
|
|
|
27
|
-
/**
|
|
28
|
-
* Check if the package is installed from npm (scoped) vs workspace (unscoped)
|
|
29
|
-
*
|
|
30
|
-
* In workspace development:
|
|
31
|
-
* - Package is installed as "@rangojs/router" via pnpm workspace alias
|
|
32
|
-
* - The scoped name (@rangojs/router) doesn't exist in node_modules
|
|
33
|
-
*
|
|
34
|
-
* When installed from npm:
|
|
35
|
-
* - Package is installed as "@rangojs/router"
|
|
36
|
-
* - We need aliases to map "@rangojs/router/*" to "@rangojs/router/*"
|
|
37
|
-
*/
|
|
38
17
|
export function isInstalledFromNpm(): boolean {
|
|
39
18
|
const packageName = getPublishedPackageName();
|
|
40
19
|
// Check if the scoped package exists in node_modules
|
|
41
20
|
return existsSync(resolve(process.cwd(), "node_modules", packageName));
|
|
42
21
|
}
|
|
43
22
|
|
|
44
|
-
/**
|
|
45
|
-
* Check if we're in a monorepo/workspace development context
|
|
46
|
-
*/
|
|
47
23
|
export function isWorkspaceDevelopment(): boolean {
|
|
48
24
|
return !isInstalledFromNpm();
|
|
49
25
|
}
|
|
50
26
|
|
|
51
|
-
/**
|
|
52
|
-
* Subpaths derived from package.json exports that use TypeScript source.
|
|
53
|
-
* These must be excluded from Vite's dependency optimization (they ship
|
|
54
|
-
* as .ts/.tsx, not compiled JS) and aliased when installed from npm.
|
|
55
|
-
*
|
|
56
|
-
* Derived automatically from the exports field to prevent drift.
|
|
57
|
-
*/
|
|
58
27
|
const SOURCE_EXPORT_SUBPATHS = Object.keys(packageJson.exports)
|
|
59
28
|
.filter((key) => {
|
|
60
29
|
const entry = (
|
|
@@ -70,12 +39,6 @@ const SOURCE_EXPORT_SUBPATHS = Object.keys(packageJson.exports)
|
|
|
70
39
|
})
|
|
71
40
|
.map((key) => key.replace(/^\./, ""));
|
|
72
41
|
|
|
73
|
-
/**
|
|
74
|
-
* Generate the list of modules to exclude from Vite's dependency optimization.
|
|
75
|
-
*
|
|
76
|
-
* We include both the published name and the virtual name because
|
|
77
|
-
* Vite's optimizer runs before alias resolution.
|
|
78
|
-
*/
|
|
79
42
|
export function getExcludeDeps(): string[] {
|
|
80
43
|
const packageName = getPublishedPackageName();
|
|
81
44
|
const excludes: string[] = [];
|
|
@@ -92,24 +55,10 @@ export function getExcludeDeps(): string[] {
|
|
|
92
55
|
return excludes;
|
|
93
56
|
}
|
|
94
57
|
|
|
95
|
-
/**
|
|
96
|
-
* Subpaths that need aliasing — same as SOURCE_EXPORT_SUBPATHS.
|
|
97
|
-
* When installed from npm, virtual entries may use a different package name
|
|
98
|
-
* than the published one; aliases bridge them.
|
|
99
|
-
*/
|
|
100
58
|
const ALIAS_SUBPATHS = SOURCE_EXPORT_SUBPATHS;
|
|
101
59
|
|
|
102
|
-
/**
|
|
103
|
-
* Generate aliases to map virtual package paths to the actual published package.
|
|
104
|
-
*
|
|
105
|
-
* Only needed when installed from npm, where the package is under @rangojs/router
|
|
106
|
-
* but virtual entries import from rsc-router/*.
|
|
107
|
-
*
|
|
108
|
-
* Returns empty object in workspace development where rsc-router resolves directly.
|
|
109
|
-
*/
|
|
110
60
|
export function getPackageAliases(): Record<string, string> {
|
|
111
61
|
if (isWorkspaceDevelopment()) {
|
|
112
|
-
// No aliases needed - rsc-router resolves directly
|
|
113
62
|
return {};
|
|
114
63
|
}
|
|
115
64
|
|
|
@@ -123,28 +72,7 @@ export function getPackageAliases(): Record<string, string> {
|
|
|
123
72
|
return aliases;
|
|
124
73
|
}
|
|
125
74
|
|
|
126
|
-
/**
|
|
127
|
-
* Plugin-rsc pushes bare specs like
|
|
128
|
-
* `@vitejs/plugin-rsc/vendor/react-server-dom/client.edge` into
|
|
129
|
-
* `optimizeDeps.include` for the ssr and rsc environments. In strict pnpm
|
|
130
|
-
* consumer apps, `@vitejs/plugin-rsc` is only reachable from @rangojs/router's
|
|
131
|
-
* node_modules, so Vite's optimizer — which resolves from the project root —
|
|
132
|
-
* can't find them and emits "Failed to resolve dependency" warnings.
|
|
133
|
-
*
|
|
134
|
-
* We resolve those specs from this plugin's location (where plugin-rsc is
|
|
135
|
-
* guaranteed to be installed as our dep) and expose them as `resolve.alias`
|
|
136
|
-
* entries. The optimizer's resolver honors aliases, so the bare specs map to
|
|
137
|
-
* absolute paths and resolve cleanly.
|
|
138
|
-
*/
|
|
139
75
|
export function getVendorAliases(): Record<string, string> {
|
|
140
|
-
// client.browser is intentionally NOT aliased. plugin-rsc injects it into
|
|
141
|
-
// the client env's optimizeDeps.include; Vite's manual-include path resolves
|
|
142
|
-
// and pre-bundles regardless of optimizeDeps.exclude, so aliasing would
|
|
143
|
-
// trigger esbuild pre-bundling of the CJS vendor file and bypass the
|
|
144
|
-
// cjs-to-esm transform that patches `require('react'|'react-dom')` into
|
|
145
|
-
// real ESM imports. The consumer may still see a single "Failed to resolve"
|
|
146
|
-
// warning for client.browser; runtime resolution from plugin-rsc's own
|
|
147
|
-
// importer works because Vite resolves relative to the importer (not root).
|
|
148
76
|
const specs = [
|
|
149
77
|
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
|
|
150
78
|
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
|
|
@@ -154,7 +82,7 @@ export function getVendorAliases(): Record<string, string> {
|
|
|
154
82
|
try {
|
|
155
83
|
aliases[spec] = require.resolve(spec);
|
|
156
84
|
} catch {
|
|
157
|
-
//
|
|
85
|
+
// Non-fatal; Vite will warn if it cannot resolve the spec
|
|
158
86
|
}
|
|
159
87
|
}
|
|
160
88
|
return aliases;
|
|
@@ -9,18 +9,10 @@ import {
|
|
|
9
9
|
} from "node:fs";
|
|
10
10
|
import { resolve } from "node:path";
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Escape special RegExp characters in a string for safe interpolation
|
|
14
|
-
* into new RegExp() patterns.
|
|
15
|
-
*/
|
|
16
12
|
export function escapeRegExp(str: string): string {
|
|
17
13
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
18
14
|
}
|
|
19
15
|
|
|
20
|
-
/**
|
|
21
|
-
* Encode route param values for path interpolation while preserving path
|
|
22
|
-
* separators for wildcard params (splat-style values can include `/`).
|
|
23
|
-
*/
|
|
24
16
|
export function encodePathParam(value: unknown): string {
|
|
25
17
|
return String(value)
|
|
26
18
|
.split("/")
|
|
@@ -28,11 +20,6 @@ export function encodePathParam(value: unknown): string {
|
|
|
28
20
|
.join("/");
|
|
29
21
|
}
|
|
30
22
|
|
|
31
|
-
/**
|
|
32
|
-
* Substitute route params into a pattern, stripping constraint and optional
|
|
33
|
-
* syntax (:param(a|b)? -> value). Also handles wildcard params (*key).
|
|
34
|
-
* Optional params not present in `params` are removed from the output.
|
|
35
|
-
*/
|
|
36
23
|
export function substituteRouteParams(
|
|
37
24
|
pattern: string,
|
|
38
25
|
params: Record<string, string>,
|
|
@@ -41,17 +28,9 @@ export function substituteRouteParams(
|
|
|
41
28
|
let result = pattern;
|
|
42
29
|
let hadOmittedOptional = false;
|
|
43
30
|
|
|
44
|
-
// First pass: substitute provided params.
|
|
45
|
-
// Empty string on an optional placeholder is treated as omitted —
|
|
46
|
-
// caller-supplied params or `getParams()` shapes may pass `""` for an
|
|
47
|
-
// absent optional, so letting the second pass strip them keeps slash
|
|
48
|
-
// cleanup consistent. Empty string on required `:key` or wildcard
|
|
49
|
-
// `*key` still substitutes, matching prior behaviour.
|
|
50
31
|
for (const [key, value] of Object.entries(params)) {
|
|
51
32
|
const escaped = escapeRegExp(key);
|
|
52
33
|
if (value === "") {
|
|
53
|
-
// Only replace required placeholders (negative lookahead for `?`);
|
|
54
|
-
// leave `:key?` for the second pass.
|
|
55
34
|
result = result.replace(
|
|
56
35
|
new RegExp(`:${escaped}(\\([^)]*\\))?(?!\\?)`),
|
|
57
36
|
"",
|
|
@@ -66,13 +45,11 @@ export function substituteRouteParams(
|
|
|
66
45
|
}
|
|
67
46
|
}
|
|
68
47
|
|
|
69
|
-
// Second pass: strip remaining optional param placeholders not in params
|
|
70
48
|
result = result.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\([^)]*\))?\?/g, () => {
|
|
71
49
|
hadOmittedOptional = true;
|
|
72
50
|
return "";
|
|
73
51
|
});
|
|
74
52
|
|
|
75
|
-
// Clean up slashes from omitted optional segments
|
|
76
53
|
if (hadOmittedOptional) {
|
|
77
54
|
const hadTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
|
|
78
55
|
result = result.replace(/\/\/+/g, "/").replace(/\/+$/, "") || "/";
|
|
@@ -82,10 +59,6 @@ export function substituteRouteParams(
|
|
|
82
59
|
return result;
|
|
83
60
|
}
|
|
84
61
|
|
|
85
|
-
/**
|
|
86
|
-
* Run an async function over items with bounded concurrency.
|
|
87
|
-
* Errors propagate immediately and abort remaining work.
|
|
88
|
-
*/
|
|
89
62
|
export async function runWithConcurrency<T>(
|
|
90
63
|
items: T[],
|
|
91
64
|
concurrency: number,
|
|
@@ -106,10 +79,6 @@ export async function runWithConcurrency<T>(
|
|
|
106
79
|
await Promise.all(Array.from({ length: limit }, () => worker()));
|
|
107
80
|
}
|
|
108
81
|
|
|
109
|
-
/**
|
|
110
|
-
* Group prerender entries by their concurrency setting so each group
|
|
111
|
-
* can be rendered with the appropriate parallelism.
|
|
112
|
-
*/
|
|
113
82
|
export function groupByConcurrency<T extends { concurrency: number }>(
|
|
114
83
|
entries: T[],
|
|
115
84
|
): { concurrency: number; entries: T[] }[] {
|
|
@@ -129,10 +98,6 @@ export function groupByConcurrency<T extends { concurrency: number }>(
|
|
|
129
98
|
}));
|
|
130
99
|
}
|
|
131
100
|
|
|
132
|
-
/**
|
|
133
|
-
* Notify all routers' onError callbacks about a build-time error.
|
|
134
|
-
* Uses a synthetic request since there is no real request during build.
|
|
135
|
-
*/
|
|
136
101
|
export function notifyOnError(
|
|
137
102
|
registry: Map<string, any>,
|
|
138
103
|
error: unknown,
|