@rangojs/router 0.0.0-experimental.8678bb02 → 0.0.0-experimental.87
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/README.md +126 -38
- package/dist/bin/rango.js +130 -47
- package/dist/vite/index.js +847 -384
- package/dist/vite/index.js.bak +5448 -0
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +5 -5
- package/skills/breadcrumbs/SKILL.md +3 -1
- 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 +35 -2
- 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 +59 -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 +24 -0
- package/skills/router-setup/SKILL.md +35 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/typesafety/SKILL.md +3 -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/navigation-bridge.ts +87 -6
- package/src/browser/navigation-client.ts +128 -77
- package/src/browser/navigation-store.ts +68 -9
- package/src/browser/partial-update.ts +60 -7
- package/src/browser/prefetch/cache.ts +129 -21
- package/src/browser/prefetch/fetch.ts +156 -18
- package/src/browser/prefetch/queue.ts +36 -5
- package/src/browser/rango-state.ts +53 -13
- package/src/browser/react/Link.tsx +72 -8
- package/src/browser/react/NavigationProvider.tsx +57 -11
- 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 +60 -9
- package/src/browser/scroll-restoration.ts +10 -8
- package/src/browser/segment-reconciler.ts +36 -14
- package/src/browser/server-action-bridge.ts +8 -18
- package/src/browser/types.ts +33 -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 +211 -72
- package/src/build/route-types/scan-filter.ts +8 -1
- package/src/cache/cf/cf-cache-store.ts +5 -7
- package/src/client.tsx +84 -230
- package/src/deps/browser.ts +0 -1
- 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 +210 -35
- package/src/route-definition/helpers-types.ts +61 -14
- package/src/route-definition/index.ts +3 -0
- package/src/route-definition/redirect.ts +9 -1
- package/src/route-definition/resolve-handler-use.ts +155 -0
- package/src/route-types.ts +18 -0
- package/src/router/content-negotiation.ts +100 -1
- package/src/router/handler-context.ts +70 -17
- package/src/router/intercept-resolution.ts +9 -4
- package/src/router/lazy-includes.ts +6 -6
- package/src/router/loader-resolution.ts +153 -21
- package/src/router/manifest.ts +22 -13
- package/src/router/match-api.ts +127 -192
- package/src/router/match-middleware/cache-lookup.ts +28 -8
- package/src/router/match-middleware/segment-resolution.ts +53 -0
- package/src/router/match-result.ts +82 -4
- package/src/router/middleware-types.ts +2 -28
- package/src/router/middleware.ts +32 -7
- 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-interfaces.ts +36 -4
- package/src/router/router-options.ts +37 -11
- package/src/router/segment-resolution/fresh.ts +70 -5
- package/src/router/segment-resolution/revalidation.ts +87 -9
- package/src/router/trie-matching.ts +10 -4
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +54 -7
- package/src/rsc/handler.ts +478 -399
- package/src/rsc/helpers.ts +69 -41
- package/src/rsc/loader-fetch.ts +18 -3
- package/src/rsc/manifest-init.ts +5 -1
- package/src/rsc/progressive-enhancement.ts +14 -3
- package/src/rsc/response-route-handler.ts +14 -1
- package/src/rsc/rsc-rendering.ts +15 -2
- package/src/rsc/server-action.ts +10 -2
- package/src/rsc/ssr-setup.ts +2 -2
- package/src/rsc/types.ts +6 -4
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +11 -61
- package/src/server/context.ts +65 -5
- package/src/server/handle-store.ts +19 -0
- package/src/server/loader-registry.ts +9 -8
- package/src/server/request-context.ts +142 -55
- package/src/ssr/index.tsx +3 -0
- package/src/static-handler.ts +18 -6
- package/src/types/cache-types.ts +4 -4
- package/src/types/handler-context.ts +17 -43
- package/src/types/loader-types.ts +37 -11
- package/src/types/request-scope.ts +126 -0
- package/src/types/route-entry.ts +12 -1
- package/src/types/segments.ts +1 -1
- package/src/urls/include-helper.ts +24 -14
- package/src/urls/path-helper-types.ts +39 -6
- package/src/urls/path-helper.ts +47 -12
- 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/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 -4
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +60 -5
- 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-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 +64 -206
- package/src/vite/plugins/refresh-cmd.ts +88 -26
- package/src/vite/rango.ts +40 -18
- package/src/vite/router-discovery.ts +237 -37
- package/src/vite/utils/banner.ts +1 -1
- package/src/vite/utils/package-resolution.ts +1 -1
- package/src/vite/utils/prerender-utils.ts +37 -5
- package/src/vite/utils/shared-utils.ts +3 -2
- package/src/browser/debug-channel.ts +0 -93
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Vite plugin that triggers a full browser reload
|
|
5
|
-
*
|
|
4
|
+
* Vite plugin that triggers a full browser reload from terminal input.
|
|
5
|
+
*
|
|
6
|
+
* This plugin is intentionally passive:
|
|
7
|
+
* - it never enables raw mode on stdin
|
|
8
|
+
* - it never restores terminal state
|
|
9
|
+
* - it reacts to Ctrl+R when that raw byte reaches the process
|
|
10
|
+
* - it also supports safe line-based fallbacks like "e" + Enter
|
|
6
11
|
*
|
|
7
12
|
* Usage:
|
|
8
13
|
* ```ts
|
|
@@ -20,35 +25,95 @@ export function poke(): Plugin {
|
|
|
20
25
|
|
|
21
26
|
configureServer(server) {
|
|
22
27
|
const stdin = process.stdin;
|
|
28
|
+
const debug = process.env.RANGO_POKE_DEBUG === "1";
|
|
29
|
+
|
|
30
|
+
const triggerReload = (source: string) => {
|
|
31
|
+
server.hot.send({ type: "full-reload", path: "*" });
|
|
32
|
+
server.config.logger.info(` browser reload (${source})`, {
|
|
33
|
+
timestamp: true,
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const toBuffer = (chunk: string | Buffer): Buffer => {
|
|
38
|
+
return typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const formatChunk = (chunk: string | Buffer): string => {
|
|
42
|
+
const data = toBuffer(chunk);
|
|
43
|
+
const hex = Array.from(data)
|
|
44
|
+
.map((byte) => `0x${byte.toString(16).padStart(2, "0")}`)
|
|
45
|
+
.join(" ");
|
|
46
|
+
const ascii = Array.from(data)
|
|
47
|
+
.map((byte) => {
|
|
48
|
+
if (byte >= 0x20 && byte <= 0x7e) return String.fromCharCode(byte);
|
|
49
|
+
if (byte === 0x0a) return "\\n";
|
|
50
|
+
if (byte === 0x0d) return "\\r";
|
|
51
|
+
if (byte === 0x09) return "\\t";
|
|
52
|
+
return ".";
|
|
53
|
+
})
|
|
54
|
+
.join("");
|
|
55
|
+
return `len=${data.length} hex=[${hex}] ascii="${ascii}"`;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const readCtrlR = (chunk: string | Buffer): boolean => {
|
|
59
|
+
const data =
|
|
60
|
+
typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
61
|
+
return data.length === 1 && data[0] === 0x12;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const readSubmittedCommands = (chunk: string | Buffer): string[] => {
|
|
65
|
+
const text = toBuffer(chunk)
|
|
66
|
+
.toString("utf8")
|
|
67
|
+
.replace(/\r\n/g, "\n")
|
|
68
|
+
.replace(/\r/g, "\n");
|
|
69
|
+
|
|
70
|
+
if (!text.includes("\n")) return [];
|
|
71
|
+
|
|
72
|
+
const lines = text.split("\n");
|
|
73
|
+
lines.pop();
|
|
74
|
+
return lines;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
if (debug) {
|
|
78
|
+
server.config.logger.info(
|
|
79
|
+
` poke debug enabled (isTTY=${stdin.isTTY ? "yes" : "no"}, isRaw=${stdin.isTTY ? (stdin.isRaw ? "yes" : "no") : "n/a"})`,
|
|
80
|
+
{ timestamp: true },
|
|
81
|
+
);
|
|
82
|
+
}
|
|
23
83
|
|
|
24
|
-
// Raw mode delivers individual keystrokes as immediate single-byte
|
|
25
|
-
// events instead of waiting for Enter (cooked/line-buffered mode).
|
|
26
|
-
// Without it, Ctrl+R (0x12) is never delivered as a discrete byte.
|
|
27
|
-
// When stdin is a pipe (CI, spawned process) setRawMode is unavailable
|
|
28
|
-
// but data already arrives unbuffered, so the isTTY guard suffices.
|
|
29
|
-
const previousRawMode = stdin.isTTY ? stdin.isRaw : null;
|
|
30
84
|
if (stdin.isTTY) {
|
|
31
|
-
|
|
85
|
+
server.config.logger.info(
|
|
86
|
+
" poke ready: press e + enter to reload browser (ctrl+r also works when available)",
|
|
87
|
+
{ timestamp: true },
|
|
88
|
+
);
|
|
32
89
|
}
|
|
33
90
|
|
|
34
|
-
const onData = (data: Buffer) => {
|
|
35
|
-
if (
|
|
91
|
+
const onData = (data: string | Buffer) => {
|
|
92
|
+
if (debug) {
|
|
93
|
+
server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
|
|
94
|
+
timestamp: true,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
36
97
|
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
if (data
|
|
42
|
-
|
|
98
|
+
// Only react to the exact Ctrl+R byte when some host terminal or
|
|
99
|
+
// wrapper already delivers it to this process. We intentionally do
|
|
100
|
+
// not enable raw mode here because that can steal Vite shortcuts
|
|
101
|
+
// like "r" / "q" and interfere with terminal-level controls.
|
|
102
|
+
if (readCtrlR(data)) {
|
|
103
|
+
triggerReload("ctrl+r");
|
|
43
104
|
return;
|
|
44
105
|
}
|
|
45
106
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
107
|
+
for (const command of readSubmittedCommands(data)) {
|
|
108
|
+
if (command === "e") {
|
|
109
|
+
triggerReload("e+enter");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (command === "\u001br") {
|
|
114
|
+
triggerReload("option+r+enter");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
52
117
|
}
|
|
53
118
|
};
|
|
54
119
|
|
|
@@ -56,9 +121,6 @@ export function poke(): Plugin {
|
|
|
56
121
|
|
|
57
122
|
server.httpServer?.on("close", () => {
|
|
58
123
|
stdin.off("data", onData);
|
|
59
|
-
if (stdin.isTTY && previousRawMode !== null) {
|
|
60
|
-
stdin.setRawMode(previousRawMode);
|
|
61
|
-
}
|
|
62
124
|
});
|
|
63
125
|
},
|
|
64
126
|
};
|
package/src/vite/rango.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { VIRTUAL_IDS } from "./plugins/virtual-entries.js";
|
|
|
12
12
|
import {
|
|
13
13
|
getExcludeDeps,
|
|
14
14
|
getPackageAliases,
|
|
15
|
+
getPublishedPackageName,
|
|
15
16
|
} from "./utils/package-resolution.js";
|
|
16
17
|
import { findRouterFiles } from "../build/generate-route-types.js";
|
|
17
18
|
import { createVersionPlugin } from "./plugins/version-plugin.js";
|
|
@@ -55,14 +56,29 @@ import { performanceTracksPlugin } from "./plugins/performance-tracks.js";
|
|
|
55
56
|
export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
56
57
|
const resolvedOptions: RangoOptions = options ?? { preset: "node" };
|
|
57
58
|
const preset = resolvedOptions.preset ?? "node";
|
|
58
|
-
console.log("[perf-tracks] rango() called, preset:", preset);
|
|
59
59
|
const showBanner = resolvedOptions.banner ?? true;
|
|
60
60
|
|
|
61
61
|
const plugins: PluginOption[] = [];
|
|
62
62
|
|
|
63
63
|
// Get package resolution info (workspace vs npm install)
|
|
64
64
|
const rangoAliases = getPackageAliases();
|
|
65
|
-
const excludeDeps =
|
|
65
|
+
const excludeDeps = [
|
|
66
|
+
...getExcludeDeps(),
|
|
67
|
+
// The public browser entry re-exports the RSDW browser client.
|
|
68
|
+
// Excluding both keeps Vite from freezing the unpatched bundle into
|
|
69
|
+
// .vite/deps before our source transforms run.
|
|
70
|
+
"@vitejs/plugin-rsc/browser",
|
|
71
|
+
// Keep the browser RSDW client out of Vite's dep optimizer so our
|
|
72
|
+
// cjs-to-esm transform can patch the real file.
|
|
73
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.browser",
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
// Vite supports a nested `A > B` syntax in optimizeDeps.include that resolves
|
|
77
|
+
// B from A's location. We anchor transitive deps (rsc-html-stream,
|
|
78
|
+
// @vitejs/plugin-rsc/vendor/*) to @rangojs/router so pnpm consumers — where
|
|
79
|
+
// these aren't visible at the app root — can still pre-bundle them.
|
|
80
|
+
const pkg = getPublishedPackageName();
|
|
81
|
+
const nested = (spec: string) => `${pkg} > ${spec}`;
|
|
66
82
|
|
|
67
83
|
// Mutable ref for router path (node preset only).
|
|
68
84
|
// Set immediately when user-specified, or populated by the auto-discover
|
|
@@ -118,7 +134,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
118
134
|
// Pre-bundle rsc-html-stream to prevent discovery during first request
|
|
119
135
|
// Exclude rsc-router modules to ensure same Context instance
|
|
120
136
|
optimizeDeps: {
|
|
121
|
-
include: ["rsc-html-stream/client"],
|
|
137
|
+
include: [nested("rsc-html-stream/client")],
|
|
122
138
|
exclude: excludeDeps,
|
|
123
139
|
esbuildOptions: sharedEsbuildOptions,
|
|
124
140
|
},
|
|
@@ -143,8 +159,10 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
143
159
|
"react-dom/static.edge",
|
|
144
160
|
"react/jsx-runtime",
|
|
145
161
|
"react/jsx-dev-runtime",
|
|
146
|
-
"rsc-html-stream/server",
|
|
147
|
-
|
|
162
|
+
nested("rsc-html-stream/server"),
|
|
163
|
+
nested(
|
|
164
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
|
|
165
|
+
),
|
|
148
166
|
],
|
|
149
167
|
exclude: excludeDeps,
|
|
150
168
|
esbuildOptions: sharedEsbuildOptions,
|
|
@@ -159,7 +177,9 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
159
177
|
"react",
|
|
160
178
|
"react/jsx-runtime",
|
|
161
179
|
"react/jsx-dev-runtime",
|
|
162
|
-
|
|
180
|
+
nested(
|
|
181
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
|
|
182
|
+
),
|
|
163
183
|
],
|
|
164
184
|
exclude: excludeDeps,
|
|
165
185
|
esbuildOptions: sharedEsbuildOptions,
|
|
@@ -184,6 +204,9 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
184
204
|
|
|
185
205
|
plugins.push(createVirtualEntriesPlugin(finalEntries));
|
|
186
206
|
|
|
207
|
+
// Dev-only: RSDW client patch for React Performance Tracks
|
|
208
|
+
plugins.push(performanceTracksPlugin());
|
|
209
|
+
|
|
187
210
|
// Add RSC plugin with cloudflare-specific options
|
|
188
211
|
// Note: loadModuleDevProxy should NOT be used with childEnvironments
|
|
189
212
|
// since SSR runs in workerd alongside RSC
|
|
@@ -269,7 +292,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
269
292
|
"react-dom",
|
|
270
293
|
"react/jsx-runtime",
|
|
271
294
|
"react/jsx-dev-runtime",
|
|
272
|
-
"rsc-html-stream/client",
|
|
295
|
+
nested("rsc-html-stream/client"),
|
|
273
296
|
],
|
|
274
297
|
exclude: excludeDeps,
|
|
275
298
|
esbuildOptions: sharedEsbuildOptions,
|
|
@@ -286,7 +309,9 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
286
309
|
"react-dom/static.edge",
|
|
287
310
|
"react/jsx-runtime",
|
|
288
311
|
"react/jsx-dev-runtime",
|
|
289
|
-
|
|
312
|
+
nested(
|
|
313
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
|
|
314
|
+
),
|
|
290
315
|
],
|
|
291
316
|
exclude: excludeDeps,
|
|
292
317
|
esbuildOptions: sharedEsbuildOptions,
|
|
@@ -299,7 +324,9 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
299
324
|
"react",
|
|
300
325
|
"react/jsx-runtime",
|
|
301
326
|
"react/jsx-dev-runtime",
|
|
302
|
-
|
|
327
|
+
nested(
|
|
328
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
|
|
329
|
+
),
|
|
303
330
|
],
|
|
304
331
|
esbuildOptions: sharedEsbuildOptions,
|
|
305
332
|
},
|
|
@@ -336,14 +363,8 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
336
363
|
// Add virtual entries plugin (RSC entry generated lazily from routerRef)
|
|
337
364
|
plugins.push(createVirtualEntriesPlugin(finalEntries, routerRef));
|
|
338
365
|
|
|
339
|
-
// Dev-only:
|
|
340
|
-
|
|
341
|
-
const perfPlugin = performanceTracksPlugin();
|
|
342
|
-
console.log(
|
|
343
|
-
"[perf-tracks] rango: plugin created, has configureServer:",
|
|
344
|
-
!!perfPlugin.configureServer,
|
|
345
|
-
);
|
|
346
|
-
plugins.push(perfPlugin);
|
|
366
|
+
// Dev-only: RSDW client patch for React Performance Tracks
|
|
367
|
+
plugins.push(performanceTracksPlugin());
|
|
347
368
|
|
|
348
369
|
plugins.push(
|
|
349
370
|
rsc({
|
|
@@ -448,7 +469,8 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
448
469
|
createRouterDiscoveryPlugin(discoveryEntryPath, {
|
|
449
470
|
routerPathRef: discoveryRouterRef,
|
|
450
471
|
enableBuildPrerender: prerenderEnabled,
|
|
451
|
-
|
|
472
|
+
buildEnv: options?.buildEnv,
|
|
473
|
+
preset,
|
|
452
474
|
}),
|
|
453
475
|
);
|
|
454
476
|
|