@rangojs/router 0.0.0-experimental.8874d8d2 → 0.0.0-experimental.89
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 +1705 -701
- 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 +175 -15
- package/src/browser/prefetch/fetch.ts +180 -33
- 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 +437 -297
- 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 +17 -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 +184 -0
- package/src/vite/discovery/bundle-postprocess.ts +30 -33
- package/src/vite/discovery/discover-routers.ts +36 -4
- package/src/vite/discovery/prerender-collection.ts +175 -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/cjs-to-esm.ts +5 -0
- package/src/vite/plugins/client-ref-dedup.ts +16 -0
- package/src/vite/plugins/client-ref-hashing.ts +16 -4
- 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 +53 -31
- 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-ids/router-transform.ts +20 -3
- package/src/vite/plugins/expose-internal-ids.ts +563 -316
- package/src/vite/plugins/performance-tracks.ts +96 -0
- package/src/vite/plugins/refresh-cmd.ts +88 -26
- package/src/vite/plugins/use-cache-transform.ts +56 -43
- package/src/vite/plugins/version-plugin.ts +13 -1
- package/src/vite/rango.ts +204 -217
- package/src/vite/router-discovery.ts +393 -67
- 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
|
@@ -3,6 +3,9 @@ import MagicString from "magic-string";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import { normalizePath } from "./expose-id-utils.js";
|
|
6
|
+
import { createRangoDebugger, createCounter, NS } from "../debug.js";
|
|
7
|
+
|
|
8
|
+
const debug = createRangoDebugger(NS.transform);
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* Type for the RSC plugin's manager API
|
|
@@ -254,6 +257,8 @@ export function exposeActionId(): Plugin {
|
|
|
254
257
|
let isBuild = false;
|
|
255
258
|
let hashToFileMap: Map<string, string> | undefined;
|
|
256
259
|
let rscPluginApi: RscPluginApi | undefined;
|
|
260
|
+
const counterTransform = createCounter(debug, "expose-action-id transform");
|
|
261
|
+
const counterRender = createCounter(debug, "expose-action-id renderChunk");
|
|
257
262
|
|
|
258
263
|
return {
|
|
259
264
|
name: "@rangojs/router:expose-action-id",
|
|
@@ -268,6 +273,11 @@ export function exposeActionId(): Plugin {
|
|
|
268
273
|
rscPluginApi = getRscPluginApi(config);
|
|
269
274
|
},
|
|
270
275
|
|
|
276
|
+
buildEnd() {
|
|
277
|
+
counterTransform?.flush();
|
|
278
|
+
counterRender?.flush();
|
|
279
|
+
},
|
|
280
|
+
|
|
271
281
|
buildStart() {
|
|
272
282
|
// Verify RSC plugin is present at build start (after all config hooks have run)
|
|
273
283
|
// This allows rsc-router:rsc-integration to dynamically add the RSC plugin
|
|
@@ -278,9 +288,7 @@ export function exposeActionId(): Plugin {
|
|
|
278
288
|
if (!rscPluginApi) {
|
|
279
289
|
throw new Error(
|
|
280
290
|
"[rsc-router] Could not find @vitejs/plugin-rsc. " +
|
|
281
|
-
"@rangojs/router requires the Vite RSC plugin
|
|
282
|
-
"The RSC plugin should be included automatically. If you disabled it with\n" +
|
|
283
|
-
"rango({ rsc: false }), add rsc() before rango() in your config.",
|
|
291
|
+
"@rangojs/router requires the Vite RSC plugin, which is included automatically by rango().",
|
|
284
292
|
);
|
|
285
293
|
}
|
|
286
294
|
|
|
@@ -326,40 +334,54 @@ export function exposeActionId(): Plugin {
|
|
|
326
334
|
return;
|
|
327
335
|
}
|
|
328
336
|
|
|
329
|
-
|
|
330
|
-
|
|
337
|
+
const start = counterTransform ? performance.now() : 0;
|
|
338
|
+
try {
|
|
339
|
+
// Dev mode: no hash-to-file mapping needed (IDs are already file paths)
|
|
340
|
+
return transformServerReferences(code, id);
|
|
341
|
+
} finally {
|
|
342
|
+
counterTransform?.record(id, performance.now() - start);
|
|
343
|
+
}
|
|
331
344
|
},
|
|
332
345
|
|
|
333
346
|
// Build mode: renderChunk runs after all transforms and bundling complete
|
|
334
347
|
renderChunk(code, chunk) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
code
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
348
|
+
const start = counterRender ? performance.now() : 0;
|
|
349
|
+
try {
|
|
350
|
+
// Only RSC bundle should get file paths for revalidation matching
|
|
351
|
+
// SSR bundle must NOT use file paths because client components run there
|
|
352
|
+
// and need to match the client bundle during hydration (otherwise: error #418)
|
|
353
|
+
const isRscEnv = this.environment?.name === "rsc";
|
|
354
|
+
|
|
355
|
+
// Only use file path mapping for RSC environment
|
|
356
|
+
const effectiveMap = isRscEnv ? hashToFileMap : undefined;
|
|
357
|
+
|
|
358
|
+
// For RSC bundles, both createServerReference and registerServerReference
|
|
359
|
+
// may need transforming. Use a single MagicString for correct sourcemaps.
|
|
360
|
+
if (isRscEnv && hashToFileMap) {
|
|
361
|
+
const s = new MagicString(code);
|
|
362
|
+
const changed1 = applyServerReferenceWrapping(code, s, effectiveMap);
|
|
363
|
+
const changed2 = applyRegisterReferenceWrapping(
|
|
364
|
+
code,
|
|
365
|
+
s,
|
|
366
|
+
hashToFileMap,
|
|
367
|
+
);
|
|
368
|
+
if (changed1 || changed2) {
|
|
369
|
+
return {
|
|
370
|
+
code: s.toString(),
|
|
371
|
+
map: s.generateMap({
|
|
372
|
+
source: chunk.fileName,
|
|
373
|
+
includeContent: true,
|
|
374
|
+
}),
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
return null;
|
|
357
378
|
}
|
|
358
|
-
return null;
|
|
359
|
-
}
|
|
360
379
|
|
|
361
|
-
|
|
362
|
-
|
|
380
|
+
// Non-RSC environments: only transform createServerReference calls
|
|
381
|
+
return transformServerReferences(code, chunk.fileName, effectiveMap);
|
|
382
|
+
} finally {
|
|
383
|
+
counterRender?.record(chunk.fileName, performance.now() - start);
|
|
384
|
+
}
|
|
363
385
|
},
|
|
364
386
|
};
|
|
365
387
|
}
|
|
@@ -19,6 +19,18 @@ export function hashId(filePath: string, exportName: string): string {
|
|
|
19
19
|
return `${hash.slice(0, 8)}#${exportName}`;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Build a stable ID for an export binding. Uses hashed IDs in production
|
|
24
|
+
* builds (short + opaque) and readable path#name IDs in dev.
|
|
25
|
+
*/
|
|
26
|
+
export function makeStubId(
|
|
27
|
+
filePath: string,
|
|
28
|
+
exportName: string,
|
|
29
|
+
isBuild: boolean,
|
|
30
|
+
): string {
|
|
31
|
+
return isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
22
34
|
/**
|
|
23
35
|
* Generate an 8-char hex hash for an inline static handler call site.
|
|
24
36
|
* Uses file path and line number (plus optional index for same-line collisions).
|
|
@@ -138,6 +138,36 @@ export function generateExprStubs(
|
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Replace handler call expressions with lightweight stub objects on an
|
|
143
|
+
* existing MagicString. Unlike generateExprStubs (which creates its own
|
|
144
|
+
* MagicString and returns the full result), this integrates into the
|
|
145
|
+
* unified transform pipeline so all transforms share one sourcemap.
|
|
146
|
+
*/
|
|
147
|
+
export function stubHandlerExprs(
|
|
148
|
+
cfg: HandlerTransformConfig,
|
|
149
|
+
bindings: CreateExportBinding[],
|
|
150
|
+
s: MagicString,
|
|
151
|
+
filePath: string,
|
|
152
|
+
isBuild: boolean,
|
|
153
|
+
): boolean {
|
|
154
|
+
let hasChanges = false;
|
|
155
|
+
for (const binding of bindings) {
|
|
156
|
+
const exportName = binding.exportNames[0];
|
|
157
|
+
const handlerId = isBuild
|
|
158
|
+
? hashId(filePath, exportName)
|
|
159
|
+
: `${filePath}#${exportName}`;
|
|
160
|
+
|
|
161
|
+
s.overwrite(
|
|
162
|
+
binding.callExprStart,
|
|
163
|
+
binding.callCloseParenPos + 1,
|
|
164
|
+
`{ __brand: "${cfg.brand}", $$id: "${handlerId}" }`,
|
|
165
|
+
);
|
|
166
|
+
hasChanges = true;
|
|
167
|
+
}
|
|
168
|
+
return hasChanges;
|
|
169
|
+
}
|
|
170
|
+
|
|
141
171
|
/**
|
|
142
172
|
* Inject $$id into export const handler calls in RSC environments.
|
|
143
173
|
*/
|
|
@@ -4,6 +4,9 @@ import path from "node:path";
|
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import { normalizePath, findMatchingParen } from "../expose-id-utils.js";
|
|
6
6
|
import { getImportedFnNames } from "./export-analysis.js";
|
|
7
|
+
import { createRangoDebugger, createCounter, NS } from "../../debug.js";
|
|
8
|
+
|
|
9
|
+
const debug = createRangoDebugger(NS.transform);
|
|
7
10
|
|
|
8
11
|
export function transformRouter(
|
|
9
12
|
code: string,
|
|
@@ -82,11 +85,15 @@ export function transformRouter(
|
|
|
82
85
|
*/
|
|
83
86
|
export function exposeRouterId(): Plugin {
|
|
84
87
|
let projectRoot = "";
|
|
88
|
+
const counter = createCounter(debug, "expose-router-id");
|
|
85
89
|
return {
|
|
86
90
|
name: "@rangojs/router:expose-router-id",
|
|
87
91
|
configResolved(config) {
|
|
88
92
|
projectRoot = config.root;
|
|
89
93
|
},
|
|
94
|
+
buildEnd() {
|
|
95
|
+
counter?.flush();
|
|
96
|
+
},
|
|
90
97
|
transform(code, id) {
|
|
91
98
|
if (!code.includes("createRouter")) return null;
|
|
92
99
|
// Accepts both @rangojs/router and @rangojs/router/server subpath.
|
|
@@ -102,9 +109,19 @@ export function exposeRouterId(): Plugin {
|
|
|
102
109
|
}
|
|
103
110
|
if (id.includes("node_modules")) return null;
|
|
104
111
|
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
112
|
+
const start = counter ? performance.now() : 0;
|
|
113
|
+
try {
|
|
114
|
+
const filePath = normalizePath(path.relative(projectRoot, id));
|
|
115
|
+
const routerFnNames = getImportedFnNames(code, "createRouter");
|
|
116
|
+
return transformRouter(
|
|
117
|
+
code,
|
|
118
|
+
filePath,
|
|
119
|
+
routerFnNames,
|
|
120
|
+
normalizePath(id),
|
|
121
|
+
);
|
|
122
|
+
} finally {
|
|
123
|
+
counter?.record(id, performance.now() - start);
|
|
124
|
+
}
|
|
108
125
|
},
|
|
109
126
|
};
|
|
110
127
|
}
|