@rangojs/router 0.27.0 → 0.29.0
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 +1 -1
- package/dist/types/__internal.d.ts +7 -1
- package/dist/types/browser/action-fence.d.ts +2 -1
- package/dist/types/browser/event-controller.d.ts +8 -2
- package/dist/types/browser/history-state.d.ts +3 -9
- package/dist/types/browser/navigation-store.d.ts +8 -6
- package/dist/types/browser/partial-update.d.ts +11 -0
- package/dist/types/browser/react/filter-segment-order.d.ts +2 -2
- package/dist/types/browser/react/use-action.d.ts +7 -2
- package/dist/types/browser/react/use-handle.d.ts +19 -16
- package/dist/types/browser/react/use-link-status.d.ts +5 -2
- package/dist/types/browser/segment-reconciler.d.ts +32 -4
- package/dist/types/browser/types.d.ts +24 -5
- package/dist/types/browser/wire-protocol.d.ts +26 -0
- package/dist/types/cache/cache-key-utils.d.ts +11 -5
- package/dist/types/cache/cache-scope.d.ts +34 -22
- package/dist/types/cache/cf/cf-cache-constants.d.ts +2 -2
- package/dist/types/cache/cf/cf-cache-store.d.ts +47 -65
- package/dist/types/cache/cf/cf-kv-utils.d.ts +1 -1
- package/dist/types/cache/handle-snapshot.d.ts +9 -4
- package/dist/types/cache/segment-codec.d.ts +14 -0
- package/dist/types/cache/shell-snapshot.d.ts +1 -1
- package/dist/types/cache/taint.d.ts +5 -3
- package/dist/types/cache/types.d.ts +7 -3
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +8 -6
- package/dist/types/prefetch-markers.d.ts +5 -14
- package/dist/types/prerender/store.d.ts +31 -0
- package/dist/types/prerender/warm-request.d.ts +3 -3
- package/dist/types/prerender.d.ts +2 -2
- package/dist/types/route-name.d.ts +5 -0
- package/dist/types/router/error-handling.d.ts +11 -5
- package/dist/types/router/instrument.d.ts +4 -3
- package/dist/types/router/intercept-resolution.d.ts +25 -9
- package/dist/types/router/match-context.d.ts +6 -11
- package/dist/types/router/match-handlers.d.ts +2 -6
- package/dist/types/router/match-middleware/background-revalidation.d.ts +13 -22
- package/dist/types/router/match-middleware/cache-lookup.d.ts +34 -86
- package/dist/types/router/match-middleware/segment-resolution.d.ts +8 -6
- package/dist/types/router/navigation-snapshot.d.ts +7 -0
- package/dist/types/router/prerender-match.d.ts +21 -6
- package/dist/types/router/preview-match.d.ts +2 -7
- package/dist/types/router/request-classification.d.ts +5 -0
- package/dist/types/router/router-context.d.ts +7 -46
- package/dist/types/router/router-interfaces.d.ts +8 -14
- package/dist/types/router/segment-resolution/helpers.d.ts +19 -3
- package/dist/types/router/segment-resolution/loader-cache.d.ts +3 -3
- package/dist/types/router/segment-resolution/loader-mask.d.ts +4 -4
- package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +20 -18
- package/dist/types/router/segment-resolution/resolution-pass.d.ts +95 -0
- package/dist/types/router/segment-resolution/revalidation.d.ts +82 -31
- package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +2 -0
- package/dist/types/router/segment-resolution.d.ts +1 -2
- package/dist/types/router/segment-wrappers.d.ts +11 -48
- package/dist/types/router/telemetry.d.ts +2 -0
- package/dist/types/router/types.d.ts +11 -1
- package/dist/types/rsc/full-payload.d.ts +2 -2
- package/dist/types/rsc/handler-context.d.ts +6 -6
- package/dist/types/rsc/json-route-result.d.ts +5 -9
- package/dist/types/rsc/request-stages.d.ts +203 -0
- package/dist/types/rsc/response-cache-serve.d.ts +7 -12
- package/dist/types/rsc/response-route-handler.d.ts +2 -2
- package/dist/types/rsc/routine-plan.d.ts +1 -1
- package/dist/types/rsc/server-action.d.ts +2 -2
- package/dist/types/rsc/shell-capture-constants.d.ts +1 -1
- package/dist/types/rsc/shell-capture.d.ts +132 -15
- package/dist/types/rsc/shell-serve.d.ts +37 -12
- package/dist/types/server/context.d.ts +9 -8
- package/dist/types/server/handle-store.d.ts +16 -0
- package/dist/types/server/render-pass.d.ts +72 -0
- package/dist/types/server/request-context.d.ts +53 -104
- package/dist/types/server/rewrite-trail.d.ts +2 -2
- package/dist/types/testing/dispatch.d.ts +35 -18
- package/dist/types/testing/render-route.d.ts +43 -8
- package/dist/types/testing/serve-shell-request.d.ts +8 -1
- package/dist/types/types/cache-types.d.ts +6 -3
- package/dist/types/types/error-types.d.ts +30 -3
- package/dist/types/types/handler-context.d.ts +9 -1
- package/dist/types/types/segments.d.ts +1 -1
- package/dist/types/vite/discovery/build-discovery-phase.d.ts +40 -0
- package/dist/types/vite/discovery/build-env.d.ts +22 -0
- package/dist/types/vite/discovery/bundle-scan-phase.d.ts +12 -0
- package/dist/types/vite/discovery/dev-prerender-cache.d.ts +3 -2
- package/dist/types/vite/discovery/dev-server-phase.d.ts +26 -0
- package/dist/types/vite/discovery/discovery-errors.d.ts +1 -1
- package/dist/types/vite/discovery/state.d.ts +12 -0
- package/dist/types/vite/plugins/version-plugin.d.ts +1 -1
- package/dist/types/vite/plugins/virtual-entries.d.ts +1 -1
- package/dist/types/vite/router-discovery.d.ts +8 -47
- package/dist/types/vite/temp-rsc-server.d.ts +39 -0
- package/dist/types/vite/utils/prerender-utils.d.ts +9 -0
- package/dist/types/wire-params.d.ts +39 -0
- package/dist/vite/index.js +3822 -3727
- package/package.json +1 -1
- package/skills/cache-guide/SKILL.md +8 -5
- package/skills/caching/SKILL.md +37 -18
- package/skills/client-urls/SKILL.md +4 -2
- package/skills/document-cache/SKILL.md +13 -1
- package/skills/handler-use/SKILL.md +1 -1
- package/skills/hooks/SKILL.md +1 -1
- package/skills/hooks/data.md +8 -1
- package/skills/hooks/handle-and-actions.md +33 -2
- package/skills/hooks/navigation.md +121 -15
- package/skills/hooks/state.md +6 -4
- package/skills/hooks/urls.md +16 -5
- package/skills/intercept/SKILL.md +23 -7
- package/skills/middleware/SKILL.md +18 -0
- package/skills/observability/SKILL.md +30 -0
- package/skills/ppr/SKILL.md +18 -3
- package/skills/prerender/SKILL.md +39 -15
- package/skills/rango/SKILL.md +5 -1
- package/skills/server-actions/SKILL.md +15 -1
- package/skills/testing/client-components.md +25 -18
- package/skills/testing/response-routes.md +6 -4
- package/skills/testing/serve-shell-request.md +7 -7
- package/skills/use-cache/SKILL.md +46 -8
- package/skills/view-transitions/SKILL.md +1 -1
- package/src/__internal.ts +7 -1
- package/src/browser/action-fence.ts +2 -1
- package/src/browser/connection-warmup.ts +3 -1
- package/src/browser/event-controller.ts +37 -13
- package/src/browser/history-state.ts +6 -12
- package/src/browser/navigation-bridge.ts +59 -26
- package/src/browser/navigation-client.ts +20 -25
- package/src/browser/navigation-store.ts +25 -27
- package/src/browser/navigation-transaction.ts +4 -1
- package/src/browser/network-error-handler.ts +4 -0
- package/src/browser/partial-update.ts +33 -6
- package/src/browser/prefetch/cache.ts +2 -1
- package/src/browser/prefetch/fetch.ts +8 -16
- package/src/browser/prefetch/queue.ts +4 -4
- package/src/browser/react/NavigationProvider.tsx +2 -1
- package/src/browser/react/filter-segment-order.ts +2 -2
- package/src/browser/react/use-action.ts +24 -48
- package/src/browser/react/use-handle.ts +22 -18
- package/src/browser/react/use-link-status.ts +48 -60
- package/src/browser/react/use-navigation.ts +92 -41
- package/src/browser/rsc-router.tsx +1 -0
- package/src/browser/segment-reconciler.ts +109 -53
- package/src/browser/server-action-bridge.ts +81 -61
- package/src/browser/types.ts +25 -5
- package/src/browser/wire-protocol.ts +43 -0
- package/src/cache/cache-key-utils.ts +11 -5
- package/src/cache/cache-runtime.ts +132 -75
- package/src/cache/cache-scope.ts +110 -64
- package/src/cache/cf/cf-cache-constants.ts +2 -2
- package/src/cache/cf/cf-cache-store.ts +486 -874
- package/src/cache/cf/cf-kv-utils.ts +1 -1
- package/src/cache/document-cache.ts +64 -46
- package/src/cache/handle-snapshot.ts +19 -7
- package/src/cache/read-through-swr.ts +20 -18
- package/src/cache/segment-codec.ts +55 -0
- package/src/cache/shell-snapshot.ts +2 -2
- package/src/cache/tag-invalidation.ts +6 -2
- package/src/cache/taint.ts +5 -3
- package/src/cache/types.ts +7 -3
- package/src/cache/vercel/vercel-cache-store.ts +243 -310
- package/src/handles/pushed-by.ts +1 -1
- package/src/prefetch-markers.ts +5 -16
- package/src/prerender/store.ts +76 -0
- package/src/prerender/warm-request.ts +8 -4
- package/src/prerender.ts +2 -2
- package/src/route-name.ts +8 -0
- package/src/router/error-handling.ts +22 -10
- package/src/router/instrument.ts +4 -3
- package/src/router/intercept-resolution.ts +82 -75
- package/src/router/loader-resolution.ts +5 -4
- package/src/router/match-api.ts +5 -5
- package/src/router/match-context.ts +23 -12
- package/src/router/match-handlers.ts +8 -20
- package/src/router/match-middleware/background-revalidation.ts +46 -57
- package/src/router/match-middleware/cache-lookup.ts +677 -726
- package/src/router/match-middleware/cache-store.ts +4 -8
- package/src/router/match-middleware/intercept-resolution.ts +3 -23
- package/src/router/match-middleware/segment-resolution.ts +34 -61
- package/src/router/middleware.ts +69 -11
- package/src/router/navigation-snapshot.ts +14 -4
- package/src/router/prerender-match.ts +100 -44
- package/src/router/preview-match.ts +6 -41
- package/src/router/request-classification.ts +13 -7
- package/src/router/route-snapshot.ts +2 -5
- package/src/router/router-context.ts +10 -95
- package/src/router/router-interfaces.ts +8 -14
- package/src/router/segment-resolution/helpers.ts +49 -13
- package/src/router/segment-resolution/loader-cache.ts +15 -9
- package/src/router/segment-resolution/loader-mask.ts +5 -5
- package/src/router/segment-resolution/prefetch-deferral.ts +30 -27
- package/src/router/segment-resolution/resolution-pass.ts +139 -0
- package/src/router/segment-resolution/revalidation.ts +939 -789
- package/src/router/segment-resolution/streamed-handler-boundary.ts +3 -0
- package/src/router/segment-resolution.ts +4 -13
- package/src/router/segment-wrappers.ts +51 -269
- package/src/router/telemetry.ts +5 -0
- package/src/router/types.ts +11 -1
- package/src/router.ts +19 -17
- package/src/rsc/full-payload.ts +6 -5
- package/src/rsc/handler-context.ts +8 -14
- package/src/rsc/handler.ts +126 -507
- package/src/rsc/json-route-result.ts +5 -9
- package/src/rsc/loader-fetch.ts +6 -5
- package/src/rsc/progressive-enhancement.ts +5 -0
- package/src/rsc/request-stages.ts +759 -0
- package/src/rsc/response-cache-serve.ts +10 -14
- package/src/rsc/response-route-handler.ts +13 -5
- package/src/rsc/rewrite-passes.ts +2 -1
- package/src/rsc/routine-plan.ts +1 -1
- package/src/rsc/rsc-rendering.ts +164 -349
- package/src/rsc/server-action.ts +87 -113
- package/src/rsc/shell-capture-constants.ts +1 -1
- package/src/rsc/shell-capture.ts +275 -227
- package/src/rsc/shell-serve.ts +121 -18
- package/src/rsc/ssr-setup.ts +5 -4
- package/src/segment-system.tsx +3 -3
- package/src/server/context.ts +22 -25
- package/src/server/handle-store.ts +55 -0
- package/src/server/render-pass.ts +291 -0
- package/src/server/request-context.ts +75 -115
- package/src/server/rewrite-trail.ts +6 -4
- package/src/ssr/index.tsx +1 -1
- package/src/testing/dispatch.ts +226 -710
- package/src/testing/e2e/page-helpers.ts +2 -2
- package/src/testing/render-route.tsx +199 -13
- package/src/testing/serve-shell-request.ts +36 -40
- package/src/types/cache-types.ts +6 -3
- package/src/types/error-types.ts +30 -3
- package/src/types/handler-context.ts +12 -1
- package/src/types/segments.ts +1 -1
- package/src/vite/discovery/build-discovery-phase.ts +204 -0
- package/src/vite/discovery/build-env.ts +148 -0
- package/src/vite/discovery/bundle-scan-phase.ts +128 -0
- package/src/vite/discovery/dev-prerender-cache.ts +8 -3
- package/src/vite/discovery/dev-server-phase.ts +1776 -0
- package/src/vite/discovery/discover-routers.ts +1 -1
- package/src/vite/discovery/discovery-errors.ts +1 -1
- package/src/vite/discovery/prerender-collection.ts +24 -39
- package/src/vite/discovery/state.ts +15 -0
- package/src/vite/plugins/version-plugin.ts +1 -1
- package/src/vite/plugins/virtual-entries.ts +1 -1
- package/src/vite/router-discovery.ts +29 -2428
- package/src/vite/temp-rsc-server.ts +223 -0
- package/src/vite/utils/prerender-utils.ts +47 -0
- package/src/wire-params.ts +40 -0
- package/dist/types/router/segment-resolution/fresh.d.ts +0 -72
- package/src/router/segment-resolution/fresh.ts +0 -945
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build discovery phase: the discovery plugin's buildStart, buildApp (post)
|
|
3
|
+
* and buildEnd hooks.
|
|
4
|
+
*
|
|
5
|
+
* buildStart discovers routers through a temp RSC server and writes the
|
|
6
|
+
* generated route types. When PPR shell candidates exist, it defers closing
|
|
7
|
+
* that server, and releasing the buildEnv, as a PAIR: the buildApp post hook
|
|
8
|
+
* releases them after the shell capture (success), buildEnd after an
|
|
9
|
+
* environment build failure (abort).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { Rolldown, ViteBuilder } from "vite";
|
|
13
|
+
import type { DiscoveryState } from "./state.js";
|
|
14
|
+
import { createTempRscServer } from "../temp-rsc-server.js";
|
|
15
|
+
import { acquireBuildEnv, releaseBuildEnv } from "./build-env.js";
|
|
16
|
+
import { discoverRouters } from "./discover-routers.js";
|
|
17
|
+
import { writeRouteTypesFiles } from "./route-types-writer.js";
|
|
18
|
+
import { runShellPrerenderPhase } from "./shell-prerender-phase.js";
|
|
19
|
+
import { runRouterVersionsPhase } from "./router-versions-phase.js";
|
|
20
|
+
import { resetStagedBuildAssets } from "../utils/prerender-utils.js";
|
|
21
|
+
import { createRangoDebugger, timed, timedSync, NS } from "../debug.js";
|
|
22
|
+
|
|
23
|
+
const debugDiscovery = createRangoDebugger(NS.discovery);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Reset the per-build prerender collection state. A helper (not inline
|
|
27
|
+
* assignments in buildStart) so TS's property narrowing does not pin
|
|
28
|
+
* `s.shellCandidates` to `null` across the discovery call that repopulates
|
|
29
|
+
* it — the finally block re-reads it to decide the temp-server keep-alive.
|
|
30
|
+
*/
|
|
31
|
+
function resetPrerenderCollection(s: DiscoveryState): void {
|
|
32
|
+
s.prerenderManifestEntries = null;
|
|
33
|
+
s.staticManifestEntries = null;
|
|
34
|
+
s.shellCandidates = null;
|
|
35
|
+
s.prerenderPayloadValues = null;
|
|
36
|
+
s.buildData = [];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* buildStart. Build mode: create a temporary Vite dev server to access the
|
|
41
|
+
* RSC environment's module runner, then discover routers and generate
|
|
42
|
+
* manifests. The manifest data is stored for the virtual module's load hook.
|
|
43
|
+
*/
|
|
44
|
+
export async function buildDiscoveryPhase(
|
|
45
|
+
s: DiscoveryState,
|
|
46
|
+
context: Rolldown.PluginContext,
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
if (!s.isBuildMode) return;
|
|
49
|
+
// Only run once across environment builds
|
|
50
|
+
if (s.mergedRouteManifest !== null) {
|
|
51
|
+
debugDiscovery?.(
|
|
52
|
+
"build: skip (already discovered, env=%s)",
|
|
53
|
+
context.environment?.name ?? "?",
|
|
54
|
+
);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const buildStartTime = performance.now();
|
|
58
|
+
debugDiscovery?.("build: start (env=%s)", context.environment?.name ?? "?");
|
|
59
|
+
resetStagedBuildAssets(s.projectRoot);
|
|
60
|
+
resetPrerenderCollection(s);
|
|
61
|
+
|
|
62
|
+
// Acquire build-time env bindings if configured
|
|
63
|
+
await timed(debugDiscovery, "build acquireBuildEnv", () =>
|
|
64
|
+
acquireBuildEnv(s, s.viteCommand, s.viteMode),
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
let tempServer: any = null;
|
|
68
|
+
// Signal to user-space code (e.g. reverse.ts) that build-time discovery
|
|
69
|
+
// is active. Uses globalThis because the temp server's module runner
|
|
70
|
+
// creates a separate module context — there is no shared import path
|
|
71
|
+
// between the vite plugin and user code loaded via runner.import().
|
|
72
|
+
(globalThis as any).__rscRouterDiscoveryActive = true;
|
|
73
|
+
try {
|
|
74
|
+
tempServer = await timed(debugDiscovery, "build createTempRscServer", () =>
|
|
75
|
+
createTempRscServer(s, { forceBuild: true }),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const rscEnv = (tempServer.environments as any)?.rsc;
|
|
79
|
+
if (!rscEnv?.runner) {
|
|
80
|
+
console.warn(
|
|
81
|
+
"[rango] RSC environment runner not available during build, skipping manifest generation",
|
|
82
|
+
);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Point resolvedStaticModules at the temp server's expose-internal-ids
|
|
87
|
+
// plugin so that discoverRouters() can access the static handler module
|
|
88
|
+
// map after the temp server's transforms populate it.
|
|
89
|
+
const tempIdsPlugin = (tempServer as any).config?.plugins?.find(
|
|
90
|
+
(p: any) => p.name === "@rangojs/router:expose-internal-ids",
|
|
91
|
+
);
|
|
92
|
+
if (tempIdsPlugin?.api?.staticHandlerModules) {
|
|
93
|
+
s.resolvedStaticModules = tempIdsPlugin.api.staticHandlerModules;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await timed(debugDiscovery, "build discoverRouters", () =>
|
|
97
|
+
discoverRouters(s, rscEnv, (tempServer.environments as any)?.ssr),
|
|
98
|
+
);
|
|
99
|
+
// Update named-routes.gen.ts from runtime discovery.
|
|
100
|
+
// The runtime manifest includes dynamically generated routes
|
|
101
|
+
// that the static parser cannot extract from source code.
|
|
102
|
+
timedSync(debugDiscovery, "build writeRouteTypesFiles", () =>
|
|
103
|
+
writeRouteTypesFiles(s),
|
|
104
|
+
);
|
|
105
|
+
} catch (err: any) {
|
|
106
|
+
// Extract the user source file from the stack trace (skip internal frames)
|
|
107
|
+
const sourceFile = err.stack
|
|
108
|
+
?.split("\n")
|
|
109
|
+
.find(
|
|
110
|
+
(line: string) =>
|
|
111
|
+
line.includes(s.projectRoot) && !line.includes("node_modules"),
|
|
112
|
+
)
|
|
113
|
+
?.match(/\(([^)]+)\)/)?.[1];
|
|
114
|
+
// Extract the route name from "Unknown route: <name>" errors
|
|
115
|
+
const routeName = err.message?.match(/Unknown route: (.+)/)?.[1];
|
|
116
|
+
const details = [
|
|
117
|
+
routeName ? ` Route name: ${routeName}` : null,
|
|
118
|
+
sourceFile ? ` File: ${sourceFile}` : null,
|
|
119
|
+
err.stack ? ` Stack:\n${err.stack}` : null,
|
|
120
|
+
]
|
|
121
|
+
.filter(Boolean)
|
|
122
|
+
.join("\n");
|
|
123
|
+
throw new Error(`[rango] Build-time router discovery failed:\n${details}`, {
|
|
124
|
+
cause: err,
|
|
125
|
+
});
|
|
126
|
+
} finally {
|
|
127
|
+
delete (globalThis as any).__rscRouterDiscoveryActive;
|
|
128
|
+
if (tempServer && s.shellCandidates?.length) {
|
|
129
|
+
// Prerender+ppr candidates exist: keep the temp server (and its
|
|
130
|
+
// realm — tries installed, registry populated) alive for the
|
|
131
|
+
// post-build shell capture phase (buildApp post, producer B #699).
|
|
132
|
+
// The prelude embeds built client asset URLs, so the capture can
|
|
133
|
+
// only run after the client build; that phase closes the server.
|
|
134
|
+
// buildEnv release is deferred with it — a bake-lane loader
|
|
135
|
+
// executing during the capture may read ctx.env.
|
|
136
|
+
s.shellPhaseTempServer = tempServer;
|
|
137
|
+
} else {
|
|
138
|
+
if (tempServer) {
|
|
139
|
+
await timed(debugDiscovery, "build tempServer.close", () =>
|
|
140
|
+
tempServer.close(),
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
await releaseBuildEnv(s);
|
|
144
|
+
}
|
|
145
|
+
debugDiscovery?.(
|
|
146
|
+
"build discovery done (%sms)",
|
|
147
|
+
(performance.now() - buildStartTime).toFixed(1),
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* buildApp (post). Post-build phases, after EVERY environment bundle is
|
|
154
|
+
* written.
|
|
155
|
+
*
|
|
156
|
+
* 1. Cache versions (router-versions-phase.ts): hashes the server output as
|
|
157
|
+
* postprocessBundle left it and writes the per-router table into the
|
|
158
|
+
* built version module. First, because phase 2 stamps its entries with
|
|
159
|
+
* these versions and reads the same RSC out dir.
|
|
160
|
+
* 2. PPR shell capture (producer B, #699): the shell prelude embeds built
|
|
161
|
+
* client asset URLs (bootstrap entry), which do not exist at buildStart.
|
|
162
|
+
* The kept temp server and the buildEnv were deferred AS A PAIR in
|
|
163
|
+
* buildStart's finally; this finally is the pair's success-path owner
|
|
164
|
+
* (buildEndPhase owns the aborted-build path) — the phase itself is a pure
|
|
165
|
+
* producer and tears down only the globals it installs.
|
|
166
|
+
*/
|
|
167
|
+
export async function postBuildPhase(
|
|
168
|
+
s: DiscoveryState,
|
|
169
|
+
builder: ViteBuilder,
|
|
170
|
+
): Promise<void> {
|
|
171
|
+
try {
|
|
172
|
+
await runShellPrerenderPhase(
|
|
173
|
+
s,
|
|
174
|
+
builder as any,
|
|
175
|
+
runRouterVersionsPhase(s, builder as any),
|
|
176
|
+
);
|
|
177
|
+
} finally {
|
|
178
|
+
if (s.isBuildMode) {
|
|
179
|
+
const tempServer = s.shellPhaseTempServer;
|
|
180
|
+
s.shellPhaseTempServer = null;
|
|
181
|
+
if (tempServer) await tempServer.close();
|
|
182
|
+
await releaseBuildEnv(s);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* buildEnd. An environment build failure aborts the builder before the
|
|
189
|
+
* buildApp post hook — never leak the kept temp server (open handles hang
|
|
190
|
+
* the CLI) or the deferred buildEnv (a live miniflare proxy).
|
|
191
|
+
*/
|
|
192
|
+
export async function buildEndPhase(
|
|
193
|
+
s: DiscoveryState,
|
|
194
|
+
error: Error | undefined,
|
|
195
|
+
): Promise<void> {
|
|
196
|
+
if (!error || !s.shellPhaseTempServer) return;
|
|
197
|
+
const tempServer = s.shellPhaseTempServer;
|
|
198
|
+
s.shellPhaseTempServer = null;
|
|
199
|
+
try {
|
|
200
|
+
await tempServer.close();
|
|
201
|
+
} finally {
|
|
202
|
+
await releaseBuildEnv(s);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build-time env (rango({ buildEnv })): resolution of the option and the
|
|
3
|
+
* lifetime of the resolved bindings on DiscoveryState. Acquired by dev
|
|
4
|
+
* discovery (dev-server-phase.ts) and build discovery
|
|
5
|
+
* (build-discovery-phase.ts).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { dirname, join, resolve } from "node:path";
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
|
+
import { pathToFileURL } from "node:url";
|
|
12
|
+
import { BUILD_ENV_GLOBAL_KEY } from "../plugins/cloudflare-protocol-stub.js";
|
|
13
|
+
import type {
|
|
14
|
+
BuildEnvOption,
|
|
15
|
+
BuildEnvFactoryContext,
|
|
16
|
+
BuildEnvResult,
|
|
17
|
+
} from "../plugin-types.js";
|
|
18
|
+
import type { DiscoveryState } from "./state.js";
|
|
19
|
+
|
|
20
|
+
const WRANGLER_CONFIG_NAMES: readonly string[] = [
|
|
21
|
+
"wrangler.json",
|
|
22
|
+
"wrangler.jsonc",
|
|
23
|
+
"wrangler.toml",
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* getPlatformProxy() looks for the wrangler config from process.cwd() and
|
|
28
|
+
* resolves its default persist path against cwd, so building from another
|
|
29
|
+
* directory dropped the app's bindings (#1037). Search upward from the Vite
|
|
30
|
+
* root with wrangler's own file names and order. Persisted state goes under
|
|
31
|
+
* the Vite root, where @cloudflare/vite-plugin reads it in dev and preview
|
|
32
|
+
* (its getPersistenceRoot), also when the config sits above the root. No
|
|
33
|
+
* config found: no options, wrangler's own lookup.
|
|
34
|
+
*/
|
|
35
|
+
function wranglerProxyOptions(
|
|
36
|
+
root: string,
|
|
37
|
+
): Record<string, unknown> | undefined {
|
|
38
|
+
const viteRoot = resolve(root);
|
|
39
|
+
for (let dir = viteRoot; ; dir = dirname(dir)) {
|
|
40
|
+
for (const name of WRANGLER_CONFIG_NAMES) {
|
|
41
|
+
const configPath = join(dir, name);
|
|
42
|
+
if (existsSync(configPath)) {
|
|
43
|
+
return {
|
|
44
|
+
configPath,
|
|
45
|
+
persist: { path: join(viteRoot, ".wrangler", "state", "v3") },
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (dirname(dir) === dir) return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Resolve the buildEnv option into a concrete { env, dispose? } result.
|
|
55
|
+
* Handles all four input shapes: false, "auto", factory, plain object.
|
|
56
|
+
*/
|
|
57
|
+
export async function resolveBuildEnv(
|
|
58
|
+
option: BuildEnvOption | undefined,
|
|
59
|
+
factoryCtx: BuildEnvFactoryContext,
|
|
60
|
+
): Promise<BuildEnvResult | null> {
|
|
61
|
+
if (!option) return null;
|
|
62
|
+
|
|
63
|
+
if (option === "auto") {
|
|
64
|
+
if (factoryCtx.preset !== "cloudflare") {
|
|
65
|
+
throw new Error(
|
|
66
|
+
'[rango] buildEnv: "auto" is only supported with preset: "cloudflare". ' +
|
|
67
|
+
"Use a factory function or plain object for other presets.",
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
// Resolve wrangler from the user's project root (not the router package)
|
|
72
|
+
const userRequire = createRequire(
|
|
73
|
+
resolve(factoryCtx.root, "package.json"),
|
|
74
|
+
);
|
|
75
|
+
const wranglerPath = userRequire.resolve("wrangler");
|
|
76
|
+
const { getPlatformProxy } = (await import(
|
|
77
|
+
pathToFileURL(wranglerPath).href
|
|
78
|
+
)) as {
|
|
79
|
+
getPlatformProxy: (opts?: any) => Promise<any>;
|
|
80
|
+
};
|
|
81
|
+
const proxy = await getPlatformProxy(
|
|
82
|
+
wranglerProxyOptions(factoryCtx.root),
|
|
83
|
+
);
|
|
84
|
+
return {
|
|
85
|
+
env: proxy.env as Record<string, unknown>,
|
|
86
|
+
dispose: proxy.dispose,
|
|
87
|
+
};
|
|
88
|
+
} catch (err: any) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
'[rango] buildEnv: "auto" requires wrangler to be installed.\n' +
|
|
91
|
+
`Install it with: pnpm add -D wrangler\n${err.message}`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (typeof option === "function") {
|
|
97
|
+
return await option(factoryCtx);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Plain object
|
|
101
|
+
return { env: option };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Acquire build-time env bindings and store on discovery state.
|
|
106
|
+
* Returns true if env was acquired, false if buildEnv is disabled.
|
|
107
|
+
*/
|
|
108
|
+
export async function acquireBuildEnv(
|
|
109
|
+
s: DiscoveryState,
|
|
110
|
+
command: "serve" | "build",
|
|
111
|
+
mode: string,
|
|
112
|
+
): Promise<boolean> {
|
|
113
|
+
const option = s.opts?.buildEnv;
|
|
114
|
+
if (!option) return false;
|
|
115
|
+
|
|
116
|
+
const result = await resolveBuildEnv(option, {
|
|
117
|
+
root: s.projectRoot,
|
|
118
|
+
mode,
|
|
119
|
+
command,
|
|
120
|
+
preset: s.opts?.preset ?? "node",
|
|
121
|
+
});
|
|
122
|
+
if (!result) return false;
|
|
123
|
+
|
|
124
|
+
s.resolvedBuildEnv = result.env;
|
|
125
|
+
s.buildEnvDispose = result.dispose ?? null;
|
|
126
|
+
// Bridge the resolved env into `cloudflare:workers`'s stubbed `env`
|
|
127
|
+
// export so user code that does `import { env } from "cloudflare:workers"`
|
|
128
|
+
// sees the real bindings proxy during discovery + prerender instead of
|
|
129
|
+
// an empty object. The stub reads this global at module-evaluation time.
|
|
130
|
+
(globalThis as Record<string, unknown>)[BUILD_ENV_GLOBAL_KEY] = result.env;
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Release build-time env resources and clear state.
|
|
136
|
+
*/
|
|
137
|
+
export async function releaseBuildEnv(s: DiscoveryState): Promise<void> {
|
|
138
|
+
if (s.buildEnvDispose) {
|
|
139
|
+
try {
|
|
140
|
+
await s.buildEnvDispose();
|
|
141
|
+
} catch (err: any) {
|
|
142
|
+
console.warn(`[rango] buildEnv dispose failed: ${err.message}`);
|
|
143
|
+
}
|
|
144
|
+
s.buildEnvDispose = null;
|
|
145
|
+
}
|
|
146
|
+
s.resolvedBuildEnv = undefined;
|
|
147
|
+
delete (globalThis as Record<string, unknown>)[BUILD_ENV_GLOBAL_KEY];
|
|
148
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundle scan phase: the discovery plugin's generateBundle hook.
|
|
3
|
+
*
|
|
4
|
+
* Records the inputs of the per-router cache versions (build-versions.ts) for
|
|
5
|
+
* every environment and, during the RSC build, the RSC entry filename and the
|
|
6
|
+
* chunks holding Prerender/Static handler exports. closeBundle
|
|
7
|
+
* (bundle-postprocess.ts) uses them for handler code eviction and prerender
|
|
8
|
+
* data injection.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Rolldown } from "vite";
|
|
12
|
+
import type { DiscoveryState } from "./state.js";
|
|
13
|
+
import {
|
|
14
|
+
recordBundleFiles,
|
|
15
|
+
recordClientGraph,
|
|
16
|
+
recordServerGraph,
|
|
17
|
+
recordVersionModuleFiles,
|
|
18
|
+
} from "./build-versions.js";
|
|
19
|
+
import { extractHandlerExportsFromChunk } from "../utils/bundle-analysis.js";
|
|
20
|
+
import { createRangoDebugger, NS } from "../debug.js";
|
|
21
|
+
|
|
22
|
+
const debugBuild = createRangoDebugger(NS.build);
|
|
23
|
+
|
|
24
|
+
export function bundleScanPhase(
|
|
25
|
+
s: DiscoveryState,
|
|
26
|
+
context: Rolldown.PluginContext,
|
|
27
|
+
bundle: any,
|
|
28
|
+
): void {
|
|
29
|
+
// Inputs of the per-router cache versions (discovery/build-versions.ts).
|
|
30
|
+
// Each pass overwrites its slot: plugin-rsc runs the RSC and SSR builds
|
|
31
|
+
// twice, and the real pass comes last.
|
|
32
|
+
if (s.isBuildMode) {
|
|
33
|
+
const envName = context.environment?.name;
|
|
34
|
+
if (envName) {
|
|
35
|
+
s.versionModuleFiles.set(envName, recordVersionModuleFiles(bundle));
|
|
36
|
+
}
|
|
37
|
+
if (envName === "rsc") {
|
|
38
|
+
s.serverBuildGraph = recordServerGraph(context, bundle);
|
|
39
|
+
} else if (envName === "client") {
|
|
40
|
+
s.clientBuildGraph = recordClientGraph(context, bundle);
|
|
41
|
+
} else if (envName === "ssr") {
|
|
42
|
+
s.ssrBundle = recordBundleFiles(bundle);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (context.environment?.name !== "rsc") return;
|
|
46
|
+
const genStart = debugBuild ? performance.now() : 0;
|
|
47
|
+
|
|
48
|
+
// Record RSC entry chunk filename for closeBundle injection
|
|
49
|
+
for (const [fileName, chunk] of Object.entries(bundle) as [string, any][]) {
|
|
50
|
+
if (chunk.type === "chunk" && chunk.isEntry) {
|
|
51
|
+
s.rscEntryFileName = fileName;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!s.resolvedPrerenderModules?.size && !s.resolvedStaticModules?.size) {
|
|
57
|
+
debugBuild?.(
|
|
58
|
+
"generateBundle (rsc): no handlers to scan (%sms)",
|
|
59
|
+
(performance.now() - genStart).toFixed(1),
|
|
60
|
+
);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Clear maps at the start of each RSC generateBundle pass.
|
|
65
|
+
// Vite 6 multi-environment builds run RSC twice (analysis + production);
|
|
66
|
+
// clearing prevents stale/duplicate records from the analysis pass.
|
|
67
|
+
s.handlerChunkInfoMap.clear();
|
|
68
|
+
s.staticHandlerChunkInfoMap.clear();
|
|
69
|
+
|
|
70
|
+
for (const [fileName, chunk] of Object.entries(bundle) as [string, any][]) {
|
|
71
|
+
if (chunk.type !== "chunk") continue;
|
|
72
|
+
|
|
73
|
+
// Scan all chunks for handler exports (handlers may land in any chunk)
|
|
74
|
+
if (s.resolvedPrerenderModules?.size) {
|
|
75
|
+
const handlers = extractHandlerExportsFromChunk(
|
|
76
|
+
chunk.code,
|
|
77
|
+
s.resolvedPrerenderModules,
|
|
78
|
+
"Prerender",
|
|
79
|
+
false,
|
|
80
|
+
// Mark onDemand exports (retained, not evicted) from the
|
|
81
|
+
// discovery-derived $$id set — the same evaluated source that sets
|
|
82
|
+
// the runtime od trie flag, so retention and serve can never
|
|
83
|
+
// disagree. Populated by discoverRouters (buildStart), which runs
|
|
84
|
+
// before this generateBundle pass.
|
|
85
|
+
s.onDemandHandlerIds,
|
|
86
|
+
);
|
|
87
|
+
if (handlers.length > 0) {
|
|
88
|
+
const existing = s.handlerChunkInfoMap.get(fileName);
|
|
89
|
+
if (existing) {
|
|
90
|
+
existing.exports.push(...handlers);
|
|
91
|
+
} else {
|
|
92
|
+
s.handlerChunkInfoMap.set(fileName, {
|
|
93
|
+
fileName,
|
|
94
|
+
exports: handlers,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (s.resolvedStaticModules?.size) {
|
|
101
|
+
const handlers = extractHandlerExportsFromChunk(
|
|
102
|
+
chunk.code,
|
|
103
|
+
s.resolvedStaticModules,
|
|
104
|
+
"Static",
|
|
105
|
+
false,
|
|
106
|
+
);
|
|
107
|
+
if (handlers.length > 0) {
|
|
108
|
+
const existing = s.staticHandlerChunkInfoMap.get(fileName);
|
|
109
|
+
if (existing) {
|
|
110
|
+
existing.exports.push(...handlers);
|
|
111
|
+
} else {
|
|
112
|
+
s.staticHandlerChunkInfoMap.set(fileName, {
|
|
113
|
+
fileName,
|
|
114
|
+
exports: handlers,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
debugBuild?.(
|
|
122
|
+
"generateBundle (rsc): scanned %d chunks, %d prerender chunk(s), %d static chunk(s) (%sms)",
|
|
123
|
+
Object.keys(bundle).length,
|
|
124
|
+
s.handlerChunkInfoMap.size,
|
|
125
|
+
s.staticHandlerChunkInfoMap.size,
|
|
126
|
+
(performance.now() - genStart).toFixed(1),
|
|
127
|
+
);
|
|
128
|
+
}
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import type { SerializedSegmentData } from "../../cache/types.js";
|
|
26
|
+
import { interceptVariantSegments } from "../../prerender/store.js";
|
|
26
27
|
|
|
27
28
|
/** Structural slice of `matchForPrerender`'s result the payload derivation needs. */
|
|
28
29
|
export interface DevPrerenderMatchPayloadSource {
|
|
@@ -37,8 +38,9 @@ export interface DevPrerenderPayloadBodies {
|
|
|
37
38
|
/** `intercept != 1` response: the route's own segments + handles. */
|
|
38
39
|
main: string;
|
|
39
40
|
/**
|
|
40
|
-
* `intercept=1` response:
|
|
41
|
-
*
|
|
41
|
+
* `intercept=1` response: the build's intercept variant
|
|
42
|
+
* (interceptVariantSegments, prerender/store.ts) with the producer's handle
|
|
43
|
+
* string for it. Falls back to `main` byte-for-byte when the route has no
|
|
42
44
|
* intercept segments — mirroring the endpoint's historical behavior.
|
|
43
45
|
*/
|
|
44
46
|
intercept: string;
|
|
@@ -64,7 +66,10 @@ export function payloadBodiesFromResult(
|
|
|
64
66
|
});
|
|
65
67
|
const intercept = result.interceptSegments?.length
|
|
66
68
|
? JSON.stringify({
|
|
67
|
-
segments:
|
|
69
|
+
segments: interceptVariantSegments(
|
|
70
|
+
result.segments,
|
|
71
|
+
result.interceptSegments,
|
|
72
|
+
),
|
|
68
73
|
handles: result.interceptHandles ?? "",
|
|
69
74
|
})
|
|
70
75
|
: main;
|