@rangojs/router 0.30.0 → 0.31.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/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/dist/bin/rango.js +7861 -197
- package/dist/types/build/generate-route-types.d.ts +1 -1
- package/dist/types/build/route-types/include-resolution.d.ts +1 -1
- package/dist/types/build/route-types/router-processing.d.ts +3 -7
- package/dist/types/suspense-audit.d.ts +19 -1
- package/dist/types/vite/discovery/build-versions.d.ts +17 -13
- package/dist/types/vite/plugins/stable-rsc-output.d.ts +1 -1
- package/dist/types/vite/temp-rsc-server.d.ts +8 -4
- package/dist/types/vite/utils/forward-user-plugins.d.ts +3 -1
- package/dist/vite/index.js +153 -50
- package/package.json +2 -2
- package/skills/rango/SKILL.md +5 -5
- package/skills/testing/response-routes.md +3 -2
- package/skills/typesafety/generated-files-and-cli.md +2 -1
- package/src/bin/rango.ts +13 -8
- package/src/build/generate-route-types.ts +0 -1
- package/src/build/route-types/include-resolution.ts +2 -1
- package/src/build/route-types/router-processing.ts +213 -49
- package/src/build/runtime-discovery.ts +90 -41
- package/src/client-urls/server-projection.ts +3 -1
- package/src/suspense-audit.ts +58 -11
- package/src/testing/render-route.tsx +5 -1
- package/src/vite/discovery/build-versions.ts +67 -26
- package/src/vite/plugins/stable-rsc-output.ts +1 -1
- package/src/vite/temp-rsc-server.ts +9 -4
- package/src/vite/utils/forward-user-plugins.ts +4 -2
|
@@ -593,11 +593,23 @@ export function isSourceMap(fileName: string): boolean {
|
|
|
593
593
|
}
|
|
594
594
|
|
|
595
595
|
/**
|
|
596
|
-
* The bundler's
|
|
597
|
-
*
|
|
596
|
+
* The bundler's module marker: the comment line before each module's code in
|
|
597
|
+
* an unminified chunk, naming the module (`\0` printed as two characters).
|
|
598
|
+
* rolldown before 1.2.15 wraps the code in `//#region <id>` and
|
|
599
|
+
* `//#endregion`; 1.2.15 (rolldown/rolldown#11235) prints only `// <id>`
|
|
600
|
+
* where the module starts.
|
|
598
601
|
*/
|
|
599
|
-
const
|
|
600
|
-
|
|
602
|
+
const MODULE_MARKER = /^\/\/(#region)? (.+)$/gm;
|
|
603
|
+
/**
|
|
604
|
+
* plugin-rsc's server-reference map: its marker in either form (group 1), and
|
|
605
|
+
* its body up to the next `// ` line or the region's end. The body stops at
|
|
606
|
+
* any `// ` line, a comment of its own included, so it never takes in the
|
|
607
|
+
* code of the module after it.
|
|
608
|
+
*/
|
|
609
|
+
const SERVER_REFERENCE_MAP = new RegExp(
|
|
610
|
+
`(^//(?:#region)? ${escapeRegExp(`\\0${SERVER_REFERENCES_MODULE_ID.slice(1)}`)}\n)[\\s\\S]*?(?=^//(?: |#endregion))`,
|
|
611
|
+
"m",
|
|
612
|
+
);
|
|
601
613
|
|
|
602
614
|
/**
|
|
603
615
|
* Drop the body of the server-reference map from a chunk's source.
|
|
@@ -609,33 +621,61 @@ const REGION_END = "//#endregion";
|
|
|
609
621
|
* hashed by the routers that reach it (resolveRouterMembers), so nothing the
|
|
610
622
|
* map says is lost by skipping it.
|
|
611
623
|
*
|
|
612
|
-
* Works on the
|
|
613
|
-
* keeps the map in every router's hash: more
|
|
624
|
+
* Works on the module markers, so a minified server build (which has none),
|
|
625
|
+
* or a map no marker follows, keeps the map in every router's hash: more
|
|
626
|
+
* clearing, never less.
|
|
614
627
|
*/
|
|
615
628
|
export function stripServerReferenceMap(source: string): string {
|
|
616
|
-
|
|
617
|
-
if (start === -1) return source;
|
|
618
|
-
const bodyStart = start + SERVER_REFERENCES_REGION_START.length;
|
|
619
|
-
const end = source.indexOf(REGION_END, bodyStart);
|
|
620
|
-
if (end === -1) return source;
|
|
621
|
-
return source.slice(0, bodyStart) + source.slice(end);
|
|
629
|
+
return source.replace(SERVER_REFERENCE_MAP, "$1");
|
|
622
630
|
}
|
|
623
631
|
|
|
624
|
-
|
|
632
|
+
/**
|
|
633
|
+
* Every way the bundler can print one of `moduleIds` in a marker. rolldown
|
|
634
|
+
* prints a path relative to its working directory (`stabilize_id`), so any
|
|
635
|
+
* trailing run of the path's segments, and any other id as it is.
|
|
636
|
+
*/
|
|
637
|
+
function printedModuleIds(moduleIds: readonly string[]): Set<string> {
|
|
638
|
+
const printed = new Set<string>();
|
|
639
|
+
for (const id of moduleIds) {
|
|
640
|
+
if (!isAbsolutePath(id)) {
|
|
641
|
+
printed.add(id.replaceAll("\0", "\\0"));
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
const segments = id.replaceAll("\\", "/").split("/");
|
|
645
|
+
for (let index = 0; index < segments.length; index++) {
|
|
646
|
+
printed.add(segments.slice(index).join("/"));
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return printed;
|
|
650
|
+
}
|
|
625
651
|
|
|
626
652
|
/**
|
|
627
|
-
* Take the module paths out of a chunk's
|
|
653
|
+
* Take the module paths out of a chunk's module markers.
|
|
654
|
+
*
|
|
655
|
+
* The path says where the build ran, not what it built: it is relative to the
|
|
656
|
+
* directory `vite build` was started from (`vite build apps/web` from a
|
|
657
|
+
* repository root prints other paths than `vite build` in the app), it holds
|
|
658
|
+
* the pnpm store directory with its peer suffix, and a virtual id is printed
|
|
659
|
+
* verbatim, absolute paths in its query included. The code after the marker
|
|
660
|
+
* is hashed either way.
|
|
628
661
|
*
|
|
629
|
-
*
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
* prints other paths than `vite build` in the app), it holds the pnpm store
|
|
633
|
-
* directory with its peer suffix, and a virtual id is printed verbatim,
|
|
634
|
-
* absolute paths in its query included. The code under the comment is hashed
|
|
635
|
-
* either way.
|
|
662
|
+
* A `//#region` line is always a marker. A `// ` line is one only when it
|
|
663
|
+
* names a module of the chunk (`moduleIds`): a kept comment or a line of a
|
|
664
|
+
* multi-line string can start the same way, and is hashed.
|
|
636
665
|
*/
|
|
637
|
-
export function
|
|
638
|
-
|
|
666
|
+
export function stripModulePaths(
|
|
667
|
+
source: string,
|
|
668
|
+
moduleIds: readonly string[],
|
|
669
|
+
): string {
|
|
670
|
+
let printed: Set<string> | undefined;
|
|
671
|
+
return source.replace(
|
|
672
|
+
MODULE_MARKER,
|
|
673
|
+
(line, region: string | undefined, name: string) => {
|
|
674
|
+
if (region) return "//#region";
|
|
675
|
+
printed ??= printedModuleIds(moduleIds);
|
|
676
|
+
return printed.has(name.replace(/^(?:\.\.\/)+/, "")) ? "//" : line;
|
|
677
|
+
},
|
|
678
|
+
);
|
|
639
679
|
}
|
|
640
680
|
|
|
641
681
|
/** One thing a version is a hash of: its name and the digest of its bytes. */
|
|
@@ -676,8 +716,8 @@ const FOREIGN_FILE = "~";
|
|
|
676
716
|
*
|
|
677
717
|
* Three things are taken out of a chunk's text first, each because it says
|
|
678
718
|
* where or how the build ran: the server-reference map's body
|
|
679
|
-
* ({@link stripServerReferenceMap}), the paths in
|
|
680
|
-
* ({@link
|
|
719
|
+
* ({@link stripServerReferenceMap}), the paths in module markers
|
|
720
|
+
* ({@link stripModulePaths}), and the hashed names of bundle files. A name
|
|
681
721
|
* carries the content hash of its file, and every chunk importing the file
|
|
682
722
|
* has the name in its bytes, so one router's change would otherwise move the
|
|
683
723
|
* digest of every chunk naming its chunk. Only names with a content hash are
|
|
@@ -756,8 +796,9 @@ export function digestBundle(
|
|
|
756
796
|
};
|
|
757
797
|
}
|
|
758
798
|
const references: string[] = [];
|
|
759
|
-
const text =
|
|
799
|
+
const text = stripModulePaths(
|
|
760
800
|
stripServerReferenceMap(decoder.decode(bytes)),
|
|
801
|
+
chunk.moduleIds,
|
|
761
802
|
);
|
|
762
803
|
const blanked = reference
|
|
763
804
|
? text.replace(reference, (name) => {
|
|
@@ -121,7 +121,7 @@ export function canonicalAssetsManifestBinding(
|
|
|
121
121
|
* (`ServerReferencesManager.claimMap`), which varies with the concurrent
|
|
122
122
|
* scan builds (e2e/test-app: 2 of 2 consecutive builds differed). Sorted
|
|
123
123
|
* here so a minified server build, where stripServerReferenceMap finds no
|
|
124
|
-
*
|
|
124
|
+
* module markers, still hashes the same bytes.
|
|
125
125
|
* 2. Local name of the assets-manifest import. plugin-rsc imports the manifest
|
|
126
126
|
* under three names; the bundler merges them into one import per chunk and
|
|
127
127
|
* keeps a different one from build to build (the cache-versions fixture:
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The discovery temp RSC server: a minimal Vite server whose module runner
|
|
3
3
|
* imports the user's router files. Shared by dev discovery
|
|
4
|
-
* (discovery/dev-server-phase.ts)
|
|
5
|
-
* (discovery/build-discovery-phase.ts)
|
|
4
|
+
* (discovery/dev-server-phase.ts), build discovery
|
|
5
|
+
* (discovery/build-discovery-phase.ts) and `rango generate --runtime`
|
|
6
|
+
* (build/runtime-discovery.ts).
|
|
6
7
|
*
|
|
7
8
|
* Sits in src/vite/, not src/vite/discovery/: the loader hook URL below
|
|
8
|
-
* resolves against this module's import.meta.url, and the published
|
|
9
|
-
* (dist/vite/index.js)
|
|
9
|
+
* resolves against this module's import.meta.url, and the published bundles
|
|
10
|
+
* (dist/vite/index.js, dist/bin/rango.js) ship the hook at the same relative
|
|
11
|
+
* path.
|
|
10
12
|
*/
|
|
11
13
|
|
|
12
14
|
import type { ViteDevServer } from "vite";
|
|
@@ -103,6 +105,8 @@ export async function createTempRscServer(
|
|
|
103
105
|
* shell capture actually runs.
|
|
104
106
|
*/
|
|
105
107
|
realSsrEntry?: boolean;
|
|
108
|
+
/** Caller-specific plugins, appended after the forwarded user plugins. */
|
|
109
|
+
plugins?: import("vite").Plugin[];
|
|
106
110
|
} = {},
|
|
107
111
|
): Promise<ViteDevServer> {
|
|
108
112
|
// Install the Node ESM loader hook before any module evaluation so
|
|
@@ -218,6 +222,7 @@ export async function createTempRscServer(
|
|
|
218
222
|
// IMPORT_REWRITE_PLUGINS) and placed last so framework resolution runs first;
|
|
219
223
|
// Vite re-sorts by `enforce`, so `enforce: "pre"` resolvers still lead.
|
|
220
224
|
...state.userResolvePlugins,
|
|
225
|
+
...(options.plugins ?? []),
|
|
221
226
|
],
|
|
222
227
|
});
|
|
223
228
|
}
|
|
@@ -139,6 +139,8 @@ export interface ForwardedRunnerConfig {
|
|
|
139
139
|
/**
|
|
140
140
|
* Extract the data-only config slice to mirror into the discovery temp server.
|
|
141
141
|
* `alias` is included here so callers no longer need to thread it separately.
|
|
142
|
+
* Accepts the unresolved config too: `rango generate --runtime` must not
|
|
143
|
+
* resolve it (that runs rango()'s configResolved, which writes gen files).
|
|
142
144
|
*
|
|
143
145
|
* `tsconfigPaths` is forwarded so Vite 8's native tsconfig `paths` resolution
|
|
144
146
|
* (a top-level `resolve` flag, off by default) reaches the temp server. The
|
|
@@ -154,9 +156,9 @@ export interface ForwardedRunnerConfig {
|
|
|
154
156
|
* forward `oxc` exclusively — no `esbuild` field is touched.
|
|
155
157
|
*/
|
|
156
158
|
export function pickForwardedRunnerConfig(
|
|
157
|
-
config: ResolvedConfig,
|
|
159
|
+
config: Pick<ResolvedConfig | UserConfig, "resolve" | "define" | "oxc">,
|
|
158
160
|
): ForwardedRunnerConfig {
|
|
159
|
-
const r = config.resolve ??
|
|
161
|
+
const r = config.resolve ?? {};
|
|
160
162
|
const resolve: NonNullable<UserConfig["resolve"]> = {};
|
|
161
163
|
if (r.alias !== undefined) resolve.alias = r.alias as any;
|
|
162
164
|
if (r.dedupe !== undefined) resolve.dedupe = r.dedupe;
|