@rangojs/router 0.0.0-experimental.8a4d0430 → 0.0.0-experimental.8bcfea43
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/AGENTS.md +4 -0
- package/README.md +126 -38
- package/dist/bin/rango.js +138 -50
- package/dist/vite/index.js +1171 -461
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +19 -16
- package/skills/breadcrumbs/SKILL.md +3 -1
- package/skills/cache-guide/SKILL.md +32 -0
- package/skills/caching/SKILL.md +45 -4
- package/skills/handler-use/SKILL.md +362 -0
- package/skills/hooks/SKILL.md +28 -20
- package/skills/intercept/SKILL.md +20 -0
- package/skills/layout/SKILL.md +22 -0
- package/skills/links/SKILL.md +91 -17
- package/skills/loader/SKILL.md +88 -45
- package/skills/middleware/SKILL.md +34 -3
- package/skills/migrate-nextjs/SKILL.md +560 -0
- package/skills/migrate-react-router/SKILL.md +765 -0
- package/skills/parallel/SKILL.md +185 -0
- package/skills/prerender/SKILL.md +110 -68
- package/skills/rango/SKILL.md +24 -22
- package/skills/response-routes/SKILL.md +8 -0
- package/skills/route/SKILL.md +55 -0
- package/skills/router-setup/SKILL.md +87 -2
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/typesafety/SKILL.md +13 -1
- package/src/__internal.ts +1 -1
- package/src/browser/app-shell.ts +52 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +5 -0
- package/src/browser/navigation-bridge.ts +90 -16
- package/src/browser/navigation-client.ts +167 -59
- package/src/browser/navigation-store.ts +68 -9
- package/src/browser/navigation-transaction.ts +11 -9
- package/src/browser/partial-update.ts +113 -17
- package/src/browser/prefetch/cache.ts +184 -16
- package/src/browser/prefetch/fetch.ts +180 -33
- package/src/browser/prefetch/policy.ts +6 -0
- package/src/browser/prefetch/queue.ts +123 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +53 -13
- package/src/browser/react/Link.tsx +81 -9
- package/src/browser/react/NavigationProvider.tsx +89 -14
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/use-handle.ts +9 -58
- package/src/browser/react/use-navigation.ts +22 -2
- package/src/browser/react/use-params.ts +11 -1
- package/src/browser/react/use-router.ts +29 -9
- package/src/browser/rsc-router.tsx +168 -65
- package/src/browser/scroll-restoration.ts +41 -42
- package/src/browser/segment-reconciler.ts +36 -9
- package/src/browser/server-action-bridge.ts +8 -6
- package/src/browser/types.ts +49 -5
- package/src/build/generate-manifest.ts +6 -6
- package/src/build/generate-route-types.ts +3 -0
- package/src/build/route-trie.ts +50 -24
- package/src/build/route-types/include-resolution.ts +8 -1
- package/src/build/route-types/router-processing.ts +223 -74
- 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 +455 -15
- 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.tsx +84 -230
- package/src/context-var.ts +72 -2
- package/src/debug.ts +2 -2
- package/src/handle.ts +40 -0
- package/src/index.rsc.ts +6 -1
- package/src/index.ts +49 -6
- package/src/outlet-context.ts +1 -1
- package/src/prerender/store.ts +5 -4
- package/src/prerender.ts +138 -77
- package/src/response-utils.ts +28 -0
- package/src/reverse.ts +27 -2
- package/src/route-definition/dsl-helpers.ts +240 -40
- package/src/route-definition/helpers-types.ts +67 -19
- package/src/route-definition/index.ts +3 -0
- package/src/route-definition/redirect.ts +11 -3
- package/src/route-definition/resolve-handler-use.ts +155 -0
- package/src/route-map-builder.ts +7 -1
- package/src/route-types.ts +18 -0
- package/src/router/content-negotiation.ts +100 -1
- package/src/router/find-match.ts +4 -2
- package/src/router/handler-context.ts +101 -25
- package/src/router/intercept-resolution.ts +11 -4
- package/src/router/lazy-includes.ts +10 -7
- package/src/router/loader-resolution.ts +159 -21
- package/src/router/logging.ts +5 -2
- package/src/router/manifest.ts +31 -16
- package/src/router/match-api.ts +127 -192
- package/src/router/match-middleware/background-revalidation.ts +30 -2
- package/src/router/match-middleware/cache-lookup.ts +94 -17
- 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 +104 -10
- package/src/router/metrics.ts +6 -1
- package/src/router/middleware-types.ts +8 -30
- package/src/router/middleware.ts +36 -10
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +60 -9
- package/src/router/prerender-match.ts +110 -10
- package/src/router/preview-match.ts +30 -102
- package/src/router/request-classification.ts +310 -0
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +6 -1
- package/src/router/router-interfaces.ts +36 -4
- package/src/router/router-options.ts +37 -11
- package/src/router/segment-resolution/fresh.ts +198 -20
- package/src/router/segment-resolution/helpers.ts +29 -24
- package/src/router/segment-resolution/loader-cache.ts +1 -0
- package/src/router/segment-resolution/revalidation.ts +438 -300
- package/src/router/segment-wrappers.ts +2 -0
- package/src/router/trie-matching.ts +10 -4
- package/src/router/types.ts +1 -0
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +60 -8
- package/src/rsc/handler.ts +478 -374
- package/src/rsc/helpers.ts +69 -41
- package/src/rsc/loader-fetch.ts +23 -3
- package/src/rsc/manifest-init.ts +5 -1
- package/src/rsc/progressive-enhancement.ts +16 -2
- package/src/rsc/response-route-handler.ts +14 -1
- package/src/rsc/rsc-rendering.ts +19 -1
- package/src/rsc/server-action.ts +10 -0
- package/src/rsc/ssr-setup.ts +2 -2
- package/src/rsc/types.ts +9 -1
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +109 -23
- package/src/server/context.ts +166 -17
- package/src/server/handle-store.ts +19 -0
- package/src/server/loader-registry.ts +9 -8
- package/src/server/request-context.ts +194 -60
- package/src/ssr/index.tsx +4 -0
- package/src/static-handler.ts +18 -6
- package/src/types/cache-types.ts +4 -4
- package/src/types/handler-context.ts +137 -65
- package/src/types/loader-types.ts +41 -15
- package/src/types/request-scope.ts +126 -0
- package/src/types/route-entry.ts +19 -1
- package/src/types/segments.ts +2 -0
- package/src/urls/include-helper.ts +24 -14
- package/src/urls/path-helper-types.ts +39 -6
- package/src/urls/path-helper.ts +48 -13
- package/src/urls/pattern-types.ts +12 -0
- package/src/urls/response-types.ts +18 -16
- package/src/use-loader.tsx +77 -5
- package/src/vite/debug.ts +55 -0
- package/src/vite/discovery/bundle-postprocess.ts +30 -33
- package/src/vite/discovery/discover-routers.ts +5 -1
- package/src/vite/discovery/prerender-collection.ts +128 -74
- package/src/vite/discovery/state.ts +13 -6
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +51 -79
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
- package/src/vite/plugins/expose-action-id.ts +1 -3
- package/src/vite/plugins/expose-id-utils.ts +12 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +30 -0
- package/src/vite/plugins/expose-internal-ids.ts +257 -40
- package/src/vite/plugins/performance-tracks.ts +86 -0
- package/src/vite/plugins/refresh-cmd.ts +88 -26
- package/src/vite/plugins/version-plugin.ts +13 -1
- package/src/vite/rango.ts +204 -217
- package/src/vite/router-discovery.ts +335 -64
- package/src/vite/utils/banner.ts +4 -4
- package/src/vite/utils/package-resolution.ts +41 -1
- package/src/vite/utils/prerender-utils.ts +37 -5
- package/src/vite/utils/shared-utils.ts +3 -2
|
@@ -51,93 +51,144 @@ export async function expandPrerenderRoutes(
|
|
|
51
51
|
return substituteRouteParams(pattern, params);
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
let resolvedRoutes = 0;
|
|
55
|
+
let totalDynamic = 0;
|
|
56
|
+
|
|
57
|
+
// Count dynamic routes upfront for progress reporting
|
|
54
58
|
for (const { manifest } of allManifests) {
|
|
55
59
|
if (!manifest.prerenderRoutes) continue;
|
|
56
|
-
const defs = manifest._prerenderDefs || {};
|
|
57
60
|
for (const routeName of manifest.prerenderRoutes) {
|
|
58
61
|
const pattern = manifest.routeManifest[routeName];
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
62
|
+
if (pattern && (pattern.includes(":") || pattern.includes("*"))) {
|
|
63
|
+
totalDynamic++;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Periodic progress log so long getParams() calls don't look stalled
|
|
69
|
+
const paramsStart = performance.now();
|
|
70
|
+
const progressInterval =
|
|
71
|
+
totalDynamic > 0
|
|
72
|
+
? setInterval(() => {
|
|
73
|
+
const elapsed = ((performance.now() - paramsStart) / 1000).toFixed(1);
|
|
74
|
+
console.log(
|
|
75
|
+
`[rsc-router] Resolving prerender params... ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`,
|
|
76
|
+
);
|
|
77
|
+
}, 5000)
|
|
78
|
+
: undefined;
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
for (const { manifest } of allManifests) {
|
|
82
|
+
if (!manifest.prerenderRoutes) continue;
|
|
83
|
+
const defs = manifest._prerenderDefs || {};
|
|
84
|
+
const passthroughSet = new Set(manifest.passthroughRoutes || []);
|
|
85
|
+
for (const routeName of manifest.prerenderRoutes) {
|
|
86
|
+
const pattern = manifest.routeManifest[routeName];
|
|
87
|
+
if (!pattern) continue;
|
|
88
|
+
const def = defs[routeName];
|
|
89
|
+
const isPassthroughRoute = passthroughSet.has(routeName);
|
|
90
|
+
const hasDynamic = pattern.includes(":") || pattern.includes("*");
|
|
91
|
+
if (!hasDynamic) {
|
|
92
|
+
// Static route: use pattern directly (strip trailing slash for URL)
|
|
93
|
+
entries.push({
|
|
94
|
+
urlPath: pattern.replace(/\/$/, "") || "/",
|
|
95
|
+
routeName,
|
|
96
|
+
concurrency: 1,
|
|
97
|
+
isPassthroughRoute,
|
|
98
|
+
});
|
|
99
|
+
} else {
|
|
100
|
+
// Dynamic route: call getParams() to enumerate param combinations
|
|
101
|
+
if (def?.getParams) {
|
|
102
|
+
try {
|
|
103
|
+
const buildVars: Record<string, any> = {};
|
|
104
|
+
const buildEnv = state.resolvedBuildEnv;
|
|
105
|
+
const getParamsCtx = {
|
|
106
|
+
build: true as const,
|
|
107
|
+
dev: !state.isBuildMode,
|
|
108
|
+
set: ((keyOrVar: any, value: any) => {
|
|
109
|
+
contextSet(buildVars, keyOrVar, value);
|
|
110
|
+
}) as any,
|
|
111
|
+
reverse: getParamsReverse,
|
|
112
|
+
get env() {
|
|
113
|
+
if (buildEnv !== undefined) return buildEnv;
|
|
114
|
+
throw new Error(
|
|
115
|
+
"[rsc-router] ctx.env is not available during build-time getParams(). " +
|
|
116
|
+
"Configure buildEnv in your rango() plugin options to enable build-time env access.",
|
|
117
|
+
);
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
const paramsList = await def.getParams(getParamsCtx);
|
|
121
|
+
const concurrency = def.options?.concurrency ?? 1;
|
|
122
|
+
const hasBuildVars =
|
|
123
|
+
Object.keys(buildVars).length > 0 ||
|
|
124
|
+
Object.getOwnPropertySymbols(buildVars).length > 0;
|
|
125
|
+
for (const params of paramsList) {
|
|
126
|
+
let url = substituteRouteParams(
|
|
127
|
+
pattern,
|
|
128
|
+
params as Record<string, string>,
|
|
129
|
+
encodePathParam,
|
|
130
|
+
);
|
|
131
|
+
// Anonymous wildcard fallback: use conventional keys if provided
|
|
132
|
+
if (url.includes("*")) {
|
|
133
|
+
const wildcardValue =
|
|
134
|
+
(params as Record<string, string>)["*"] ??
|
|
135
|
+
(params as Record<string, string>).splat;
|
|
136
|
+
if (wildcardValue !== undefined) {
|
|
137
|
+
url = url.replace(
|
|
138
|
+
/\*[^/]*$/,
|
|
139
|
+
encodePathParam(wildcardValue),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
101
142
|
}
|
|
143
|
+
entries.push({
|
|
144
|
+
urlPath: url.replace(/\/$/, "") || "/",
|
|
145
|
+
routeName,
|
|
146
|
+
concurrency,
|
|
147
|
+
...(hasBuildVars ? { buildVars } : {}),
|
|
148
|
+
isPassthroughRoute,
|
|
149
|
+
});
|
|
102
150
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
151
|
+
resolvedRoutes++;
|
|
152
|
+
} catch (err: any) {
|
|
153
|
+
resolvedRoutes++;
|
|
154
|
+
// Skip in getParams() skips the entire route
|
|
155
|
+
if (err.name === "Skip") {
|
|
156
|
+
console.log(
|
|
157
|
+
`[rsc-router] SKIP route "${routeName}" - ${err.message}`,
|
|
158
|
+
);
|
|
159
|
+
notifyOnError(
|
|
160
|
+
registry,
|
|
161
|
+
err,
|
|
162
|
+
"prerender",
|
|
163
|
+
routeName,
|
|
164
|
+
undefined,
|
|
165
|
+
true,
|
|
166
|
+
);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
// Regular error: fail the build
|
|
170
|
+
console.error(
|
|
171
|
+
`[rsc-router] Failed to get params for prerender route "${routeName}": ${err.message}`,
|
|
124
172
|
);
|
|
125
|
-
|
|
173
|
+
notifyOnError(registry, err, "prerender", routeName);
|
|
174
|
+
throw err;
|
|
126
175
|
}
|
|
127
|
-
|
|
128
|
-
console.
|
|
129
|
-
`[rsc-router]
|
|
176
|
+
} else {
|
|
177
|
+
console.warn(
|
|
178
|
+
`[rsc-router] Dynamic prerender route "${routeName}" has no getParams(), skipping`,
|
|
130
179
|
);
|
|
131
|
-
notifyOnError(registry, err, "prerender", routeName);
|
|
132
|
-
throw err;
|
|
133
180
|
}
|
|
134
|
-
} else {
|
|
135
|
-
console.warn(
|
|
136
|
-
`[rsc-router] Dynamic prerender route "${routeName}" has no getParams(), skipping`,
|
|
137
|
-
);
|
|
138
181
|
}
|
|
139
182
|
}
|
|
140
183
|
}
|
|
184
|
+
} finally {
|
|
185
|
+
if (progressInterval) {
|
|
186
|
+
clearInterval(progressInterval);
|
|
187
|
+
const elapsed = ((performance.now() - paramsStart) / 1000).toFixed(1);
|
|
188
|
+
console.log(
|
|
189
|
+
`[rsc-router] Resolved prerender params: ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
141
192
|
}
|
|
142
193
|
|
|
143
194
|
if (entries.length === 0) return;
|
|
@@ -175,6 +226,7 @@ export async function expandPrerenderRoutes(
|
|
|
175
226
|
{},
|
|
176
227
|
entry.buildVars,
|
|
177
228
|
entry.isPassthroughRoute,
|
|
229
|
+
state.resolvedBuildEnv,
|
|
178
230
|
);
|
|
179
231
|
if (!result) continue;
|
|
180
232
|
|
|
@@ -326,6 +378,8 @@ export async function renderStaticHandlers(
|
|
|
326
378
|
def.handler,
|
|
327
379
|
def.$$id,
|
|
328
380
|
(def as any).$$routePrefix,
|
|
381
|
+
state.resolvedBuildEnv,
|
|
382
|
+
!state.isBuildMode,
|
|
329
383
|
);
|
|
330
384
|
if (result) {
|
|
331
385
|
const hasHandles = Object.keys(result.handles).length > 0;
|
|
@@ -13,11 +13,13 @@ export const VIRTUAL_ROUTES_MANIFEST_ID = "virtual:rsc-router/routes-manifest";
|
|
|
13
13
|
export interface PluginOptions {
|
|
14
14
|
enableBuildPrerender?: boolean;
|
|
15
15
|
staticRouteTypesGeneration?: boolean;
|
|
16
|
-
include?: string[];
|
|
17
|
-
exclude?: string[];
|
|
18
16
|
// Mutable ref for deferred auto-discovery (node preset).
|
|
19
17
|
// The auto-discover config() hook populates this before configResolved.
|
|
20
18
|
routerPathRef?: { path?: string };
|
|
19
|
+
/** Build-time env option from rango() config. */
|
|
20
|
+
buildEnv?: import("../plugin-types.js").BuildEnvOption;
|
|
21
|
+
/** Deployment preset (needed for buildEnv "auto" resolution). */
|
|
22
|
+
preset?: "node" | "cloudflare";
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
export interface PrecomputedEntry {
|
|
@@ -58,8 +60,8 @@ export interface DiscoveryState {
|
|
|
58
60
|
|
|
59
61
|
prerenderManifestEntries: Record<string, string> | null;
|
|
60
62
|
staticManifestEntries: Record<string, string> | null;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
handlerChunkInfoMap: Map<string, ChunkInfo>;
|
|
64
|
+
staticHandlerChunkInfoMap: Map<string, ChunkInfo>;
|
|
63
65
|
rscEntryFileName: string | null;
|
|
64
66
|
resolvedPrerenderModules: Map<string, string[]> | undefined;
|
|
65
67
|
resolvedStaticModules: Map<string, string[]> | undefined;
|
|
@@ -69,6 +71,11 @@ export interface DiscoveryState {
|
|
|
69
71
|
devServer: any;
|
|
70
72
|
selfWrittenGenFiles: Map<string, { at: number; hash: string }>;
|
|
71
73
|
SELF_WRITE_WINDOW_MS: number;
|
|
74
|
+
|
|
75
|
+
/** Resolved build-time env bindings (set during buildStart/configureServer). */
|
|
76
|
+
resolvedBuildEnv?: Record<string, unknown>;
|
|
77
|
+
/** Cleanup function for build-time env resources (e.g., miniflare). */
|
|
78
|
+
buildEnvDispose?: (() => Promise<void> | void) | null;
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
export function createDiscoveryState(
|
|
@@ -95,8 +102,8 @@ export function createDiscoveryState(
|
|
|
95
102
|
|
|
96
103
|
prerenderManifestEntries: null,
|
|
97
104
|
staticManifestEntries: null,
|
|
98
|
-
|
|
99
|
-
|
|
105
|
+
handlerChunkInfoMap: new Map(),
|
|
106
|
+
staticHandlerChunkInfoMap: new Map(),
|
|
100
107
|
rscEntryFileName: null,
|
|
101
108
|
resolvedPrerenderModules: undefined,
|
|
102
109
|
resolvedStaticModules: undefined,
|
package/src/vite/index.ts
CHANGED
package/src/vite/plugin-types.ts
CHANGED
|
@@ -1,38 +1,53 @@
|
|
|
1
|
+
// -- Build-time environment types -------------------------------------------
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
+
* Context passed to a buildEnv factory function.
|
|
5
|
+
* Provides Vite config details for conditional env setup.
|
|
4
6
|
*/
|
|
5
|
-
export interface
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
export interface BuildEnvFactoryContext {
|
|
8
|
+
/** Vite project root directory. */
|
|
9
|
+
root: string;
|
|
10
|
+
/** Vite mode (e.g. "development", "production"). */
|
|
11
|
+
mode: string;
|
|
12
|
+
/** Vite command ("serve" for dev, "build" for production). */
|
|
13
|
+
command: "serve" | "build";
|
|
14
|
+
/** Router deployment preset. */
|
|
15
|
+
preset: "node" | "cloudflare";
|
|
16
|
+
}
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Factory function that creates build-time environment bindings.
|
|
20
|
+
* Called once at plugin startup. Return `dispose` to clean up resources.
|
|
21
|
+
*/
|
|
22
|
+
export type BuildEnvFactory = (
|
|
23
|
+
ctx: BuildEnvFactoryContext,
|
|
24
|
+
) => Promise<BuildEnvResult> | BuildEnvResult;
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Result of resolving build-time environment bindings.
|
|
28
|
+
*/
|
|
29
|
+
export interface BuildEnvResult {
|
|
30
|
+
/** Environment bindings available to Prerender/Static handlers via ctx.env. */
|
|
31
|
+
env: Record<string, unknown>;
|
|
32
|
+
/** Called after build completes to clean up resources (e.g., miniflare). */
|
|
33
|
+
dispose?: () => Promise<void> | void;
|
|
23
34
|
}
|
|
24
35
|
|
|
25
36
|
/**
|
|
26
|
-
*
|
|
37
|
+
* Build-time environment configuration for Prerender and Static handlers.
|
|
38
|
+
*
|
|
39
|
+
* - `false` (default): no build-time env, `ctx.env` throws.
|
|
40
|
+
* - `"auto"`: calls `wrangler.getPlatformProxy()` (cloudflare preset only).
|
|
41
|
+
* - Object: used directly as `ctx.env` during build.
|
|
42
|
+
* - Factory: called once at startup, must return `{ env, dispose? }`.
|
|
27
43
|
*/
|
|
28
|
-
export
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
44
|
+
export type BuildEnvOption =
|
|
45
|
+
| false
|
|
46
|
+
| "auto"
|
|
47
|
+
| Record<string, unknown>
|
|
48
|
+
| BuildEnvFactory;
|
|
49
|
+
|
|
50
|
+
// -- Plugin options ---------------------------------------------------------
|
|
36
51
|
|
|
37
52
|
/**
|
|
38
53
|
* Base options shared by all presets
|
|
@@ -45,27 +60,16 @@ interface RangoBaseOptions {
|
|
|
45
60
|
banner?: boolean;
|
|
46
61
|
|
|
47
62
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
* Glob patterns for files to include in route type scanning.
|
|
57
|
-
* Only files matching at least one pattern will be scanned.
|
|
58
|
-
* Patterns are relative to the project root.
|
|
59
|
-
* When unset, all .ts/.tsx files are scanned.
|
|
60
|
-
*/
|
|
61
|
-
include?: string[];
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Glob patterns for files to exclude from route type scanning.
|
|
65
|
-
* Takes precedence over `include`. Patterns are relative to the project root.
|
|
66
|
-
* Defaults to common test/build directories.
|
|
63
|
+
* Environment bindings available to Prerender and Static handlers at build
|
|
64
|
+
* time via `ctx.env`. Applies to both production build and dev on-demand
|
|
65
|
+
* prerender (`/__rsc_prerender`).
|
|
66
|
+
*
|
|
67
|
+
* This is the build-time env supplied by the Vite plugin, not the live
|
|
68
|
+
* request env. It is shared across all prerender invocations for the build.
|
|
69
|
+
*
|
|
70
|
+
* @default false
|
|
67
71
|
*/
|
|
68
|
-
|
|
72
|
+
buildEnv?: BuildEnvOption;
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
/**
|
|
@@ -76,38 +80,6 @@ export interface RangoNodeOptions extends RangoBaseOptions {
|
|
|
76
80
|
* Deployment preset. Defaults to 'node' when not specified.
|
|
77
81
|
*/
|
|
78
82
|
preset?: "node";
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Path to your router configuration file that exports the route tree.
|
|
82
|
-
* This file must export a `router` object created with `createRouter()`.
|
|
83
|
-
*
|
|
84
|
-
* When omitted, auto-discovers the router by scanning for files containing
|
|
85
|
-
* `createRouter`. If exactly one is found, it is used automatically.
|
|
86
|
-
* If multiple are found, an error is thrown with the list of candidates.
|
|
87
|
-
*
|
|
88
|
-
* @example
|
|
89
|
-
* ```ts
|
|
90
|
-
* rango({ router: './src/router.tsx' })
|
|
91
|
-
* // or simply:
|
|
92
|
-
* rango()
|
|
93
|
-
* ```
|
|
94
|
-
*/
|
|
95
|
-
router?: string;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* RSC plugin configuration. By default, rsc-router includes @vitejs/plugin-rsc
|
|
99
|
-
* with sensible defaults.
|
|
100
|
-
*
|
|
101
|
-
* Entry files (browser, ssr, rsc) are optional - if they don't exist,
|
|
102
|
-
* virtual defaults are used.
|
|
103
|
-
*
|
|
104
|
-
* - Omit or pass `true`/`{}` to use defaults (recommended)
|
|
105
|
-
* - Pass `{ entries: {...} }` to customize entry paths
|
|
106
|
-
* - Pass `false` to disable (for manual @vitejs/plugin-rsc configuration)
|
|
107
|
-
*
|
|
108
|
-
* @default true
|
|
109
|
-
*/
|
|
110
|
-
rsc?: boolean | RscPluginOptions;
|
|
111
83
|
}
|
|
112
84
|
|
|
113
85
|
/**
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface LoaderResolveContext {
|
|
2
|
+
parentURL?: string;
|
|
3
|
+
conditions?: readonly string[];
|
|
4
|
+
importAttributes?: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface LoaderResolveResult {
|
|
8
|
+
shortCircuit?: boolean;
|
|
9
|
+
url: string;
|
|
10
|
+
format?: "module" | "commonjs" | "json" | "wasm" | null;
|
|
11
|
+
importAttributes?: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type NextResolve = (
|
|
15
|
+
specifier: string,
|
|
16
|
+
context?: LoaderResolveContext,
|
|
17
|
+
) => Promise<LoaderResolveResult>;
|
|
18
|
+
|
|
19
|
+
export function resolve(
|
|
20
|
+
specifier: string,
|
|
21
|
+
context: LoaderResolveContext,
|
|
22
|
+
nextResolve: NextResolve,
|
|
23
|
+
): Promise<LoaderResolveResult>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Node ESM loader hook that resolves `cloudflare:*` imports to the same
|
|
2
|
+
// stub ESM the Vite transform produces for rewritten specifiers.
|
|
3
|
+
//
|
|
4
|
+
// Why both? The Vite transform (cloudflare-protocol-stub.ts) catches
|
|
5
|
+
// imports in modules that flow through Vite's plugin pipeline — covers
|
|
6
|
+
// user source and any node_modules package Vite fetches and transforms.
|
|
7
|
+
// But Vite/Rollup externalize certain packages (e.g. `partyserver`,
|
|
8
|
+
// which has `import { DurableObject, env } from "cloudflare:workers"`
|
|
9
|
+
// at its top level, and similar "workerd-native" libraries). Externalized
|
|
10
|
+
// modules bypass the transform: Rollup hands their resolution to Node's
|
|
11
|
+
// native ESM loader, which rejects URL-scheme specifiers. This loader
|
|
12
|
+
// hook registers via `module.register()` from `createTempRscServer` and
|
|
13
|
+
// intercepts `cloudflare:*` at Node's resolve layer — before the default
|
|
14
|
+
// loader throws ERR_UNSUPPORTED_ESM_URL_SCHEME.
|
|
15
|
+
//
|
|
16
|
+
// Lifecycle: the hook runs in a dedicated worker thread (Node ESM loader
|
|
17
|
+
// architecture) with its own globalThis. It cannot see the main thread's
|
|
18
|
+
// `__rango_build_env__` bridge, so the `env` export here is always `{}`.
|
|
19
|
+
// That's fine in practice — externalized libraries don't typically touch
|
|
20
|
+
// `env` at module top level; they read it at request time in workerd
|
|
21
|
+
// where the real module exists. Build-time prerender handlers in user
|
|
22
|
+
// source DO read `env`, but they flow through the Vite transform (which
|
|
23
|
+
// does bridge `env` from `getPlatformProxy()`), not through this loader.
|
|
24
|
+
//
|
|
25
|
+
// Keep STUBS in sync with cloudflare-protocol-stub.ts — both paths need
|
|
26
|
+
// to hand out the same base classes.
|
|
27
|
+
|
|
28
|
+
const CF_PREFIX = "cloudflare:";
|
|
29
|
+
|
|
30
|
+
const STUBS = {
|
|
31
|
+
"cloudflare:workers": `
|
|
32
|
+
export class DurableObject { constructor(_ctx, _env) {} }
|
|
33
|
+
export class WorkerEntrypoint { constructor(_ctx, _env) {} }
|
|
34
|
+
export class WorkflowEntrypoint { constructor(_ctx, _env) {} }
|
|
35
|
+
export class RpcTarget {}
|
|
36
|
+
export const env = {};
|
|
37
|
+
export default {};
|
|
38
|
+
`,
|
|
39
|
+
"cloudflare:email": `
|
|
40
|
+
export class EmailMessage { constructor(_from, _to, _raw) {} }
|
|
41
|
+
export default {};
|
|
42
|
+
`,
|
|
43
|
+
"cloudflare:sockets": `
|
|
44
|
+
export function connect() { return {}; }
|
|
45
|
+
export default {};
|
|
46
|
+
`,
|
|
47
|
+
"cloudflare:workflows": `
|
|
48
|
+
export class NonRetryableError extends Error {
|
|
49
|
+
constructor(message, name) { super(message); this.name = name ?? "NonRetryableError"; }
|
|
50
|
+
}
|
|
51
|
+
export default {};
|
|
52
|
+
`,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Policy: unknown `cloudflare:*` specifiers resolve permissively to an
|
|
56
|
+
// empty default export rather than throwing. Same reasoning as
|
|
57
|
+
// cloudflare-protocol-stub.ts's FALLBACK_STUB — we prioritize
|
|
58
|
+
// dependency-graph resilience over strict validation, because third-party
|
|
59
|
+
// packages can pull `cloudflare:*` modules we haven't curated.
|
|
60
|
+
const FALLBACK_STUB = `export default {};\n`;
|
|
61
|
+
|
|
62
|
+
function dataUrlFor(specifier) {
|
|
63
|
+
const body = STUBS[specifier] ?? FALLBACK_STUB;
|
|
64
|
+
return "data:text/javascript;base64," + Buffer.from(body).toString("base64");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function resolve(specifier, context, nextResolve) {
|
|
68
|
+
if (specifier.startsWith(CF_PREFIX)) {
|
|
69
|
+
return {
|
|
70
|
+
shortCircuit: true,
|
|
71
|
+
url: dataUrlFor(specifier),
|
|
72
|
+
format: "module",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return nextResolve(specifier, context);
|
|
76
|
+
}
|