@rangojs/router 0.0.0-experimental.8 → 0.0.0-experimental.80
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 +9 -0
- package/README.md +942 -4
- package/dist/bin/rango.js +1689 -0
- package/dist/vite/index.js +4960 -935
- package/package.json +70 -60
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +294 -0
- package/skills/caching/SKILL.md +93 -23
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- package/skills/document-cache/SKILL.md +18 -16
- package/skills/fonts/SKILL.md +167 -0
- package/skills/handler-use/SKILL.md +362 -0
- package/skills/hooks/SKILL.md +334 -72
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +151 -8
- package/skills/layout/SKILL.md +122 -3
- package/skills/links/SKILL.md +92 -31
- package/skills/loader/SKILL.md +404 -44
- package/skills/middleware/SKILL.md +205 -37
- package/skills/migrate-nextjs/SKILL.md +560 -0
- package/skills/migrate-react-router/SKILL.md +764 -0
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +263 -1
- package/skills/prerender/SKILL.md +685 -0
- package/skills/rango/SKILL.md +87 -16
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +281 -14
- package/skills/router-setup/SKILL.md +210 -32
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +328 -89
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +102 -4
- package/src/bin/rango.ts +321 -0
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +92 -64
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +317 -560
- package/src/browser/navigation-client.ts +206 -68
- package/src/browser/navigation-store.ts +73 -55
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +343 -316
- package/src/browser/prefetch/cache.ts +216 -0
- package/src/browser/prefetch/fetch.ts +206 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +160 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +253 -74
- package/src/browser/react/NavigationProvider.tsx +87 -11
- package/src/browser/react/context.ts +11 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +12 -12
- package/src/browser/react/location-state-shared.ts +95 -53
- package/src/browser/react/location-state.ts +60 -15
- package/src/browser/react/mount-context.ts +6 -1
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +29 -51
- package/src/browser/react/use-client-cache.ts +5 -3
- package/src/browser/react/use-handle.ts +30 -126
- package/src/browser/react/use-href.tsx +2 -2
- package/src/browser/react/use-link-status.ts +6 -5
- package/src/browser/react/use-navigation.ts +44 -65
- package/src/browser/react/use-params.ts +65 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-router.ts +76 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +80 -97
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +214 -58
- package/src/browser/scroll-restoration.ts +127 -52
- package/src/browser/segment-reconciler.ts +243 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +510 -603
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +141 -48
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +235 -24
- package/src/build/generate-route-types.ts +39 -0
- package/src/build/index.ts +13 -0
- package/src/build/route-trie.ts +291 -0
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +98 -0
- package/src/build/route-types/codegen.ts +102 -0
- package/src/build/route-types/include-resolution.ts +418 -0
- package/src/build/route-types/param-extraction.ts +48 -0
- package/src/build/route-types/per-module-writer.ts +128 -0
- package/src/build/route-types/router-processing.ts +618 -0
- package/src/build/route-types/scan-filter.ts +85 -0
- package/src/build/runtime-discovery.ts +231 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +342 -0
- package/src/cache/cache-scope.ts +167 -309
- package/src/cache/cf/cf-cache-store.ts +571 -17
- package/src/cache/cf/index.ts +13 -3
- package/src/cache/document-cache.ts +116 -77
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +1 -15
- package/src/cache/memory-segment-store.ts +191 -13
- package/src/cache/profile-registry.ts +73 -0
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +256 -0
- package/src/cache/taint.ts +153 -0
- package/src/cache/types.ts +72 -122
- package/src/client.rsc.tsx +3 -1
- package/src/client.tsx +135 -301
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +5 -1
- package/src/context-var.ts +156 -0
- package/src/debug.ts +19 -9
- package/src/errors.ts +108 -2
- package/src/handle.ts +55 -29
- package/src/handles/MetaTags.tsx +73 -20
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/handles/meta.ts +30 -13
- package/src/host/cookie-handler.ts +21 -15
- package/src/host/errors.ts +8 -8
- package/src/host/index.ts +4 -7
- package/src/host/pattern-matcher.ts +27 -27
- package/src/host/router.ts +61 -39
- package/src/host/testing.ts +8 -8
- package/src/host/types.ts +15 -7
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +119 -29
- package/src/index.rsc.ts +155 -19
- package/src/index.ts +251 -30
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +26 -157
- package/src/loader.ts +27 -10
- package/src/network-error-thrower.tsx +3 -1
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +37 -0
- package/src/prerender/store.ts +186 -0
- package/src/prerender.ts +524 -0
- package/src/reverse.ts +354 -0
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +1121 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +478 -0
- package/src/route-definition/index.ts +55 -0
- package/src/route-definition/redirect.ts +101 -0
- package/src/route-definition/resolve-handler-use.ts +149 -0
- package/src/route-definition.ts +1 -1428
- package/src/route-map-builder.ts +217 -123
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +77 -8
- package/src/router/content-negotiation.ts +215 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +9 -9
- package/src/router/find-match.ts +160 -0
- package/src/router/handler-context.ts +438 -86
- package/src/router/intercept-resolution.ts +402 -0
- package/src/router/lazy-includes.ts +237 -0
- package/src/router/loader-resolution.ts +356 -128
- package/src/router/logging.ts +251 -0
- package/src/router/manifest.ts +163 -35
- package/src/router/match-api.ts +555 -0
- package/src/router/match-context.ts +5 -3
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +108 -93
- package/src/router/match-middleware/cache-lookup.ts +460 -10
- package/src/router/match-middleware/cache-store.ts +98 -26
- package/src/router/match-middleware/intercept-resolution.ts +57 -17
- package/src/router/match-middleware/segment-resolution.ts +80 -6
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +135 -35
- package/src/router/metrics.ts +240 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +220 -0
- package/src/router/middleware.ts +324 -369
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +211 -43
- package/src/router/prerender-match.ts +502 -0
- package/src/router/preview-match.ts +98 -0
- package/src/router/request-classification.ts +310 -0
- package/src/router/revalidation.ts +137 -38
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +41 -21
- package/src/router/router-interfaces.ts +484 -0
- package/src/router/router-options.ts +618 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +748 -0
- package/src/router/segment-resolution/helpers.ts +268 -0
- package/src/router/segment-resolution/loader-cache.ts +199 -0
- package/src/router/segment-resolution/revalidation.ts +1379 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -0
- package/src/router/segment-wrappers.ts +291 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +239 -0
- package/src/router/types.ts +78 -3
- package/src/router.ts +740 -4252
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +907 -797
- package/src/rsc/helpers.ts +140 -6
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +229 -0
- package/src/rsc/manifest-init.ts +90 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +391 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +246 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +356 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +46 -11
- package/src/search-params.ts +230 -0
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +134 -36
- package/src/server/context.ts +341 -61
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +113 -15
- package/src/server/loader-registry.ts +24 -64
- package/src/server/request-context.ts +607 -81
- package/src/server.ts +35 -130
- package/src/ssr/index.tsx +103 -30
- package/src/static-handler.ts +126 -0
- package/src/theme/ThemeProvider.tsx +21 -15
- package/src/theme/ThemeScript.tsx +5 -5
- package/src/theme/constants.ts +5 -2
- package/src/theme/index.ts +4 -14
- package/src/theme/theme-context.ts +4 -30
- package/src/theme/theme-script.ts +21 -18
- package/src/types/boundaries.ts +158 -0
- package/src/types/cache-types.ts +198 -0
- package/src/types/error-types.ts +192 -0
- package/src/types/global-namespace.ts +100 -0
- package/src/types/handler-context.ts +791 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +210 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +120 -0
- package/src/types/segments.ts +150 -0
- package/src/types.ts +1 -1623
- package/src/urls/include-helper.ts +207 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +372 -0
- package/src/urls/path-helper.ts +364 -0
- package/src/urls/pattern-types.ts +107 -0
- package/src/urls/response-types.ts +116 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -802
- package/src/use-loader.tsx +161 -81
- package/src/vite/discovery/bundle-postprocess.ts +181 -0
- package/src/vite/discovery/discover-routers.ts +348 -0
- package/src/vite/discovery/prerender-collection.ts +439 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +47 -0
- package/src/vite/discovery/state.ts +117 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +15 -1133
- package/src/vite/plugin-types.ts +103 -0
- package/src/vite/plugins/cjs-to-esm.ts +93 -0
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/client-ref-hashing.ts +105 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -53
- package/src/vite/plugins/expose-id-utils.ts +299 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +786 -0
- package/src/vite/plugins/performance-tracks.ts +88 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +323 -0
- package/src/vite/plugins/version-injector.ts +83 -0
- package/src/vite/plugins/version-plugin.ts +266 -0
- package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +462 -0
- package/src/vite/router-discovery.ts +918 -0
- package/src/vite/utils/ast-handler-extract.ts +517 -0
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +137 -0
- package/src/vite/utils/manifest-utils.ts +70 -0
- package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
- package/src/vite/utils/prerender-utils.ts +221 -0
- package/src/vite/utils/shared-utils.ts +170 -0
- package/CLAUDE.md +0 -43
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/memory-store.ts +0 -253
- package/src/href-context.ts +0 -33
- package/src/href.ts +0 -255
- package/src/server/route-manifest-cache.ts +0 -173
- package/src/vite/expose-handle-id.ts +0 -209
- package/src/vite/expose-loader-id.ts +0 -426
- package/src/vite/expose-location-state-id.ts +0 -177
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-Generated File Tracking
|
|
3
|
+
*
|
|
4
|
+
* Tracks gen files recently written by the discovery plugin so the
|
|
5
|
+
* file watcher can distinguish self-triggered change events from
|
|
6
|
+
* manual edits.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import type { DiscoveryState } from "./state.js";
|
|
12
|
+
|
|
13
|
+
export function markSelfGenWrite(
|
|
14
|
+
state: DiscoveryState,
|
|
15
|
+
filePath: string,
|
|
16
|
+
content: string,
|
|
17
|
+
): void {
|
|
18
|
+
const hash = createHash("sha256").update(content).digest("hex");
|
|
19
|
+
state.selfWrittenGenFiles.set(filePath, { at: Date.now(), hash });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function consumeSelfGenWrite(
|
|
23
|
+
state: DiscoveryState,
|
|
24
|
+
filePath: string,
|
|
25
|
+
): boolean {
|
|
26
|
+
const info = state.selfWrittenGenFiles.get(filePath);
|
|
27
|
+
if (!info) return false;
|
|
28
|
+
if (Date.now() - info.at > state.SELF_WRITE_WINDOW_MS) {
|
|
29
|
+
state.selfWrittenGenFiles.delete(filePath);
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const current = readFileSync(filePath, "utf-8");
|
|
34
|
+
const currentHash = createHash("sha256").update(current).digest("hex");
|
|
35
|
+
if (currentHash === info.hash) {
|
|
36
|
+
state.selfWrittenGenFiles.delete(filePath);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
// Hash mismatch: file was changed externally. Keep the entry so a
|
|
40
|
+
// subsequent watcher event from our own write can still be consumed
|
|
41
|
+
// (e.g. when multiple Vite servers watch the same directory).
|
|
42
|
+
return false;
|
|
43
|
+
} catch {
|
|
44
|
+
state.selfWrittenGenFiles.delete(filePath);
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery State
|
|
3
|
+
*
|
|
4
|
+
* Shared mutable state for the router discovery plugin.
|
|
5
|
+
* Created once by createRouterDiscoveryPlugin() and passed
|
|
6
|
+
* to all extracted helper functions.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ScanFilter } from "../../build/generate-route-types.js";
|
|
10
|
+
|
|
11
|
+
export const VIRTUAL_ROUTES_MANIFEST_ID = "virtual:rsc-router/routes-manifest";
|
|
12
|
+
|
|
13
|
+
export interface PluginOptions {
|
|
14
|
+
enableBuildPrerender?: boolean;
|
|
15
|
+
staticRouteTypesGeneration?: boolean;
|
|
16
|
+
// Mutable ref for deferred auto-discovery (node preset).
|
|
17
|
+
// The auto-discover config() hook populates this before configResolved.
|
|
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";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface PrecomputedEntry {
|
|
26
|
+
staticPrefix: string;
|
|
27
|
+
routes: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ChunkInfo {
|
|
31
|
+
fileName: string;
|
|
32
|
+
exports: Array<{ name: string; handlerId: string; passthrough: boolean }>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface PerRouterManifestEntry {
|
|
36
|
+
id: string;
|
|
37
|
+
routeManifest: Record<string, string>;
|
|
38
|
+
routeSearchSchemas?: Record<string, Record<string, string>>;
|
|
39
|
+
sourceFile?: string;
|
|
40
|
+
factoryOnlyPrefixes?: Set<string>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface DiscoveryState {
|
|
44
|
+
resolvedEntryPath: string | undefined;
|
|
45
|
+
projectRoot: string;
|
|
46
|
+
isBuildMode: boolean;
|
|
47
|
+
userResolveAlias: any;
|
|
48
|
+
scanFilter: ScanFilter | undefined;
|
|
49
|
+
cachedRouterFiles: string[] | undefined;
|
|
50
|
+
opts: PluginOptions | undefined;
|
|
51
|
+
|
|
52
|
+
mergedRouteManifest: Record<string, string> | null;
|
|
53
|
+
perRouterManifests: PerRouterManifestEntry[];
|
|
54
|
+
mergedPrecomputedEntries: PrecomputedEntry[] | null;
|
|
55
|
+
mergedRouteTrie: any;
|
|
56
|
+
|
|
57
|
+
perRouterTrieMap: Map<string, any>;
|
|
58
|
+
perRouterPrecomputedMap: Map<string, PrecomputedEntry[]>;
|
|
59
|
+
perRouterManifestDataMap: Map<string, Record<string, string>>;
|
|
60
|
+
|
|
61
|
+
prerenderManifestEntries: Record<string, string> | null;
|
|
62
|
+
staticManifestEntries: Record<string, string> | null;
|
|
63
|
+
handlerChunkInfoMap: Map<string, ChunkInfo>;
|
|
64
|
+
staticHandlerChunkInfoMap: Map<string, ChunkInfo>;
|
|
65
|
+
rscEntryFileName: string | null;
|
|
66
|
+
resolvedPrerenderModules: Map<string, string[]> | undefined;
|
|
67
|
+
resolvedStaticModules: Map<string, string[]> | undefined;
|
|
68
|
+
|
|
69
|
+
discoveryDone: Promise<void> | null;
|
|
70
|
+
devServerOrigin: string | null;
|
|
71
|
+
devServer: any;
|
|
72
|
+
selfWrittenGenFiles: Map<string, { at: number; hash: string }>;
|
|
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;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function createDiscoveryState(
|
|
82
|
+
entryPath: string | undefined,
|
|
83
|
+
opts: PluginOptions | undefined,
|
|
84
|
+
): DiscoveryState {
|
|
85
|
+
return {
|
|
86
|
+
resolvedEntryPath: entryPath,
|
|
87
|
+
projectRoot: "",
|
|
88
|
+
isBuildMode: false,
|
|
89
|
+
userResolveAlias: undefined,
|
|
90
|
+
scanFilter: undefined,
|
|
91
|
+
cachedRouterFiles: undefined,
|
|
92
|
+
opts,
|
|
93
|
+
|
|
94
|
+
mergedRouteManifest: null,
|
|
95
|
+
perRouterManifests: [],
|
|
96
|
+
mergedPrecomputedEntries: null,
|
|
97
|
+
mergedRouteTrie: null,
|
|
98
|
+
|
|
99
|
+
perRouterTrieMap: new Map(),
|
|
100
|
+
perRouterPrecomputedMap: new Map(),
|
|
101
|
+
perRouterManifestDataMap: new Map(),
|
|
102
|
+
|
|
103
|
+
prerenderManifestEntries: null,
|
|
104
|
+
staticManifestEntries: null,
|
|
105
|
+
handlerChunkInfoMap: new Map(),
|
|
106
|
+
staticHandlerChunkInfoMap: new Map(),
|
|
107
|
+
rscEntryFileName: null,
|
|
108
|
+
resolvedPrerenderModules: undefined,
|
|
109
|
+
resolvedStaticModules: undefined,
|
|
110
|
+
|
|
111
|
+
discoveryDone: null,
|
|
112
|
+
devServerOrigin: null,
|
|
113
|
+
devServer: null,
|
|
114
|
+
selfWrittenGenFiles: new Map(),
|
|
115
|
+
SELF_WRITE_WINDOW_MS: 5_000,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Virtual Module Code Generation
|
|
3
|
+
*
|
|
4
|
+
* Generates the code for virtual:rsc-router/routes-manifest and
|
|
5
|
+
* per-router virtual modules used by the load() hook.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { dirname, basename, join } from "node:path";
|
|
9
|
+
import { jsonParseExpression } from "../utils/manifest-utils.js";
|
|
10
|
+
import { VIRTUAL_ROUTES_MANIFEST_ID } from "./state.js";
|
|
11
|
+
import type { DiscoveryState } from "./state.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Generate the code for the main virtual:rsc-router/routes-manifest module.
|
|
15
|
+
*/
|
|
16
|
+
export function generateRoutesManifestModule(state: DiscoveryState): string {
|
|
17
|
+
const hasManifest =
|
|
18
|
+
state.mergedRouteManifest &&
|
|
19
|
+
Object.keys(state.mergedRouteManifest).length > 0;
|
|
20
|
+
|
|
21
|
+
if (hasManifest) {
|
|
22
|
+
// Build gen file import statements for each router with a sourceFile.
|
|
23
|
+
// This creates a dependency in Vite's module graph: when the gen file
|
|
24
|
+
// changes (e.g. after HMR route edits), Vite invalidates this virtual
|
|
25
|
+
// module and re-evaluates it on the next request, calling
|
|
26
|
+
// setCachedManifest() with fresh data. No manual sync needed.
|
|
27
|
+
const genFileImports: string[] = [];
|
|
28
|
+
const genFileVars: string[] = [];
|
|
29
|
+
const routersWithoutGenFile: Array<{
|
|
30
|
+
id: string;
|
|
31
|
+
manifest: Record<string, string>;
|
|
32
|
+
}> = [];
|
|
33
|
+
let varIdx = 0;
|
|
34
|
+
|
|
35
|
+
for (const entry of state.perRouterManifests) {
|
|
36
|
+
if (entry.sourceFile) {
|
|
37
|
+
const routerDir = dirname(entry.sourceFile);
|
|
38
|
+
const routerBasename = basename(entry.sourceFile).replace(
|
|
39
|
+
/\.(tsx?|jsx?)$/,
|
|
40
|
+
"",
|
|
41
|
+
);
|
|
42
|
+
const genPath = join(
|
|
43
|
+
routerDir,
|
|
44
|
+
`${routerBasename}.named-routes.gen.js`,
|
|
45
|
+
).replaceAll("\\", "/");
|
|
46
|
+
const varName = `_r${varIdx++}`;
|
|
47
|
+
genFileImports.push(
|
|
48
|
+
`import { NamedRoutes as ${varName} } from ${JSON.stringify(genPath)};`,
|
|
49
|
+
);
|
|
50
|
+
genFileVars.push(varName);
|
|
51
|
+
} else {
|
|
52
|
+
// Routers without sourceFile: inline their manifest data directly
|
|
53
|
+
routersWithoutGenFile.push({
|
|
54
|
+
id: entry.id,
|
|
55
|
+
manifest: entry.routeManifest,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const lines = [
|
|
61
|
+
`import { setCachedManifest, setPrecomputedEntries, setRouteTrie, setRouterManifest, registerRouterManifestLoader, clearAllRouterData } from "@rangojs/router/server";`,
|
|
62
|
+
...genFileImports,
|
|
63
|
+
// Clear stale per-router cached data (manifest, trie, precomputed entries)
|
|
64
|
+
// before re-populating. In Cloudflare dev mode, program reloads re-evaluate
|
|
65
|
+
// this virtual module but the route-map-builder singleton retains old data
|
|
66
|
+
// because it's not in the HMR invalidation chain. Without this clear, the
|
|
67
|
+
// handler finds stale trie data and never rebuilds from updated urlpatterns.
|
|
68
|
+
`clearAllRouterData();`,
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
// Flatten NamedRoutes entries: search schema objects -> plain string paths
|
|
72
|
+
if (genFileVars.length > 0) {
|
|
73
|
+
lines.push(
|
|
74
|
+
`function __flat(r) { const o = {}; for (const [k, v] of Object.entries(r)) o[k] = typeof v === "string" ? v : v.path; return o; }`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Build the merged manifest from gen file imports + inlined data
|
|
79
|
+
if (genFileVars.length === 1 && routersWithoutGenFile.length === 0) {
|
|
80
|
+
lines.push(`setCachedManifest(__flat(${genFileVars[0]}));`);
|
|
81
|
+
} else {
|
|
82
|
+
const parts: string[] = [];
|
|
83
|
+
for (const v of genFileVars) parts.push(`...__flat(${v})`);
|
|
84
|
+
for (const { manifest } of routersWithoutGenFile)
|
|
85
|
+
parts.push(`...${jsonParseExpression(manifest)}`);
|
|
86
|
+
lines.push(`setCachedManifest({ ${parts.join(", ")} });`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Set per-router manifests
|
|
90
|
+
let genVarIdx = 0;
|
|
91
|
+
for (const entry of state.perRouterManifests) {
|
|
92
|
+
if (entry.sourceFile) {
|
|
93
|
+
const varName = genFileVars[genVarIdx++];
|
|
94
|
+
lines.push(
|
|
95
|
+
`setRouterManifest(${JSON.stringify(entry.id)}, __flat(${varName}));`,
|
|
96
|
+
);
|
|
97
|
+
} else {
|
|
98
|
+
lines.push(
|
|
99
|
+
`setRouterManifest(${JSON.stringify(entry.id)}, ${jsonParseExpression(entry.routeManifest)});`,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// In dev mode, skip trie and precomputed entries injection. These are
|
|
105
|
+
// computed once during initial discovery and become stale after route
|
|
106
|
+
// changes. A stale trie would incorrectly match removed routes. The
|
|
107
|
+
// handler falls back to Phase 2 regex matching against the live
|
|
108
|
+
// router.urlpatterns, which is always correct after a program reload.
|
|
109
|
+
// In build mode, the trie is always fresh (built from the final route
|
|
110
|
+
// tree) so it's safe to inject.
|
|
111
|
+
if (state.isBuildMode) {
|
|
112
|
+
if (
|
|
113
|
+
state.mergedPrecomputedEntries &&
|
|
114
|
+
state.mergedPrecomputedEntries.length > 0
|
|
115
|
+
) {
|
|
116
|
+
lines.push(
|
|
117
|
+
`setPrecomputedEntries(${jsonParseExpression(state.mergedPrecomputedEntries)});`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
if (state.mergedRouteTrie) {
|
|
121
|
+
lines.push(
|
|
122
|
+
`setRouteTrie(${jsonParseExpression(state.mergedRouteTrie)});`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Register lazy loaders for per-router manifest modules.
|
|
128
|
+
// Each import() uses a static string literal so Rollup creates separate chunks.
|
|
129
|
+
for (const routerId of state.perRouterManifestDataMap.keys()) {
|
|
130
|
+
lines.push(
|
|
131
|
+
`registerRouterManifestLoader(${JSON.stringify(routerId)}, () => import(${JSON.stringify(VIRTUAL_ROUTES_MANIFEST_ID + "/" + routerId)}));`,
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
if (!state.isBuildMode && state.devServerOrigin) {
|
|
135
|
+
lines.push(
|
|
136
|
+
`globalThis.__PRERENDER_DEV_URL = ${JSON.stringify(state.devServerOrigin)};`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
return lines.join("\n");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// No manifest: either discovery hasn't completed or no runner (Cloudflare dev).
|
|
143
|
+
// Still inject __PRERENDER_DEV_URL so the prerender store can fetch on-demand.
|
|
144
|
+
// Re-resolve origin now since the server is listening by module load time.
|
|
145
|
+
if (!state.isBuildMode) {
|
|
146
|
+
const origin =
|
|
147
|
+
state.devServerOrigin ||
|
|
148
|
+
state.devServer?.resolvedUrls?.local?.[0]?.replace(/\/$/, "") ||
|
|
149
|
+
(state.devServer &&
|
|
150
|
+
`http://localhost:${state.devServer.config.server.port || 5173}`);
|
|
151
|
+
if (origin) {
|
|
152
|
+
state.devServerOrigin = origin;
|
|
153
|
+
return `globalThis.__PRERENDER_DEV_URL = ${JSON.stringify(origin)};`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return `// Route manifest will be populated at runtime`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Generate the code for a per-router virtual module.
|
|
161
|
+
*/
|
|
162
|
+
export function generatePerRouterModule(
|
|
163
|
+
state: DiscoveryState,
|
|
164
|
+
routerId: string,
|
|
165
|
+
): string {
|
|
166
|
+
// Find the per-router entry to get the gen file path
|
|
167
|
+
const routerEntry = state.perRouterManifests.find((e) => e.id === routerId);
|
|
168
|
+
const trie = state.perRouterTrieMap.get(routerId);
|
|
169
|
+
const entries = state.perRouterPrecomputedMap.get(routerId);
|
|
170
|
+
const lines: string[] = [];
|
|
171
|
+
|
|
172
|
+
if (routerEntry?.sourceFile) {
|
|
173
|
+
// Import manifest from the gen file so HMR auto-propagates
|
|
174
|
+
const routerDir = dirname(routerEntry.sourceFile);
|
|
175
|
+
const routerBasename = basename(routerEntry.sourceFile).replace(
|
|
176
|
+
/\.(tsx?|jsx?)$/,
|
|
177
|
+
"",
|
|
178
|
+
);
|
|
179
|
+
const genPath = join(
|
|
180
|
+
routerDir,
|
|
181
|
+
`${routerBasename}.named-routes.gen.js`,
|
|
182
|
+
).replaceAll("\\", "/");
|
|
183
|
+
lines.push(`import { NamedRoutes as _r } from ${JSON.stringify(genPath)};`);
|
|
184
|
+
lines.push(
|
|
185
|
+
`function __flat(r) { const o = {}; for (const [k, v] of Object.entries(r)) o[k] = typeof v === "string" ? v : v.path; return o; }`,
|
|
186
|
+
);
|
|
187
|
+
lines.push(`export const manifest = __flat(_r);`);
|
|
188
|
+
} else {
|
|
189
|
+
const manifest = state.perRouterManifestDataMap.get(routerId);
|
|
190
|
+
if (manifest) {
|
|
191
|
+
lines.push(`export const manifest = ${jsonParseExpression(manifest)};`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (trie) {
|
|
195
|
+
lines.push(`export const trie = ${jsonParseExpression(trie)};`);
|
|
196
|
+
}
|
|
197
|
+
if (entries && entries.length > 0) {
|
|
198
|
+
lines.push(
|
|
199
|
+
`export const precomputedEntries = ${jsonParseExpression(entries)};`,
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
return lines.join("\n") || "// empty router manifest";
|
|
203
|
+
}
|