@rangojs/router 0.0.0-experimental.97 → 0.0.0-experimental.98914650
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 +24 -9
- package/dist/bin/rango.js +157 -63
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +1584 -639
- package/package.json +71 -21
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +60 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +222 -30
- package/skills/caching/SKILL.md +263 -8
- package/skills/composability/SKILL.md +27 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +3 -1
- package/skills/hooks/SKILL.md +235 -28
- package/skills/host-router/SKILL.md +122 -22
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +29 -5
- package/skills/layout/SKILL.md +13 -9
- package/skills/links/SKILL.md +173 -17
- package/skills/loader/SKILL.md +170 -23
- package/skills/middleware/SKILL.md +16 -10
- package/skills/migrate-nextjs/SKILL.md +38 -16
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +11 -7
- package/skills/prerender/SKILL.md +14 -33
- package/skills/rango/SKILL.md +250 -25
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +114 -47
- package/skills/route/SKILL.md +42 -5
- package/skills/router-setup/SKILL.md +3 -3
- package/skills/server-actions/SKILL.md +78 -42
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +129 -0
- package/skills/testing/bindings.md +89 -0
- package/skills/testing/cache-prerender.md +124 -0
- package/skills/testing/client-components.md +122 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +92 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +121 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +120 -0
- package/skills/typesafety/SKILL.md +316 -26
- package/skills/use-cache/SKILL.md +36 -5
- package/skills/vercel/SKILL.md +107 -0
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +14 -27
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +37 -143
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/navigation-bridge.ts +30 -59
- package/src/browser/navigation-client.ts +96 -84
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +32 -82
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/partial-update.ts +60 -127
- package/src/browser/prefetch/cache.ts +82 -72
- package/src/browser/prefetch/fetch.ts +108 -33
- package/src/browser/prefetch/queue.ts +6 -3
- package/src/browser/rango-state.ts +157 -115
- package/src/browser/react/Link.tsx +0 -2
- package/src/browser/react/NavigationProvider.tsx +41 -48
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +0 -2
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +166 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +17 -14
- package/src/browser/react/use-link-status.ts +0 -4
- package/src/browser/react/use-navigation.ts +0 -3
- package/src/browser/react/use-params.ts +11 -11
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +20 -5
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +0 -13
- package/src/browser/response-adapter.ts +52 -1
- package/src/browser/rsc-router.tsx +70 -34
- package/src/browser/scroll-restoration.ts +22 -14
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +168 -44
- package/src/browser/types.ts +36 -21
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +60 -35
- package/src/build/generate-route-types.ts +3 -0
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +89 -10
- package/src/build/route-types/codegen.ts +4 -4
- package/src/build/route-types/include-resolution.ts +1 -1
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +7 -4
- package/src/build/route-types/router-processing.ts +122 -22
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-policy.ts +68 -28
- package/src/cache/cache-runtime.ts +134 -32
- package/src/cache/cache-scope.ts +100 -74
- package/src/cache/cache-tag.ts +98 -0
- package/src/cache/cf/cf-cache-store.ts +2255 -238
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +61 -20
- package/src/cache/handle-snapshot.ts +63 -0
- package/src/cache/index.ts +22 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +6 -30
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +0 -16
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +33 -100
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +799 -0
- package/src/client.rsc.tsx +6 -21
- package/src/client.tsx +25 -61
- package/src/component-utils.ts +19 -0
- package/src/context-var.ts +17 -5
- package/src/decode-loader-results.ts +36 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/errors.ts +30 -4
- package/src/handle.ts +31 -23
- package/src/handles/MetaTags.tsx +0 -14
- package/src/handles/breadcrumbs.ts +16 -5
- package/src/handles/meta.ts +0 -39
- package/src/host/cookie-handler.ts +0 -36
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -2
- package/src/host/pattern-matcher.ts +7 -50
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +63 -9
- package/src/index.ts +64 -9
- package/src/internal-debug.ts +2 -4
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/network-error-thrower.tsx +1 -6
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +10 -11
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +61 -6
- package/src/redirect-origin.ts +100 -0
- package/src/response-utils.ts +9 -0
- package/src/reverse.ts +65 -40
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +7 -72
- package/src/route-definition/dsl-helpers.ts +244 -281
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +40 -17
- package/src/route-definition/redirect.ts +43 -9
- package/src/route-definition/resolve-handler-use.ts +6 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +0 -16
- package/src/route-types.ts +19 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +15 -15
- package/src/router/error-handling.ts +13 -17
- package/src/router/find-match.ts +44 -23
- package/src/router/handler-context.ts +4 -41
- package/src/router/intercept-resolution.ts +14 -19
- package/src/router/lazy-includes.ts +9 -46
- package/src/router/loader-resolution.ts +91 -46
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +18 -29
- package/src/router/match-api.ts +0 -20
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +57 -58
- package/src/router/match-middleware/background-revalidation.ts +0 -7
- package/src/router/match-middleware/cache-lookup.ts +150 -271
- package/src/router/match-middleware/cache-store.ts +3 -33
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +31 -80
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +5 -112
- package/src/router/middleware.ts +118 -133
- package/src/router/navigation-snapshot.ts +0 -51
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +62 -67
- package/src/router/prerender-match.ts +99 -63
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +28 -62
- package/src/router/revalidation.ts +50 -56
- package/src/router/route-snapshot.ts +0 -1
- package/src/router/router-context.ts +0 -27
- package/src/router/router-interfaces.ts +68 -35
- package/src/router/router-options.ts +55 -1
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +44 -63
- package/src/router/segment-resolution/helpers.ts +34 -0
- package/src/router/segment-resolution/loader-cache.ts +40 -37
- package/src/router/segment-resolution/revalidation.ts +203 -285
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/segment-resolution.ts +4 -1
- package/src/router/segment-wrappers.ts +0 -3
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +0 -20
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/trie-matching.ts +87 -48
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +0 -5
- package/src/router.ts +80 -41
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +83 -78
- package/src/rsc/helpers.ts +93 -5
- package/src/rsc/index.ts +1 -1
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/manifest-init.ts +28 -41
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +12 -1
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +76 -62
- package/src/rsc/rsc-rendering.ts +41 -60
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +62 -67
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/types.ts +10 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +4 -20
- package/src/segment-loader-promise.ts +14 -2
- package/src/segment-system.tsx +199 -142
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +150 -51
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +7 -24
- package/src/server/loader-registry.ts +5 -24
- package/src/server/request-context.ts +165 -87
- package/src/ssr/index.tsx +14 -14
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +618 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +232 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +99 -0
- package/src/testing/internal/context.ts +348 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +330 -0
- package/src/testing/render-route.tsx +566 -0
- package/src/testing/run-loader.ts +378 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +0 -52
- package/src/theme/ThemeScript.tsx +0 -6
- package/src/theme/constants.ts +0 -12
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +0 -14
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +97 -22
- package/src/types/index.ts +1 -10
- package/src/types/loader-types.ts +6 -3
- package/src/types/request-scope.ts +0 -19
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +18 -14
- package/src/urls/include-helper.ts +9 -56
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +19 -5
- package/src/urls/path-helper.ts +17 -106
- package/src/urls/pattern-types.ts +36 -19
- package/src/urls/response-types.ts +20 -19
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -18
- package/src/use-loader.tsx +292 -107
- package/src/vite/debug.ts +1 -0
- package/src/vite/discovery/bundle-postprocess.ts +8 -7
- package/src/vite/discovery/discover-routers.ts +95 -82
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/prerender-collection.ts +26 -34
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/state.ts +39 -1
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +185 -10
- package/src/vite/plugins/cjs-to-esm.ts +3 -18
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +12 -11
- package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -21
- package/src/vite/plugins/expose-action-id.ts +4 -75
- package/src/vite/plugins/expose-id-utils.ts +3 -54
- package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +6 -74
- package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +0 -13
- package/src/vite/plugins/expose-internal-ids.ts +57 -67
- package/src/vite/plugins/performance-tracks.ts +9 -16
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +26 -49
- package/src/vite/plugins/vercel-output.ts +258 -0
- package/src/vite/plugins/version-injector.ts +2 -32
- package/src/vite/plugins/version-plugin.ts +32 -23
- package/src/vite/plugins/virtual-entries.ts +35 -17
- package/src/vite/rango.ts +148 -115
- package/src/vite/router-discovery.ts +220 -68
- package/src/vite/utils/ast-handler-extract.ts +15 -31
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +1 -73
- package/src/vite/utils/prerender-utils.ts +0 -34
- package/src/vite/utils/shared-utils.ts +95 -43
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/router/middleware-cookies.ts +0 -55
package/dist/vite/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/vite/rango.ts
|
|
2
2
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
3
|
-
import { resolve as
|
|
3
|
+
import { resolve as resolve10 } from "node:path";
|
|
4
4
|
|
|
5
5
|
// src/vite/plugins/expose-action-id.ts
|
|
6
6
|
import MagicString from "magic-string";
|
|
@@ -21,8 +21,8 @@ function hashId(filePath, exportName) {
|
|
|
21
21
|
function makeStubId(filePath, exportName, isBuild) {
|
|
22
22
|
return isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
|
|
23
23
|
}
|
|
24
|
-
function hashInlineId(filePath,
|
|
25
|
-
const input =
|
|
24
|
+
function hashInlineId(filePath, fnName, index) {
|
|
25
|
+
const input = `${filePath}:${fnName}:${index}`;
|
|
26
26
|
return crypto.createHash("sha256").update(input).digest("hex").slice(0, 8);
|
|
27
27
|
}
|
|
28
28
|
function buildExportMap(program) {
|
|
@@ -200,7 +200,8 @@ var NS = {
|
|
|
200
200
|
prerender: "rango:prerender",
|
|
201
201
|
build: "rango:build",
|
|
202
202
|
dev: "rango:dev",
|
|
203
|
-
transform: "rango:transform"
|
|
203
|
+
transform: "rango:transform",
|
|
204
|
+
chunks: "rango:chunks"
|
|
204
205
|
};
|
|
205
206
|
if (process.env.INTERNAL_RANGO_DEBUG) {
|
|
206
207
|
const existing = debugFactory.disable();
|
|
@@ -292,7 +293,7 @@ function getRscPluginApi(config) {
|
|
|
292
293
|
);
|
|
293
294
|
if (plugin) {
|
|
294
295
|
console.warn(
|
|
295
|
-
`[
|
|
296
|
+
`[rango:expose-action-id] RSC plugin found by API structure (name: "${plugin.name}"). Consider updating the name lookup if the plugin was renamed.`
|
|
296
297
|
);
|
|
297
298
|
}
|
|
298
299
|
}
|
|
@@ -393,7 +394,7 @@ function exposeActionId() {
|
|
|
393
394
|
}
|
|
394
395
|
if (!rscPluginApi) {
|
|
395
396
|
throw new Error(
|
|
396
|
-
"[
|
|
397
|
+
"[rango] Could not find @vitejs/plugin-rsc. @rangojs/router requires the Vite RSC plugin, which is included automatically by rango()."
|
|
397
398
|
);
|
|
398
399
|
}
|
|
399
400
|
if (!isBuild) return;
|
|
@@ -430,7 +431,6 @@ function exposeActionId() {
|
|
|
430
431
|
counterTransform?.record(id, performance.now() - start);
|
|
431
432
|
}
|
|
432
433
|
},
|
|
433
|
-
// Build mode: renderChunk runs after all transforms and bundling complete
|
|
434
434
|
renderChunk(code, chunk) {
|
|
435
435
|
const start = counterRender ? performance.now() : 0;
|
|
436
436
|
try {
|
|
@@ -465,7 +465,7 @@ function exposeActionId() {
|
|
|
465
465
|
|
|
466
466
|
// src/vite/plugins/expose-internal-ids.ts
|
|
467
467
|
import { parseAst as parseAst2 } from "vite";
|
|
468
|
-
import
|
|
468
|
+
import MagicString3 from "magic-string";
|
|
469
469
|
import path4 from "node:path";
|
|
470
470
|
|
|
471
471
|
// src/vite/utils/ast-handler-extract.ts
|
|
@@ -475,7 +475,7 @@ function isDirectivePrologueStatement(node) {
|
|
|
475
475
|
function findImportInsertionPos(code, parseAst4) {
|
|
476
476
|
let program;
|
|
477
477
|
try {
|
|
478
|
-
program = parseAst4(code, {
|
|
478
|
+
program = parseAst4(code, { lang: "tsx" });
|
|
479
479
|
} catch {
|
|
480
480
|
return 0;
|
|
481
481
|
}
|
|
@@ -515,7 +515,7 @@ function walkNode(node, parent, ancestors, enter) {
|
|
|
515
515
|
function findHandlerCalls(code, fnName, parseAst4) {
|
|
516
516
|
let program;
|
|
517
517
|
try {
|
|
518
|
-
program = parseAst4(code, {
|
|
518
|
+
program = parseAst4(code, { lang: "tsx" });
|
|
519
519
|
} catch {
|
|
520
520
|
return [];
|
|
521
521
|
}
|
|
@@ -589,7 +589,7 @@ function getImportedLocalNamesFromProgram(program, importedName) {
|
|
|
589
589
|
}
|
|
590
590
|
function getImportedLocalNames(code, importedName, parseAst4) {
|
|
591
591
|
try {
|
|
592
|
-
const program = parseAst4(code, {
|
|
592
|
+
const program = parseAst4(code, { lang: "tsx" });
|
|
593
593
|
return getImportedLocalNamesFromProgram(program, importedName);
|
|
594
594
|
} catch {
|
|
595
595
|
return /* @__PURE__ */ new Set();
|
|
@@ -598,7 +598,7 @@ function getImportedLocalNames(code, importedName, parseAst4) {
|
|
|
598
598
|
function extractImportDeclarations(code, parseAst4) {
|
|
599
599
|
let program;
|
|
600
600
|
try {
|
|
601
|
-
program = parseAst4(code, {
|
|
601
|
+
program = parseAst4(code, { lang: "tsx" });
|
|
602
602
|
} catch {
|
|
603
603
|
return [];
|
|
604
604
|
}
|
|
@@ -653,7 +653,7 @@ function isSafeVariableDeclaration(node, handlerNames) {
|
|
|
653
653
|
function extractModuleLevelDeclarations(code, parseAst4, handlerNames) {
|
|
654
654
|
let program;
|
|
655
655
|
try {
|
|
656
|
-
program = parseAst4(code, {
|
|
656
|
+
program = parseAst4(code, { lang: "tsx" });
|
|
657
657
|
} catch {
|
|
658
658
|
return [];
|
|
659
659
|
}
|
|
@@ -697,14 +697,12 @@ function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtu
|
|
|
697
697
|
parseAst4,
|
|
698
698
|
handlerNames
|
|
699
699
|
);
|
|
700
|
-
const lineCounts = /* @__PURE__ */ new Map();
|
|
701
700
|
const importStatements = [];
|
|
702
|
-
for (const site of inlineSites) {
|
|
703
|
-
const
|
|
704
|
-
lineCounts.set(site.lineNumber, lineCount + 1);
|
|
705
|
-
const hash = hashInlineId(filePath, site.lineNumber, lineCount);
|
|
701
|
+
for (const [siteIndex, site] of inlineSites.entries()) {
|
|
702
|
+
const hash = hashInlineId(filePath, fnName, siteIndex);
|
|
706
703
|
const exportName = `__sh_${hash}`;
|
|
707
|
-
const
|
|
704
|
+
const idSuffix = `${filePath}:${fnName}:${siteIndex}`;
|
|
705
|
+
const virtualId = `\0${virtualPrefix}${idSuffix}`;
|
|
708
706
|
const handlerCode = code.slice(site.callStart, site.callEnd);
|
|
709
707
|
virtualRegistry.set(virtualId, {
|
|
710
708
|
originalModuleId: moduleId,
|
|
@@ -714,7 +712,7 @@ function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtu
|
|
|
714
712
|
exportName
|
|
715
713
|
});
|
|
716
714
|
s.overwrite(site.callStart, site.callEnd, exportName);
|
|
717
|
-
const importId = `${virtualPrefix}${
|
|
715
|
+
const importId = `${virtualPrefix}${idSuffix}`;
|
|
718
716
|
importStatements.push(`import { ${exportName} } from "${importId}";`);
|
|
719
717
|
}
|
|
720
718
|
if (importStatements.length > 0) {
|
|
@@ -746,6 +744,83 @@ var STRICT_CREATE_CONFIGS = [
|
|
|
746
744
|
|
|
747
745
|
// src/vite/plugins/expose-ids/export-analysis.ts
|
|
748
746
|
import { parseAst } from "vite";
|
|
747
|
+
|
|
748
|
+
// src/build/route-types/source-scan.ts
|
|
749
|
+
function isLineTerminator(ch) {
|
|
750
|
+
const c = ch.charCodeAt(0);
|
|
751
|
+
return c === 10 || c === 13 || c === 8232 || c === 8233;
|
|
752
|
+
}
|
|
753
|
+
function makeCodeClassifier(code) {
|
|
754
|
+
const n = code.length;
|
|
755
|
+
let i = 0;
|
|
756
|
+
let skipStart = -1;
|
|
757
|
+
let skipEnd = -1;
|
|
758
|
+
return (q) => {
|
|
759
|
+
if (q >= skipStart && q < skipEnd) return false;
|
|
760
|
+
while (i < n && i <= q) {
|
|
761
|
+
const c = code[i];
|
|
762
|
+
const d = i + 1 < n ? code[i + 1] : "";
|
|
763
|
+
let end = -1;
|
|
764
|
+
if (c === "/" && d === "/") {
|
|
765
|
+
let j = i + 2;
|
|
766
|
+
while (j < n && !isLineTerminator(code[j])) j++;
|
|
767
|
+
end = j;
|
|
768
|
+
} else if (c === "/" && d === "*") {
|
|
769
|
+
let j = i + 2;
|
|
770
|
+
while (j < n && !(code[j] === "*" && code[j + 1] === "/")) j++;
|
|
771
|
+
end = Math.min(n, j + 2);
|
|
772
|
+
} else if (c === '"' || c === "'" || c === "`") {
|
|
773
|
+
let j = i + 1;
|
|
774
|
+
while (j < n) {
|
|
775
|
+
if (code[j] === "\\") {
|
|
776
|
+
j += 2;
|
|
777
|
+
continue;
|
|
778
|
+
}
|
|
779
|
+
if (code[j] === c) {
|
|
780
|
+
j++;
|
|
781
|
+
break;
|
|
782
|
+
}
|
|
783
|
+
j++;
|
|
784
|
+
}
|
|
785
|
+
end = j;
|
|
786
|
+
}
|
|
787
|
+
if (end >= 0) {
|
|
788
|
+
if (q < end) {
|
|
789
|
+
skipStart = i;
|
|
790
|
+
skipEnd = end;
|
|
791
|
+
return false;
|
|
792
|
+
}
|
|
793
|
+
i = end;
|
|
794
|
+
} else {
|
|
795
|
+
i++;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
return true;
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
function firstCodeMatchIndex(code, pattern) {
|
|
802
|
+
const inCode = makeCodeClassifier(code);
|
|
803
|
+
pattern.lastIndex = 0;
|
|
804
|
+
let m;
|
|
805
|
+
while ((m = pattern.exec(code)) !== null) {
|
|
806
|
+
if (inCode(m.index)) return m.index;
|
|
807
|
+
if (pattern.lastIndex <= m.index) pattern.lastIndex = m.index + 1;
|
|
808
|
+
}
|
|
809
|
+
return -1;
|
|
810
|
+
}
|
|
811
|
+
function codeMatchIndices(code, pattern) {
|
|
812
|
+
const inCode = makeCodeClassifier(code);
|
|
813
|
+
const indices = [];
|
|
814
|
+
pattern.lastIndex = 0;
|
|
815
|
+
let m;
|
|
816
|
+
while ((m = pattern.exec(code)) !== null) {
|
|
817
|
+
if (inCode(m.index)) indices.push(m.index);
|
|
818
|
+
if (pattern.lastIndex <= m.index) pattern.lastIndex = m.index + 1;
|
|
819
|
+
}
|
|
820
|
+
return indices;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// src/vite/plugins/expose-ids/export-analysis.ts
|
|
749
824
|
function isExportOnlyFile(code, bindings) {
|
|
750
825
|
if (bindings.length === 0) return false;
|
|
751
826
|
const knownLocals = /* @__PURE__ */ new Set();
|
|
@@ -774,12 +849,30 @@ function isExportOnlyFile(code, bindings) {
|
|
|
774
849
|
}
|
|
775
850
|
return true;
|
|
776
851
|
}
|
|
777
|
-
function
|
|
778
|
-
|
|
852
|
+
function createCallPattern(fnNames) {
|
|
853
|
+
return new RegExp(
|
|
779
854
|
`\\b(?:${fnNames.map(escapeRegExp).join("|")})\\s*(?:<[^>]*>\\s*)?\\(`,
|
|
780
855
|
"g"
|
|
781
856
|
);
|
|
782
|
-
|
|
857
|
+
}
|
|
858
|
+
function countCreateCallsForNames(code, fnNames) {
|
|
859
|
+
return codeMatchIndices(code, createCallPattern(fnNames)).length;
|
|
860
|
+
}
|
|
861
|
+
function offsetToLineColumn(code, index) {
|
|
862
|
+
let line = 1;
|
|
863
|
+
let lineStart = 0;
|
|
864
|
+
const end = Math.min(index, code.length);
|
|
865
|
+
for (let i = 0; i < end; i++) {
|
|
866
|
+
if (code[i] === "\n") {
|
|
867
|
+
line++;
|
|
868
|
+
lineStart = i + 1;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
return { line, column: index - lineStart + 1 };
|
|
872
|
+
}
|
|
873
|
+
function findUnsupportedCreateCallSites(code, fnNames, supportedBindings) {
|
|
874
|
+
const supported = new Set(supportedBindings.map((b) => b.callExprStart));
|
|
875
|
+
return codeMatchIndices(code, createCallPattern(fnNames)).filter((index) => !supported.has(index)).map((index) => offsetToLineColumn(code, index));
|
|
783
876
|
}
|
|
784
877
|
function getImportedFnNames(code, importedName) {
|
|
785
878
|
const importPattern = /import\s*\{([^}]*)\}\s*from\s*["']@rangojs\/router(?:\/[^"']*)?["']/g;
|
|
@@ -810,6 +903,17 @@ function getCalledIdentifierFromCall(callExpr) {
|
|
|
810
903
|
}
|
|
811
904
|
return null;
|
|
812
905
|
}
|
|
906
|
+
function unwrapSignatureWrappedCall(init, fnNameSet) {
|
|
907
|
+
if (init?.type !== "CallExpression") return init;
|
|
908
|
+
const directId = getCalledIdentifierFromCall(init);
|
|
909
|
+
if (directId && fnNameSet.has(directId)) return init;
|
|
910
|
+
const firstArg = init.arguments?.[0];
|
|
911
|
+
if (firstArg?.type === "CallExpression") {
|
|
912
|
+
const innerId = getCalledIdentifierFromCall(firstArg);
|
|
913
|
+
if (innerId && fnNameSet.has(innerId)) return firstArg;
|
|
914
|
+
}
|
|
915
|
+
return init;
|
|
916
|
+
}
|
|
813
917
|
function collectCreateExportBindingsFallback(code, fnNames) {
|
|
814
918
|
const alternation = fnNames.map(escapeRegExp).join("|");
|
|
815
919
|
const exportConstPattern = new RegExp(
|
|
@@ -869,7 +973,7 @@ function collectCreateExportBindingsFallback(code, fnNames) {
|
|
|
869
973
|
function collectCreateExportBindings(code, fnNames, program) {
|
|
870
974
|
if (!program) {
|
|
871
975
|
try {
|
|
872
|
-
program = parseAst(code, {
|
|
976
|
+
program = parseAst(code, { lang: "tsx" });
|
|
873
977
|
} catch {
|
|
874
978
|
return collectCreateExportBindingsFallback(code, fnNames);
|
|
875
979
|
}
|
|
@@ -882,16 +986,16 @@ function collectCreateExportBindings(code, fnNames, program) {
|
|
|
882
986
|
return;
|
|
883
987
|
}
|
|
884
988
|
for (const decl of varDecl.declarations ?? []) {
|
|
885
|
-
const
|
|
886
|
-
|
|
989
|
+
const callExpr = unwrapSignatureWrappedCall(decl?.init, fnNameSet);
|
|
990
|
+
const calledIdentifier = getCalledIdentifierFromCall(callExpr);
|
|
991
|
+
if (decl?.id?.type !== "Identifier" || callExpr?.type !== "CallExpression" || !calledIdentifier || !fnNameSet.has(calledIdentifier)) {
|
|
887
992
|
continue;
|
|
888
993
|
}
|
|
889
994
|
const localName = decl.id.name;
|
|
890
995
|
const exportNames = exportMap.get(localName) ?? [];
|
|
891
996
|
if (exportNames.length === 0) continue;
|
|
892
|
-
const
|
|
893
|
-
const
|
|
894
|
-
const calleeEnd = decl.init.callee.end;
|
|
997
|
+
const callEnd = callExpr.end;
|
|
998
|
+
const calleeEnd = callExpr.callee.end;
|
|
895
999
|
let openParenPos = -1;
|
|
896
1000
|
for (let i = calleeEnd; i < callEnd; i++) {
|
|
897
1001
|
if (code[i] === "(") {
|
|
@@ -905,10 +1009,10 @@ function collectCreateExportBindings(code, fnNames, program) {
|
|
|
905
1009
|
bindings.push({
|
|
906
1010
|
localName,
|
|
907
1011
|
exportNames,
|
|
908
|
-
callExprStart:
|
|
1012
|
+
callExprStart: callExpr.start,
|
|
909
1013
|
callOpenParenPos: openParenPos,
|
|
910
1014
|
callCloseParenPos: closeParenPos,
|
|
911
|
-
argCount:
|
|
1015
|
+
argCount: callExpr.arguments?.length ?? 0,
|
|
912
1016
|
statementEnd
|
|
913
1017
|
});
|
|
914
1018
|
}
|
|
@@ -927,9 +1031,20 @@ function collectCreateExportBindings(code, fnNames, program) {
|
|
|
927
1031
|
}
|
|
928
1032
|
return bindings;
|
|
929
1033
|
}
|
|
930
|
-
function buildUnsupportedShapeWarning(filePath, fnName) {
|
|
931
|
-
|
|
932
|
-
|
|
1034
|
+
function buildUnsupportedShapeWarning(filePath, fnName, sites = []) {
|
|
1035
|
+
const lines = [`[rango] Unsupported ${fnName} shape in "${filePath}".`];
|
|
1036
|
+
if (sites.length === 1) {
|
|
1037
|
+
const s = sites[0];
|
|
1038
|
+
lines.push(
|
|
1039
|
+
`The ${fnName}(...) call at ${filePath}:${s.line}:${s.column} has no stable $$id injected \u2014 it is not in a supported shape.`
|
|
1040
|
+
);
|
|
1041
|
+
} else if (sites.length > 1) {
|
|
1042
|
+
lines.push(
|
|
1043
|
+
`These ${fnName}(...) calls have no stable $$id injected \u2014 they are not in a supported shape:`
|
|
1044
|
+
);
|
|
1045
|
+
for (const s of sites) lines.push(` - ${filePath}:${s.line}:${s.column}`);
|
|
1046
|
+
}
|
|
1047
|
+
lines.push(
|
|
933
1048
|
`Supported shapes are:`,
|
|
934
1049
|
` - export const X = ${fnName}(...)`,
|
|
935
1050
|
` - const X = ${fnName}(...); export { X }`,
|
|
@@ -937,7 +1052,8 @@ function buildUnsupportedShapeWarning(filePath, fnName) {
|
|
|
937
1052
|
`Potentially unsupported forms include:`,
|
|
938
1053
|
` - export let/var X = ${fnName}(...)`,
|
|
939
1054
|
` - inline ${fnName}(...) calls`
|
|
940
|
-
|
|
1055
|
+
);
|
|
1056
|
+
return lines.join("\n");
|
|
941
1057
|
}
|
|
942
1058
|
|
|
943
1059
|
// src/vite/plugins/expose-ids/loader-transform.ts
|
|
@@ -951,7 +1067,7 @@ function generateClientLoaderStubs(bindings, code, filePath, isBuild) {
|
|
|
951
1067
|
const lines = [];
|
|
952
1068
|
for (const binding of bindings) {
|
|
953
1069
|
for (const name of binding.exportNames) {
|
|
954
|
-
const loaderId =
|
|
1070
|
+
const loaderId = makeStubId(filePath, name, isBuild);
|
|
955
1071
|
lines.push(
|
|
956
1072
|
`export const ${name} = { __brand: "loader", $$id: "${loaderId}" };`
|
|
957
1073
|
);
|
|
@@ -963,7 +1079,7 @@ function transformLoaders(bindings, s, filePath, isBuild) {
|
|
|
963
1079
|
let hasChanges = false;
|
|
964
1080
|
for (const binding of bindings) {
|
|
965
1081
|
const exportName = binding.exportNames[0];
|
|
966
|
-
const loaderId =
|
|
1082
|
+
const loaderId = makeStubId(filePath, exportName, isBuild);
|
|
967
1083
|
const paramInjection = binding.argCount === 1 ? `, undefined, "${loaderId}"` : `, "${loaderId}"`;
|
|
968
1084
|
s.appendLeft(binding.callCloseParenPos, paramInjection);
|
|
969
1085
|
const propInjection = `
|
|
@@ -975,7 +1091,6 @@ ${binding.localName}.$$id = "${loaderId}";`;
|
|
|
975
1091
|
}
|
|
976
1092
|
|
|
977
1093
|
// src/vite/plugins/expose-ids/handler-transform.ts
|
|
978
|
-
import MagicString2 from "magic-string";
|
|
979
1094
|
function analyzeCreateHandleArgs(code, startPos, endPos) {
|
|
980
1095
|
const content = code.slice(startPos, endPos).trim();
|
|
981
1096
|
return { hasArgs: content.length > 0 };
|
|
@@ -989,7 +1104,7 @@ function transformHandles(bindings, s, code, filePath, isBuild) {
|
|
|
989
1104
|
binding.callOpenParenPos + 1,
|
|
990
1105
|
binding.callCloseParenPos
|
|
991
1106
|
);
|
|
992
|
-
const handleId =
|
|
1107
|
+
const handleId = makeStubId(filePath, exportName, isBuild);
|
|
993
1108
|
let paramInjection;
|
|
994
1109
|
if (!args.hasArgs) {
|
|
995
1110
|
paramInjection = `undefined, "${handleId}"`;
|
|
@@ -1008,7 +1123,7 @@ function transformLocationState(bindings, s, filePath, isBuild) {
|
|
|
1008
1123
|
let hasChanges = false;
|
|
1009
1124
|
for (const binding of bindings) {
|
|
1010
1125
|
const exportName = binding.exportNames[0];
|
|
1011
|
-
const stateKey =
|
|
1126
|
+
const stateKey = makeStubId(filePath, exportName, isBuild);
|
|
1012
1127
|
const propInjection = `
|
|
1013
1128
|
${binding.localName}.__rsc_ls_key = "__rsc_ls_${stateKey}";`;
|
|
1014
1129
|
s.appendRight(binding.statementEnd, propInjection);
|
|
@@ -1020,7 +1135,7 @@ function generateWholeFileStubs(cfg, bindings, code, filePath, isBuild) {
|
|
|
1020
1135
|
if (!isExportOnlyFile(code, bindings)) return null;
|
|
1021
1136
|
const exportNames = bindings.flatMap((b) => b.exportNames);
|
|
1022
1137
|
const stubs = exportNames.map((name) => {
|
|
1023
|
-
const handlerId =
|
|
1138
|
+
const handlerId = makeStubId(filePath, name, isBuild);
|
|
1024
1139
|
return `export const ${name} = { __brand: "${cfg.brand}", $$id: "${handlerId}" };`;
|
|
1025
1140
|
});
|
|
1026
1141
|
return { code: stubs.join("\n") + "\n", map: null };
|
|
@@ -1029,7 +1144,7 @@ function stubHandlerExprs(cfg, bindings, s, filePath, isBuild) {
|
|
|
1029
1144
|
let hasChanges = false;
|
|
1030
1145
|
for (const binding of bindings) {
|
|
1031
1146
|
const exportName = binding.exportNames[0];
|
|
1032
|
-
const handlerId =
|
|
1147
|
+
const handlerId = makeStubId(filePath, exportName, isBuild);
|
|
1033
1148
|
s.overwrite(
|
|
1034
1149
|
binding.callExprStart,
|
|
1035
1150
|
binding.callCloseParenPos + 1,
|
|
@@ -1043,7 +1158,7 @@ function transformHandlerIds(cfg, bindings, s, filePath, isBuild) {
|
|
|
1043
1158
|
let hasChanges = false;
|
|
1044
1159
|
for (const binding of bindings) {
|
|
1045
1160
|
const exportName = binding.exportNames[0];
|
|
1046
|
-
const handlerId =
|
|
1161
|
+
const handlerId = makeStubId(filePath, exportName, isBuild);
|
|
1047
1162
|
let paramInjection;
|
|
1048
1163
|
if (binding.argCount === 0) {
|
|
1049
1164
|
paramInjection = `undefined, "${handlerId}"`;
|
|
@@ -1062,7 +1177,7 @@ ${binding.localName}.$$id = "${handlerId}";`;
|
|
|
1062
1177
|
}
|
|
1063
1178
|
|
|
1064
1179
|
// src/vite/plugins/expose-ids/router-transform.ts
|
|
1065
|
-
import
|
|
1180
|
+
import MagicString2 from "magic-string";
|
|
1066
1181
|
import path3 from "node:path";
|
|
1067
1182
|
import { createHash } from "node:crypto";
|
|
1068
1183
|
var debug2 = createRangoDebugger(NS.transform);
|
|
@@ -1072,10 +1187,10 @@ function transformRouter(code, filePath, routerFnNames, absolutePath) {
|
|
|
1072
1187
|
"g"
|
|
1073
1188
|
);
|
|
1074
1189
|
let match;
|
|
1075
|
-
const s = new
|
|
1190
|
+
const s = new MagicString2(code);
|
|
1076
1191
|
let changed = false;
|
|
1077
|
-
const
|
|
1078
|
-
const routeNamesImport = `./${
|
|
1192
|
+
const basename2 = path3.basename(filePath).replace(/\.(tsx?|jsx?)$/, "");
|
|
1193
|
+
const routeNamesImport = `./${basename2}.named-routes.gen.js`;
|
|
1079
1194
|
const routeNamesVar = `__rsc_rn`;
|
|
1080
1195
|
while ((match = pat.exec(code)) !== null) {
|
|
1081
1196
|
const callStart = match.index;
|
|
@@ -1229,6 +1344,7 @@ ${lazyImports.join(",\n")}
|
|
|
1229
1344
|
// --------------- Loader pre-scan (build mode) ---------------
|
|
1230
1345
|
async buildStart() {
|
|
1231
1346
|
if (!isBuild) return;
|
|
1347
|
+
if (this.environment && this.environment.name !== "rsc") return;
|
|
1232
1348
|
const fs2 = await import("node:fs/promises");
|
|
1233
1349
|
const SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", "build", "coverage"]);
|
|
1234
1350
|
async function scanDir(dir) {
|
|
@@ -1335,7 +1451,7 @@ ${lazyImports.join(",\n")}
|
|
|
1335
1451
|
}
|
|
1336
1452
|
if (_cachedAst !== void 0 || _astParseFailed) return _cachedAst;
|
|
1337
1453
|
try {
|
|
1338
|
-
_cachedAst = parseAst2(code, {
|
|
1454
|
+
_cachedAst = parseAst2(code, { lang: "tsx" });
|
|
1339
1455
|
} catch {
|
|
1340
1456
|
_astParseFailed = true;
|
|
1341
1457
|
}
|
|
@@ -1358,13 +1474,16 @@ ${lazyImports.join(",\n")}
|
|
|
1358
1474
|
const hasCode = cfg.fnName === "createLoader" ? hasLoaderCode : cfg.fnName === "createHandle" ? hasHandleCode : hasLocationStateCode;
|
|
1359
1475
|
if (!hasCode) continue;
|
|
1360
1476
|
const fnNames = getFnNames(cfg.fnName);
|
|
1361
|
-
const
|
|
1362
|
-
|
|
1363
|
-
|
|
1477
|
+
const sites = findUnsupportedCreateCallSites(
|
|
1478
|
+
code,
|
|
1479
|
+
fnNames,
|
|
1480
|
+
getBindings(code, fnNames)
|
|
1481
|
+
);
|
|
1482
|
+
if (sites.length === 0) continue;
|
|
1364
1483
|
const warnKey = `${id}::${cfg.fnName}`;
|
|
1365
1484
|
if (unsupportedShapeWarnings.has(warnKey)) continue;
|
|
1366
1485
|
unsupportedShapeWarnings.add(warnKey);
|
|
1367
|
-
this.warn(buildUnsupportedShapeWarning(filePath, cfg.fnName));
|
|
1486
|
+
this.warn(buildUnsupportedShapeWarning(filePath, cfg.fnName, sites));
|
|
1368
1487
|
}
|
|
1369
1488
|
if (hasLoaderCode && isRscEnv) {
|
|
1370
1489
|
const fnNames = getFnNames("createLoader");
|
|
@@ -1401,15 +1520,6 @@ ${lazyImports.join(",\n")}
|
|
|
1401
1520
|
);
|
|
1402
1521
|
if (wholeFile) return wholeFile;
|
|
1403
1522
|
}
|
|
1404
|
-
if (hasPrerenderHandlerCode && isRscEnv && isBuild) {
|
|
1405
|
-
const fnNames = getFnNames(PRERENDER_CONFIG.fnName);
|
|
1406
|
-
const exportNames = getBindings(code, fnNames).map(
|
|
1407
|
-
(b) => b.exportNames[0]
|
|
1408
|
-
);
|
|
1409
|
-
if (exportNames.length > 0) {
|
|
1410
|
-
prerenderHandlerModules.set(id, exportNames);
|
|
1411
|
-
}
|
|
1412
|
-
}
|
|
1413
1523
|
let changed = false;
|
|
1414
1524
|
const handlerConfigs = [
|
|
1415
1525
|
hasStaticHandlerCode && STATIC_CONFIG,
|
|
@@ -1422,7 +1532,7 @@ ${lazyImports.join(",\n")}
|
|
|
1422
1532
|
const totalCalls = countCreateCallsForNames(code, fnNames);
|
|
1423
1533
|
const supportedBindings = getBindings(code, fnNames).length;
|
|
1424
1534
|
if (totalCalls > supportedBindings) {
|
|
1425
|
-
const iterS = new
|
|
1535
|
+
const iterS = new MagicString3(code);
|
|
1426
1536
|
const result = transformInlineHandlers(
|
|
1427
1537
|
cfg.fnName,
|
|
1428
1538
|
VIRTUAL_HANDLER_PREFIX,
|
|
@@ -1587,16 +1697,24 @@ ${lazyImports.join(",\n")}
|
|
|
1587
1697
|
return { code: lines.join("\n") + "\n", map: null };
|
|
1588
1698
|
}
|
|
1589
1699
|
}
|
|
1590
|
-
if (
|
|
1591
|
-
const
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1700
|
+
if (isRscEnv && isBuild) {
|
|
1701
|
+
const trackTypes = [
|
|
1702
|
+
[
|
|
1703
|
+
hasPrerenderHandlerCode,
|
|
1704
|
+
PRERENDER_CONFIG,
|
|
1705
|
+
prerenderHandlerModules
|
|
1706
|
+
],
|
|
1707
|
+
[hasStaticHandlerCode, STATIC_CONFIG, staticHandlerModules]
|
|
1708
|
+
];
|
|
1709
|
+
for (const [has2, cfg, trackMap] of trackTypes) {
|
|
1710
|
+
if (!has2) continue;
|
|
1711
|
+
const exportNames = getBindings(code, getFnNames(cfg.fnName)).map(
|
|
1712
|
+
(b) => b.exportNames[0]
|
|
1713
|
+
);
|
|
1714
|
+
if (exportNames.length > 0) trackMap.set(id, exportNames);
|
|
1597
1715
|
}
|
|
1598
1716
|
}
|
|
1599
|
-
const s = new
|
|
1717
|
+
const s = new MagicString3(code);
|
|
1600
1718
|
if (hasLoaderCode) {
|
|
1601
1719
|
const fnNames = getFnNames("createLoader");
|
|
1602
1720
|
changed = transformLoaders(
|
|
@@ -1625,41 +1743,13 @@ ${lazyImports.join(",\n")}
|
|
|
1625
1743
|
isBuild
|
|
1626
1744
|
) || changed;
|
|
1627
1745
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
s,
|
|
1636
|
-
filePath,
|
|
1637
|
-
isBuild
|
|
1638
|
-
) || changed;
|
|
1639
|
-
} else {
|
|
1640
|
-
changed = stubHandlerExprs(
|
|
1641
|
-
PRERENDER_CONFIG,
|
|
1642
|
-
bindings,
|
|
1643
|
-
s,
|
|
1644
|
-
filePath,
|
|
1645
|
-
isBuild
|
|
1646
|
-
) || changed;
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
if (hasStaticHandlerCode) {
|
|
1650
|
-
const fnNames = getFnNames(STATIC_CONFIG.fnName);
|
|
1651
|
-
const bindings = getBindings(code, fnNames);
|
|
1652
|
-
if (isRscEnv) {
|
|
1653
|
-
changed = transformHandlerIds(
|
|
1654
|
-
STATIC_CONFIG,
|
|
1655
|
-
bindings,
|
|
1656
|
-
s,
|
|
1657
|
-
filePath,
|
|
1658
|
-
isBuild
|
|
1659
|
-
) || changed;
|
|
1660
|
-
} else {
|
|
1661
|
-
changed = stubHandlerExprs(STATIC_CONFIG, bindings, s, filePath, isBuild) || changed;
|
|
1662
|
-
}
|
|
1746
|
+
const finalHandlerConfigs = [
|
|
1747
|
+
hasPrerenderHandlerCode && PRERENDER_CONFIG,
|
|
1748
|
+
hasStaticHandlerCode && STATIC_CONFIG
|
|
1749
|
+
].filter((c) => !!c);
|
|
1750
|
+
for (const cfg of finalHandlerConfigs) {
|
|
1751
|
+
const bindings = getBindings(code, getFnNames(cfg.fnName));
|
|
1752
|
+
changed = (isRscEnv ? transformHandlerIds(cfg, bindings, s, filePath, isBuild) : stubHandlerExprs(cfg, bindings, s, filePath, isBuild)) || changed;
|
|
1663
1753
|
}
|
|
1664
1754
|
if (!changed) return;
|
|
1665
1755
|
return {
|
|
@@ -1675,10 +1765,11 @@ ${lazyImports.join(",\n")}
|
|
|
1675
1765
|
|
|
1676
1766
|
// src/vite/plugins/use-cache-transform.ts
|
|
1677
1767
|
import path5 from "node:path";
|
|
1678
|
-
import
|
|
1768
|
+
import MagicString4 from "magic-string";
|
|
1679
1769
|
var debug4 = createRangoDebugger(NS.transform);
|
|
1680
1770
|
var CACHE_RUNTIME_IMPORT = "@rangojs/router/cache-runtime";
|
|
1681
1771
|
var LAYOUT_TEMPLATE_PATTERN = /\/(layout|template)\.(tsx?|jsx?)$/;
|
|
1772
|
+
var USE_CACHE_DIRECTIVE_RE = /^use cache(:\s*[\w-]+)?$/;
|
|
1682
1773
|
function useCacheTransform() {
|
|
1683
1774
|
let projectRoot = "";
|
|
1684
1775
|
let isBuild = false;
|
|
@@ -1716,7 +1807,7 @@ function useCacheTransform() {
|
|
|
1716
1807
|
let ast;
|
|
1717
1808
|
try {
|
|
1718
1809
|
const { parseAst: parseAst4 } = await import("vite");
|
|
1719
|
-
ast = parseAst4(code);
|
|
1810
|
+
ast = parseAst4(code, { lang: "tsx" });
|
|
1720
1811
|
} catch {
|
|
1721
1812
|
return;
|
|
1722
1813
|
}
|
|
@@ -1750,7 +1841,7 @@ function useCacheTransform() {
|
|
|
1750
1841
|
};
|
|
1751
1842
|
}
|
|
1752
1843
|
function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLayoutOrTemplate, transformWrapExport) {
|
|
1753
|
-
const
|
|
1844
|
+
const unconfirmedExports = [];
|
|
1754
1845
|
const { exportNames, output } = transformWrapExport(code, ast, {
|
|
1755
1846
|
runtime: (value, name) => {
|
|
1756
1847
|
const funcId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
|
|
@@ -1759,20 +1850,21 @@ function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLa
|
|
|
1759
1850
|
rejectNonAsyncFunction: false,
|
|
1760
1851
|
filter: (name, meta) => {
|
|
1761
1852
|
if (name === "default" && isLayoutOrTemplate) return false;
|
|
1762
|
-
if (meta.isFunction
|
|
1763
|
-
|
|
1853
|
+
if (meta.isFunction !== true) {
|
|
1854
|
+
unconfirmedExports.push(name);
|
|
1764
1855
|
return false;
|
|
1765
1856
|
}
|
|
1766
1857
|
return true;
|
|
1767
1858
|
}
|
|
1768
1859
|
});
|
|
1769
|
-
if (
|
|
1860
|
+
if (unconfirmedExports.length > 0) {
|
|
1861
|
+
const plural = unconfirmedExports.length > 1;
|
|
1770
1862
|
throw new Error(
|
|
1771
|
-
`[rango:use-cache] File-level "use cache" in ${sourceId}
|
|
1863
|
+
`[rango:use-cache] File-level "use cache" in ${sourceId} only wraps exports that are statically-confirmed functions. ${plural ? "These exports are" : "This export is"} not: ${unconfirmedExports.map((n) => `"${n}"`).join(", ")}. Declare them directly (export async function foo() {} or export const foo = async () => {}). A factory or otherwise statically-indeterminate initializer (export const foo = makeCached(fn)) is rejected even if it returns a function at runtime -- rewrite it as a direct async function, or move non-function exports to a separate module.`
|
|
1772
1864
|
);
|
|
1773
1865
|
}
|
|
1774
1866
|
if (exportNames.length === 0) {
|
|
1775
|
-
const s = new
|
|
1867
|
+
const s = new MagicString4(code);
|
|
1776
1868
|
const directive2 = findFileLevelDirective(ast);
|
|
1777
1869
|
if (directive2) {
|
|
1778
1870
|
s.overwrite(
|
|
@@ -1807,7 +1899,7 @@ function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLa
|
|
|
1807
1899
|
function transformFunctionLevelUseCache(code, ast, filePath, sourceId, isBuild, transformHoistInlineDirective) {
|
|
1808
1900
|
try {
|
|
1809
1901
|
const { output, names } = transformHoistInlineDirective(code, ast, {
|
|
1810
|
-
directive:
|
|
1902
|
+
directive: USE_CACHE_DIRECTIVE_RE,
|
|
1811
1903
|
runtime: (value, name, meta) => {
|
|
1812
1904
|
const funcId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
|
|
1813
1905
|
const profileMatch = meta.directiveMatch[1];
|
|
@@ -1837,14 +1929,13 @@ function findFileLevelDirective(ast) {
|
|
|
1837
1929
|
}
|
|
1838
1930
|
return null;
|
|
1839
1931
|
}
|
|
1840
|
-
var VALID_DIRECTIVE_RE = /^use cache(:\s*[\w-]+)?$/;
|
|
1841
1932
|
var NEAR_MISS_RE = /^use cache:\s*.+$/;
|
|
1842
1933
|
function warnOnNearMissDirectives(ast, fileId, warn) {
|
|
1843
1934
|
const visit = (node) => {
|
|
1844
1935
|
if (!node || typeof node !== "object") return;
|
|
1845
1936
|
if (node.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
|
|
1846
1937
|
const value = node.expression.value;
|
|
1847
|
-
if (value.startsWith("use cache") && NEAR_MISS_RE.test(value) && !
|
|
1938
|
+
if (value.startsWith("use cache") && NEAR_MISS_RE.test(value) && !USE_CACHE_DIRECTIVE_RE.test(value)) {
|
|
1848
1939
|
const profilePart = value.slice("use cache:".length).trim();
|
|
1849
1940
|
warn(
|
|
1850
1941
|
`[rango:use-cache] "${value}" in ${fileId} has an invalid profile name "${profilePart}". Profile names must match [a-zA-Z0-9_-]+. This directive will be ignored.`
|
|
@@ -1907,7 +1998,6 @@ function clientRefDedup() {
|
|
|
1907
1998
|
if (this.environment?.name !== "client") return;
|
|
1908
1999
|
if (!importer?.includes(CLIENT_IN_SERVER_PROXY_PREFIX)) return;
|
|
1909
2000
|
if (!source.includes("/node_modules/")) return;
|
|
1910
|
-
if (!importer) return;
|
|
1911
2001
|
const packageName = extractPackageName(source);
|
|
1912
2002
|
if (!packageName) return;
|
|
1913
2003
|
if (clientExclude.includes(packageName)) return;
|
|
@@ -1938,7 +2028,7 @@ import {
|
|
|
1938
2028
|
import { createElement, StrictMode } from "react";
|
|
1939
2029
|
import { hydrateRoot } from "react-dom/client";
|
|
1940
2030
|
import { rscStream } from "@rangojs/router/internal/deps/html-stream-client";
|
|
1941
|
-
import { initBrowserApp,
|
|
2031
|
+
import { initBrowserApp, Rango } from "@rangojs/router/browser";
|
|
1942
2032
|
|
|
1943
2033
|
async function initializeApp() {
|
|
1944
2034
|
const deps = {
|
|
@@ -1953,7 +2043,7 @@ async function initializeApp() {
|
|
|
1953
2043
|
|
|
1954
2044
|
hydrateRoot(
|
|
1955
2045
|
document,
|
|
1956
|
-
createElement(StrictMode, null, createElement(
|
|
2046
|
+
createElement(StrictMode, null, createElement(Rango))
|
|
1957
2047
|
);
|
|
1958
2048
|
}
|
|
1959
2049
|
|
|
@@ -2022,6 +2112,38 @@ export default function handler(request, env) {
|
|
|
2022
2112
|
}
|
|
2023
2113
|
`.trim();
|
|
2024
2114
|
}
|
|
2115
|
+
function getVirtualEntryRSCHost(hostEntryPath) {
|
|
2116
|
+
return `
|
|
2117
|
+
import * as __hostEntry from "${hostEntryPath}";
|
|
2118
|
+
|
|
2119
|
+
// Register every sub-app's fetchable loaders + route manifests at startup, same
|
|
2120
|
+
// as the single-router entry. Discovery's host fallback populates these for all
|
|
2121
|
+
// mounted sub-apps, so the aggregate manifests cover the whole host tree.
|
|
2122
|
+
import "virtual:rsc-router/loader-manifest";
|
|
2123
|
+
import "virtual:rsc-router/routes-manifest";
|
|
2124
|
+
|
|
2125
|
+
// The host entry module must export the HostRouter instance (createHostRouter()),
|
|
2126
|
+
// as a default export or a named \`hostRouter\`/\`router\` export. A Cloudflare-style
|
|
2127
|
+
// \`export default { fetch }\` object is not a HostRouter and is rejected here.
|
|
2128
|
+
const __defaultExport = __hostEntry.default;
|
|
2129
|
+
const hostRouter =
|
|
2130
|
+
__defaultExport && typeof __defaultExport.match === "function"
|
|
2131
|
+
? __defaultExport
|
|
2132
|
+
: __hostEntry.hostRouter ?? __hostEntry.router;
|
|
2133
|
+
|
|
2134
|
+
if (!hostRouter || typeof hostRouter.match !== "function") {
|
|
2135
|
+
throw new Error(
|
|
2136
|
+
"[rango] The host entry (${hostEntryPath}) must export a HostRouter instance for the node/vercel preset: a default export, or a named 'hostRouter'/'router' export (e.g. export default createHostRouter()). A Cloudflare-style 'export default { fetch }' object is not supported on this preset."
|
|
2137
|
+
);
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
// input = { env, ctx } from the launcher / node server. The host router threads
|
|
2141
|
+
// it unchanged to each matched sub-app's handler and cache factory.
|
|
2142
|
+
export default function handler(request, input) {
|
|
2143
|
+
return hostRouter.match(request, input);
|
|
2144
|
+
}
|
|
2145
|
+
`.trim();
|
|
2146
|
+
}
|
|
2025
2147
|
var VIRTUAL_IDS = {
|
|
2026
2148
|
browser: "virtual:rsc-router/entry.browser.js",
|
|
2027
2149
|
ssr: "virtual:rsc-router/entry.ssr.js",
|
|
@@ -2040,7 +2162,7 @@ import { resolve } from "node:path";
|
|
|
2040
2162
|
// package.json
|
|
2041
2163
|
var package_default = {
|
|
2042
2164
|
name: "@rangojs/router",
|
|
2043
|
-
version: "0.0.0-experimental.
|
|
2165
|
+
version: "0.0.0-experimental.98914650",
|
|
2044
2166
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
2045
2167
|
keywords: [
|
|
2046
2168
|
"react",
|
|
@@ -2166,6 +2288,31 @@ var package_default = {
|
|
|
2166
2288
|
"./host/testing": {
|
|
2167
2289
|
types: "./src/host/testing.ts",
|
|
2168
2290
|
default: "./src/host/testing.ts"
|
|
2291
|
+
},
|
|
2292
|
+
"./testing": {
|
|
2293
|
+
types: "./src/testing/index.ts",
|
|
2294
|
+
default: "./src/testing/index.ts"
|
|
2295
|
+
},
|
|
2296
|
+
"./testing/vitest": {
|
|
2297
|
+
types: "./src/testing/vitest.ts",
|
|
2298
|
+
default: "./dist/testing/vitest.js"
|
|
2299
|
+
},
|
|
2300
|
+
"./testing/dom": {
|
|
2301
|
+
types: "./src/testing/dom.entry.ts",
|
|
2302
|
+
default: "./src/testing/dom.entry.ts"
|
|
2303
|
+
},
|
|
2304
|
+
"./testing/e2e": {
|
|
2305
|
+
types: "./src/testing/e2e/index.ts",
|
|
2306
|
+
default: "./src/testing/e2e/index.ts"
|
|
2307
|
+
},
|
|
2308
|
+
"./testing/flight": {
|
|
2309
|
+
types: "./src/testing/flight.entry.ts",
|
|
2310
|
+
"react-server": "./src/testing/flight.entry.ts",
|
|
2311
|
+
default: "./src/testing/flight.entry.ts"
|
|
2312
|
+
},
|
|
2313
|
+
"./testing/flight-matchers": {
|
|
2314
|
+
types: "./src/testing/flight-matchers.ts",
|
|
2315
|
+
default: "./src/testing/flight-matchers.ts"
|
|
2169
2316
|
}
|
|
2170
2317
|
},
|
|
2171
2318
|
publishConfig: {
|
|
@@ -2173,47 +2320,71 @@ var package_default = {
|
|
|
2173
2320
|
tag: "experimental"
|
|
2174
2321
|
},
|
|
2175
2322
|
scripts: {
|
|
2176
|
-
build: "pnpm dlx esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && mkdir -p dist/vite/plugins && cp src/vite/plugins/cloudflare-protocol-loader-hook.mjs dist/vite/plugins/cloudflare-protocol-loader-hook.mjs && pnpm dlx esbuild src/bin/rango.ts --bundle --format=esm --outfile=dist/bin/rango.js --platform=node --packages=external --banner:js='#!/usr/bin/env node' && chmod +x dist/bin/rango.js",
|
|
2323
|
+
build: "pnpm dlx esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && mkdir -p dist/vite/plugins && cp src/vite/plugins/cloudflare-protocol-loader-hook.mjs dist/vite/plugins/cloudflare-protocol-loader-hook.mjs && pnpm dlx esbuild src/testing/vitest.ts --bundle --format=esm --outfile=dist/testing/vitest.js --platform=node --packages=external && pnpm dlx esbuild src/bin/rango.ts --bundle --format=esm --outfile=dist/bin/rango.js --platform=node --packages=external --banner:js='#!/usr/bin/env node' && chmod +x dist/bin/rango.js",
|
|
2177
2324
|
prepublishOnly: "pnpm build",
|
|
2178
|
-
typecheck: "tsc --noEmit && tsc -p tsconfig.strict-check.json --noEmit",
|
|
2325
|
+
typecheck: "tsc --noEmit && tsc -p tsconfig.strict-check.json --noEmit && tsc -p tsconfig.augment-check.json --noEmit",
|
|
2179
2326
|
test: "playwright test",
|
|
2180
2327
|
"test:ui": "playwright test --ui",
|
|
2328
|
+
"test:hmr-local": "playwright test --project=dev-warmup --project=hmr-routes --project=hmr-basename --project=hmr-prerender --no-deps --workers=1",
|
|
2181
2329
|
"test:unit": "vitest run",
|
|
2182
|
-
"test:unit:watch": "vitest"
|
|
2330
|
+
"test:unit:watch": "vitest",
|
|
2331
|
+
"test:unit:rsc": "vitest run --config vitest.rsc.config.ts"
|
|
2183
2332
|
},
|
|
2184
2333
|
dependencies: {
|
|
2185
2334
|
"@types/debug": "^4.1.12",
|
|
2186
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
2335
|
+
"@vitejs/plugin-rsc": "^0.5.26",
|
|
2187
2336
|
debug: "^4.4.1",
|
|
2188
2337
|
"magic-string": "^0.30.17",
|
|
2189
2338
|
picomatch: "^4.0.3",
|
|
2190
|
-
"rsc-html-stream": "^0.0.7"
|
|
2339
|
+
"rsc-html-stream": "^0.0.7",
|
|
2340
|
+
srvx: "^0.11.15",
|
|
2341
|
+
tinyexec: "^0.3.2"
|
|
2191
2342
|
},
|
|
2192
2343
|
devDependencies: {
|
|
2193
2344
|
"@playwright/test": "^1.49.1",
|
|
2345
|
+
"@shared/e2e": "workspace:*",
|
|
2346
|
+
"@testing-library/dom": "^10.4.1",
|
|
2347
|
+
"@testing-library/react": "^16.3.2",
|
|
2194
2348
|
"@types/node": "^24.10.1",
|
|
2195
2349
|
"@types/react": "catalog:",
|
|
2196
2350
|
"@types/react-dom": "catalog:",
|
|
2197
2351
|
esbuild: "^0.27.0",
|
|
2352
|
+
"happy-dom": "^20.10.1",
|
|
2198
2353
|
jiti: "^2.6.1",
|
|
2199
2354
|
react: "catalog:",
|
|
2200
2355
|
"react-dom": "catalog:",
|
|
2201
|
-
tinyexec: "^0.3.2",
|
|
2202
2356
|
typescript: "^5.3.0",
|
|
2203
2357
|
vitest: "^4.0.0"
|
|
2204
2358
|
},
|
|
2205
2359
|
peerDependencies: {
|
|
2206
|
-
"@cloudflare/vite-plugin": "^1.
|
|
2207
|
-
"@
|
|
2208
|
-
react: "
|
|
2209
|
-
|
|
2360
|
+
"@cloudflare/vite-plugin": "^1.38.0",
|
|
2361
|
+
"@playwright/test": "^1.49.1",
|
|
2362
|
+
"@testing-library/react": ">=16",
|
|
2363
|
+
"@vercel/functions": "^3.0.0",
|
|
2364
|
+
"@vitejs/plugin-rsc": "^0.5.26",
|
|
2365
|
+
react: ">=19.2.6 <20",
|
|
2366
|
+
"react-dom": ">=19.2.6 <20",
|
|
2367
|
+
vite: "^8.0.0",
|
|
2368
|
+
vitest: ">=3"
|
|
2210
2369
|
},
|
|
2211
2370
|
peerDependenciesMeta: {
|
|
2212
2371
|
"@cloudflare/vite-plugin": {
|
|
2213
2372
|
optional: true
|
|
2214
2373
|
},
|
|
2374
|
+
"@playwright/test": {
|
|
2375
|
+
optional: true
|
|
2376
|
+
},
|
|
2377
|
+
"@testing-library/react": {
|
|
2378
|
+
optional: true
|
|
2379
|
+
},
|
|
2380
|
+
"@vercel/functions": {
|
|
2381
|
+
optional: true
|
|
2382
|
+
},
|
|
2215
2383
|
vite: {
|
|
2216
2384
|
optional: true
|
|
2385
|
+
},
|
|
2386
|
+
vitest: {
|
|
2387
|
+
optional: true
|
|
2217
2388
|
}
|
|
2218
2389
|
}
|
|
2219
2390
|
};
|
|
@@ -2288,10 +2459,10 @@ function extractParamsFromPattern(pattern) {
|
|
|
2288
2459
|
function formatRouteEntry(key, pattern, _params, search) {
|
|
2289
2460
|
const hasSearch = search && Object.keys(search).length > 0;
|
|
2290
2461
|
if (!hasSearch) {
|
|
2291
|
-
return ` ${key}:
|
|
2462
|
+
return ` ${key}: ${JSON.stringify(pattern)},`;
|
|
2292
2463
|
}
|
|
2293
|
-
const searchBody = Object.entries(search).map(([k, v]) => `${k}:
|
|
2294
|
-
return ` ${key}: { path:
|
|
2464
|
+
const searchBody = Object.entries(search).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join(", ");
|
|
2465
|
+
return ` ${key}: { path: ${JSON.stringify(pattern)}, search: { ${searchBody} } },`;
|
|
2295
2466
|
}
|
|
2296
2467
|
|
|
2297
2468
|
// src/build/route-types/ast-route-extraction.ts
|
|
@@ -2399,7 +2570,7 @@ ${objectBody}
|
|
|
2399
2570
|
} as const;
|
|
2400
2571
|
|
|
2401
2572
|
declare global {
|
|
2402
|
-
namespace
|
|
2573
|
+
namespace Rango {
|
|
2403
2574
|
interface GeneratedRouteMap extends Readonly<typeof NamedRoutes> {}
|
|
2404
2575
|
}
|
|
2405
2576
|
}
|
|
@@ -2407,7 +2578,31 @@ declare global {
|
|
|
2407
2578
|
}
|
|
2408
2579
|
|
|
2409
2580
|
// src/build/route-types/scan-filter.ts
|
|
2581
|
+
import { join, relative } from "node:path";
|
|
2410
2582
|
import picomatch from "picomatch";
|
|
2583
|
+
var DEFAULT_EXCLUDE_PATTERNS = [
|
|
2584
|
+
"**/__tests__/**",
|
|
2585
|
+
"**/__mocks__/**",
|
|
2586
|
+
"**/dist/**",
|
|
2587
|
+
"**/coverage/**",
|
|
2588
|
+
"**/*.test.{ts,tsx,js,jsx}",
|
|
2589
|
+
"**/*.spec.{ts,tsx,js,jsx}"
|
|
2590
|
+
];
|
|
2591
|
+
function createScanFilter(root, opts) {
|
|
2592
|
+
const { include, exclude } = opts;
|
|
2593
|
+
const hasInclude = include && include.length > 0;
|
|
2594
|
+
const hasCustomExclude = exclude !== void 0;
|
|
2595
|
+
if (!hasInclude && !hasCustomExclude) return void 0;
|
|
2596
|
+
const effectiveExclude = exclude ?? DEFAULT_EXCLUDE_PATTERNS;
|
|
2597
|
+
const includeMatcher = hasInclude ? picomatch(include) : null;
|
|
2598
|
+
const excludeMatcher = effectiveExclude.length > 0 ? picomatch(effectiveExclude) : null;
|
|
2599
|
+
return (absolutePath) => {
|
|
2600
|
+
const rel = relative(root, absolutePath);
|
|
2601
|
+
if (excludeMatcher && excludeMatcher(rel)) return false;
|
|
2602
|
+
if (includeMatcher) return includeMatcher(rel);
|
|
2603
|
+
return true;
|
|
2604
|
+
};
|
|
2605
|
+
}
|
|
2411
2606
|
|
|
2412
2607
|
// src/build/route-types/per-module-writer.ts
|
|
2413
2608
|
import ts4 from "typescript";
|
|
@@ -2634,7 +2829,7 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
|
|
|
2634
2829
|
const realPath = resolve2(filePath);
|
|
2635
2830
|
const key = variableName ? `${realPath}:${variableName}` : realPath;
|
|
2636
2831
|
if (visited.has(key)) {
|
|
2637
|
-
console.warn(`[
|
|
2832
|
+
console.warn(`[rango] Circular include detected, skipping: ${key}`);
|
|
2638
2833
|
return { routes: {}, searchSchemas: {} };
|
|
2639
2834
|
}
|
|
2640
2835
|
visited.add(key);
|
|
@@ -2676,7 +2871,7 @@ import {
|
|
|
2676
2871
|
readdirSync
|
|
2677
2872
|
} from "node:fs";
|
|
2678
2873
|
import {
|
|
2679
|
-
join,
|
|
2874
|
+
join as join2,
|
|
2680
2875
|
dirname as dirname2,
|
|
2681
2876
|
resolve as resolve3,
|
|
2682
2877
|
sep,
|
|
@@ -2695,6 +2890,7 @@ function countPublicRouteEntries(source) {
|
|
|
2695
2890
|
return count;
|
|
2696
2891
|
}
|
|
2697
2892
|
var ROUTER_CALL_PATTERN = /\bcreateRouter\s*[<(]/;
|
|
2893
|
+
var ROUTER_CALL_PATTERN_G = /\bcreateRouter\s*[<(]/g;
|
|
2698
2894
|
function isRoutableSourceFile(name) {
|
|
2699
2895
|
return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
|
|
2700
2896
|
}
|
|
@@ -2704,14 +2900,14 @@ function findRouterFilesRecursive(dir, filter, results) {
|
|
|
2704
2900
|
entries = readdirSync(dir, { withFileTypes: true });
|
|
2705
2901
|
} catch (err) {
|
|
2706
2902
|
console.warn(
|
|
2707
|
-
`[
|
|
2903
|
+
`[rango] Failed to scan directory ${dir}: ${err.message}`
|
|
2708
2904
|
);
|
|
2709
2905
|
return;
|
|
2710
2906
|
}
|
|
2711
2907
|
const childDirs = [];
|
|
2712
2908
|
const routerFilesInDir = [];
|
|
2713
2909
|
for (const entry of entries) {
|
|
2714
|
-
const fullPath =
|
|
2910
|
+
const fullPath = join2(dir, entry.name);
|
|
2715
2911
|
if (entry.isDirectory()) {
|
|
2716
2912
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "coverage" || entry.name === "__tests__" || entry.name === "__mocks__" || entry.name.startsWith("."))
|
|
2717
2913
|
continue;
|
|
@@ -2722,7 +2918,7 @@ function findRouterFilesRecursive(dir, filter, results) {
|
|
|
2722
2918
|
if (filter && !filter(fullPath)) continue;
|
|
2723
2919
|
try {
|
|
2724
2920
|
const source = readFileSync2(fullPath, "utf-8");
|
|
2725
|
-
if (ROUTER_CALL_PATTERN.test(source)) {
|
|
2921
|
+
if (ROUTER_CALL_PATTERN.test(source) && firstCodeMatchIndex(source, ROUTER_CALL_PATTERN_G) >= 0) {
|
|
2726
2922
|
routerFilesInDir.push(fullPath);
|
|
2727
2923
|
}
|
|
2728
2924
|
} catch {
|
|
@@ -2760,7 +2956,7 @@ function findNestedRouterConflict(routerFiles) {
|
|
|
2760
2956
|
}
|
|
2761
2957
|
return null;
|
|
2762
2958
|
}
|
|
2763
|
-
function formatNestedRouterConflictError(conflict, prefix = "[
|
|
2959
|
+
function formatNestedRouterConflictError(conflict, prefix = "[rango]") {
|
|
2764
2960
|
return `${prefix} Nested router roots are not supported.
|
|
2765
2961
|
Router root: ${conflict.ancestor}
|
|
2766
2962
|
Nested router: ${conflict.nested}
|
|
@@ -2856,19 +3052,38 @@ function extractBasenameFromRouter(code) {
|
|
|
2856
3052
|
visit(sourceFile);
|
|
2857
3053
|
return result;
|
|
2858
3054
|
}
|
|
2859
|
-
function applyBasenameToRoutes(result,
|
|
3055
|
+
function applyBasenameToRoutes(result, basename2) {
|
|
2860
3056
|
const prefixed = {};
|
|
2861
3057
|
for (const [name, pattern] of Object.entries(result.routes)) {
|
|
2862
3058
|
if (pattern === "/") {
|
|
2863
|
-
prefixed[name] =
|
|
2864
|
-
} else if (
|
|
2865
|
-
prefixed[name] =
|
|
3059
|
+
prefixed[name] = basename2;
|
|
3060
|
+
} else if (basename2.endsWith("/") && pattern.startsWith("/")) {
|
|
3061
|
+
prefixed[name] = basename2 + pattern.slice(1);
|
|
2866
3062
|
} else {
|
|
2867
|
-
prefixed[name] =
|
|
3063
|
+
prefixed[name] = basename2 + pattern;
|
|
2868
3064
|
}
|
|
2869
3065
|
}
|
|
2870
3066
|
return { routes: prefixed, searchSchemas: result.searchSchemas };
|
|
2871
3067
|
}
|
|
3068
|
+
function genFileTsPath(sourceFile) {
|
|
3069
|
+
const base = pathBasename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
3070
|
+
return join2(dirname2(sourceFile), `${base}.named-routes.gen.ts`);
|
|
3071
|
+
}
|
|
3072
|
+
function resolveSearchSchemas(publicRouteNames, runtimeSchemas, sourceFile) {
|
|
3073
|
+
if (runtimeSchemas && Object.keys(runtimeSchemas).length > 0) {
|
|
3074
|
+
return runtimeSchemas;
|
|
3075
|
+
}
|
|
3076
|
+
const staticParsed = buildCombinedRouteMapForRouterFile(sourceFile);
|
|
3077
|
+
if (Object.keys(staticParsed.searchSchemas).length === 0) {
|
|
3078
|
+
return runtimeSchemas;
|
|
3079
|
+
}
|
|
3080
|
+
const filtered = {};
|
|
3081
|
+
for (const name of publicRouteNames) {
|
|
3082
|
+
const schema = staticParsed.searchSchemas[name];
|
|
3083
|
+
if (schema) filtered[name] = schema;
|
|
3084
|
+
}
|
|
3085
|
+
return Object.keys(filtered).length > 0 ? filtered : runtimeSchemas;
|
|
3086
|
+
}
|
|
2872
3087
|
function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
2873
3088
|
let routerSource;
|
|
2874
3089
|
try {
|
|
@@ -2881,7 +3096,7 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
|
2881
3096
|
return { routes: {}, searchSchemas: {} };
|
|
2882
3097
|
}
|
|
2883
3098
|
const rawBasename = extractBasenameFromRouter(routerSource);
|
|
2884
|
-
const
|
|
3099
|
+
const basename2 = rawBasename ? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "") : void 0;
|
|
2885
3100
|
let result;
|
|
2886
3101
|
if (extraction.kind === "inline") {
|
|
2887
3102
|
result = buildCombinedRouteMapWithSearch(
|
|
@@ -2906,8 +3121,8 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
|
2906
3121
|
result = buildCombinedRouteMapWithSearch(routerFilePath, extraction.name);
|
|
2907
3122
|
}
|
|
2908
3123
|
}
|
|
2909
|
-
if (
|
|
2910
|
-
result = applyBasenameToRoutes(result,
|
|
3124
|
+
if (basename2) {
|
|
3125
|
+
result = applyBasenameToRoutes(result, basename2);
|
|
2911
3126
|
}
|
|
2912
3127
|
return result;
|
|
2913
3128
|
}
|
|
@@ -2916,13 +3131,50 @@ function findRouterFiles(root, filter) {
|
|
|
2916
3131
|
findRouterFilesRecursive(root, filter, result);
|
|
2917
3132
|
return result;
|
|
2918
3133
|
}
|
|
3134
|
+
var HOST_ROUTER_CALL_PATTERN = /\bcreateHostRouter\s*[<(]/;
|
|
3135
|
+
var HOST_ROUTER_CALL_PATTERN_G = /\bcreateHostRouter\s*[<(]/g;
|
|
3136
|
+
function findHostRouterFilesRecursive(dir, filter, results) {
|
|
3137
|
+
let entries;
|
|
3138
|
+
try {
|
|
3139
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
3140
|
+
} catch (err) {
|
|
3141
|
+
console.warn(
|
|
3142
|
+
`[rango] Failed to scan directory ${dir}: ${err.message}`
|
|
3143
|
+
);
|
|
3144
|
+
return;
|
|
3145
|
+
}
|
|
3146
|
+
for (const entry of entries) {
|
|
3147
|
+
const fullPath = join2(dir, entry.name);
|
|
3148
|
+
if (entry.isDirectory()) {
|
|
3149
|
+
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "coverage" || entry.name === "__tests__" || entry.name === "__mocks__" || entry.name.startsWith("."))
|
|
3150
|
+
continue;
|
|
3151
|
+
findHostRouterFilesRecursive(fullPath, filter, results);
|
|
3152
|
+
continue;
|
|
3153
|
+
}
|
|
3154
|
+
if (!isRoutableSourceFile(entry.name)) continue;
|
|
3155
|
+
if (filter && !filter(fullPath)) continue;
|
|
3156
|
+
try {
|
|
3157
|
+
const source = readFileSync2(fullPath, "utf-8");
|
|
3158
|
+
if (HOST_ROUTER_CALL_PATTERN.test(source) && firstCodeMatchIndex(source, HOST_ROUTER_CALL_PATTERN_G) >= 0) {
|
|
3159
|
+
results.push(fullPath);
|
|
3160
|
+
}
|
|
3161
|
+
} catch {
|
|
3162
|
+
continue;
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
function findHostRouterFiles(root, filter) {
|
|
3167
|
+
const result = [];
|
|
3168
|
+
findHostRouterFilesRecursive(root, filter, result);
|
|
3169
|
+
return result;
|
|
3170
|
+
}
|
|
2919
3171
|
function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
2920
3172
|
try {
|
|
2921
|
-
const oldCombinedPath =
|
|
3173
|
+
const oldCombinedPath = join2(root, "src", "named-routes.gen.ts");
|
|
2922
3174
|
if (existsSync3(oldCombinedPath)) {
|
|
2923
3175
|
unlinkSync(oldCombinedPath);
|
|
2924
3176
|
console.log(
|
|
2925
|
-
`[
|
|
3177
|
+
`[rango] Removed stale combined route types: ${oldCombinedPath}`
|
|
2926
3178
|
);
|
|
2927
3179
|
}
|
|
2928
3180
|
} catch {
|
|
@@ -2944,18 +3196,12 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
|
2944
3196
|
}
|
|
2945
3197
|
if (!extractUrlsFromRouter(routerSource)) continue;
|
|
2946
3198
|
}
|
|
2947
|
-
const
|
|
2948
|
-
/\.(tsx?|jsx?)$/,
|
|
2949
|
-
""
|
|
2950
|
-
);
|
|
2951
|
-
const outPath = join(
|
|
2952
|
-
dirname2(routerFilePath),
|
|
2953
|
-
`${routerBasename}.named-routes.gen.ts`
|
|
2954
|
-
);
|
|
3199
|
+
const outPath = genFileTsPath(routerFilePath);
|
|
2955
3200
|
const existing = existsSync3(outPath) ? readFileSync2(outPath, "utf-8") : null;
|
|
2956
3201
|
if (Object.keys(result.routes).length === 0) {
|
|
2957
3202
|
if (!existing) {
|
|
2958
3203
|
const emptySource = generateRouteTypesSource({});
|
|
3204
|
+
opts?.onWrite?.(outPath, emptySource);
|
|
2959
3205
|
writeFileSync(outPath, emptySource);
|
|
2960
3206
|
}
|
|
2961
3207
|
continue;
|
|
@@ -2975,9 +3221,10 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
|
2975
3221
|
continue;
|
|
2976
3222
|
}
|
|
2977
3223
|
}
|
|
3224
|
+
opts?.onWrite?.(outPath, source);
|
|
2978
3225
|
writeFileSync(outPath, source);
|
|
2979
3226
|
console.log(
|
|
2980
|
-
`[
|
|
3227
|
+
`[rango] Generated route types (${Object.keys(result.routes).length} routes) -> ${outPath}`
|
|
2981
3228
|
);
|
|
2982
3229
|
}
|
|
2983
3230
|
}
|
|
@@ -2994,7 +3241,7 @@ function normalizeModuleId(id) {
|
|
|
2994
3241
|
function getClientModuleSignature(source) {
|
|
2995
3242
|
let program;
|
|
2996
3243
|
try {
|
|
2997
|
-
program = parseAst3(source, {
|
|
3244
|
+
program = parseAst3(source, { lang: "tsx" });
|
|
2998
3245
|
} catch {
|
|
2999
3246
|
return void 0;
|
|
3000
3247
|
}
|
|
@@ -3077,11 +3324,12 @@ function createVersionPlugin() {
|
|
|
3077
3324
|
let currentVersion = buildVersion;
|
|
3078
3325
|
let isDev = false;
|
|
3079
3326
|
let server = null;
|
|
3327
|
+
let resolvedCacheDir;
|
|
3080
3328
|
const clientModuleSignatures = /* @__PURE__ */ new Map();
|
|
3081
3329
|
let versionCounter = 0;
|
|
3082
3330
|
const bumpVersion = (reason) => {
|
|
3083
3331
|
currentVersion = Date.now().toString(16) + String(++versionCounter);
|
|
3084
|
-
console.log(`[
|
|
3332
|
+
console.log(`[rango] ${reason}, version updated: ${currentVersion}`);
|
|
3085
3333
|
const rscEnv = server?.environments?.rsc;
|
|
3086
3334
|
const versionMod = rscEnv?.moduleGraph?.getModuleById(
|
|
3087
3335
|
"\0" + VIRTUAL_IDS.version
|
|
@@ -3095,6 +3343,7 @@ function createVersionPlugin() {
|
|
|
3095
3343
|
enforce: "pre",
|
|
3096
3344
|
configResolved(config) {
|
|
3097
3345
|
isDev = config.command === "serve";
|
|
3346
|
+
resolvedCacheDir = config.cacheDir ? String(config.cacheDir).replace(/\\/g, "/") : void 0;
|
|
3098
3347
|
},
|
|
3099
3348
|
configureServer(devServer) {
|
|
3100
3349
|
server = devServer;
|
|
@@ -3131,11 +3380,11 @@ function createVersionPlugin() {
|
|
|
3131
3380
|
}
|
|
3132
3381
|
return null;
|
|
3133
3382
|
},
|
|
3134
|
-
// Track RSC module changes and update version
|
|
3135
3383
|
async hotUpdate(ctx) {
|
|
3136
3384
|
if (!isDev) return;
|
|
3137
3385
|
const isRscModule = this.environment?.name === "rsc";
|
|
3138
3386
|
if (!isRscModule) return;
|
|
3387
|
+
if (isViteDepCachePath(ctx.file, resolvedCacheDir)) return;
|
|
3139
3388
|
if (ctx.modules.length === 1 && ctx.modules[0].id === "\0" + VIRTUAL_IDS.version) {
|
|
3140
3389
|
return;
|
|
3141
3390
|
}
|
|
@@ -3165,6 +3414,17 @@ function createVersionPlugin() {
|
|
|
3165
3414
|
}
|
|
3166
3415
|
};
|
|
3167
3416
|
}
|
|
3417
|
+
function isViteDepCachePath(filePath, cacheDir) {
|
|
3418
|
+
if (!filePath) return false;
|
|
3419
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
3420
|
+
if (cacheDir) {
|
|
3421
|
+
const normalizedCacheDir = cacheDir.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
3422
|
+
if (normalized === normalizedCacheDir || normalized.startsWith(normalizedCacheDir + "/")) {
|
|
3423
|
+
return true;
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3426
|
+
return /\/node_modules\/\.vite[^/]*\//.test(normalized) || normalized.includes("/.vite-isolated/");
|
|
3427
|
+
}
|
|
3168
3428
|
|
|
3169
3429
|
// src/vite/utils/shared-utils.ts
|
|
3170
3430
|
import * as Vite from "vite";
|
|
@@ -3193,22 +3453,15 @@ function patchRsdwClientDebugInfoRecovery(code) {
|
|
|
3193
3453
|
};
|
|
3194
3454
|
}
|
|
3195
3455
|
function performanceTracksOptimizeDepsPlugin() {
|
|
3456
|
+
const RSDW_CLIENT_RE = /react-server-dom-webpack-client\.browser\.(development|production)\.js$/;
|
|
3196
3457
|
return {
|
|
3197
3458
|
name: "@rangojs/router:performance-tracks-optimize-deps",
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
const code = await readFile(args.path, "utf8");
|
|
3205
|
-
const patched = patchRsdwClientDebugInfoRecovery(code);
|
|
3206
|
-
return {
|
|
3207
|
-
contents: patched.code,
|
|
3208
|
-
loader: "js"
|
|
3209
|
-
};
|
|
3210
|
-
}
|
|
3211
|
-
);
|
|
3459
|
+
async load(id) {
|
|
3460
|
+
const cleanId = id.split("?")[0] ?? id;
|
|
3461
|
+
if (!RSDW_CLIENT_RE.test(cleanId)) return null;
|
|
3462
|
+
const code = await readFile(cleanId, "utf8");
|
|
3463
|
+
const patched = patchRsdwClientDebugInfoRecovery(code);
|
|
3464
|
+
return { code: patched.code };
|
|
3212
3465
|
}
|
|
3213
3466
|
};
|
|
3214
3467
|
}
|
|
@@ -3235,24 +3488,27 @@ function performanceTracksPlugin() {
|
|
|
3235
3488
|
}
|
|
3236
3489
|
|
|
3237
3490
|
// src/vite/utils/shared-utils.ts
|
|
3238
|
-
|
|
3491
|
+
function resolveRscEntryFromConfig(config) {
|
|
3492
|
+
const entries = config.environments?.["rsc"]?.optimizeDeps?.entries;
|
|
3493
|
+
if (typeof entries === "string") return entries;
|
|
3494
|
+
if (Array.isArray(entries) && entries.length > 0) return entries[0];
|
|
3495
|
+
return void 0;
|
|
3496
|
+
}
|
|
3497
|
+
var versionRolldownPlugin = {
|
|
3239
3498
|
name: "@rangojs/router-version",
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
loader: "js"
|
|
3250
|
-
})
|
|
3251
|
-
);
|
|
3499
|
+
resolveId(id) {
|
|
3500
|
+
if (id === VIRTUAL_IDS.version) return "\0" + VIRTUAL_IDS.version;
|
|
3501
|
+
return void 0;
|
|
3502
|
+
},
|
|
3503
|
+
load(id) {
|
|
3504
|
+
if (id === "\0" + VIRTUAL_IDS.version) {
|
|
3505
|
+
return getVirtualVersionContent("dev");
|
|
3506
|
+
}
|
|
3507
|
+
return void 0;
|
|
3252
3508
|
}
|
|
3253
3509
|
};
|
|
3254
|
-
var
|
|
3255
|
-
plugins: [
|
|
3510
|
+
var sharedRolldownOptions = {
|
|
3511
|
+
plugins: [versionRolldownPlugin, performanceTracksOptimizeDepsPlugin()]
|
|
3256
3512
|
};
|
|
3257
3513
|
function createVirtualEntriesPlugin(entries, routerPathRef) {
|
|
3258
3514
|
const virtualModules = {};
|
|
@@ -3287,15 +3543,36 @@ function createVirtualEntriesPlugin(entries, routerPathRef) {
|
|
|
3287
3543
|
if (virtualId === VIRTUAL_IDS.rsc && routerPathRef?.path) {
|
|
3288
3544
|
const raw = routerPathRef.path.startsWith(".") ? "/" + routerPathRef.path.slice(2) : routerPathRef.path;
|
|
3289
3545
|
const absoluteRouterPath = raw.replaceAll("\\", "/");
|
|
3290
|
-
return getVirtualEntryRSC(absoluteRouterPath);
|
|
3546
|
+
return routerPathRef.kind === "host" ? getVirtualEntryRSCHost(absoluteRouterPath) : getVirtualEntryRSC(absoluteRouterPath);
|
|
3291
3547
|
}
|
|
3292
3548
|
}
|
|
3293
3549
|
return null;
|
|
3294
3550
|
}
|
|
3295
3551
|
};
|
|
3296
3552
|
}
|
|
3553
|
+
function isContentHashedAssetConflict(message) {
|
|
3554
|
+
if (!message) return false;
|
|
3555
|
+
const match = /The emitted file "?([^"\s]+)"? overwrites a previously emitted file/.exec(
|
|
3556
|
+
message
|
|
3557
|
+
);
|
|
3558
|
+
if (!match) return false;
|
|
3559
|
+
const fileName = match[1];
|
|
3560
|
+
const base = fileName.slice(fileName.lastIndexOf("/") + 1);
|
|
3561
|
+
const dot = base.lastIndexOf(".");
|
|
3562
|
+
if (dot <= 0) return false;
|
|
3563
|
+
const stem = base.slice(0, dot);
|
|
3564
|
+
const HASH_LEN = 8;
|
|
3565
|
+
if (stem.length < HASH_LEN + 1 || stem[stem.length - HASH_LEN - 1] !== "-") {
|
|
3566
|
+
return false;
|
|
3567
|
+
}
|
|
3568
|
+
const hash = stem.slice(-HASH_LEN);
|
|
3569
|
+
return /^[A-Za-z0-9_-]+$/.test(hash) && /[A-Z0-9]/.test(hash);
|
|
3570
|
+
}
|
|
3297
3571
|
function onwarn(warning, defaultHandler) {
|
|
3298
|
-
if (warning.code === "MODULE_LEVEL_DIRECTIVE" || warning.code === "SOURCEMAP_ERROR" || warning.code === "EMPTY_BUNDLE") {
|
|
3572
|
+
if (warning.code === "MODULE_LEVEL_DIRECTIVE" || warning.code === "SOURCEMAP_ERROR" || warning.code === "EMPTY_BUNDLE" || warning.code === "INEFFECTIVE_DYNAMIC_IMPORT") {
|
|
3573
|
+
return;
|
|
3574
|
+
}
|
|
3575
|
+
if (warning.code === "FILE_NAME_CONFLICT" && isContentHashedAssetConflict(warning.message)) {
|
|
3299
3576
|
return;
|
|
3300
3577
|
}
|
|
3301
3578
|
if (warning.message?.includes("Sourcemap is likely to be incorrect")) {
|
|
@@ -3314,73 +3591,354 @@ function getManualChunks(id) {
|
|
|
3314
3591
|
return "react";
|
|
3315
3592
|
}
|
|
3316
3593
|
const packageName = getPublishedPackageName();
|
|
3317
|
-
if (normalized.includes(`node_modules/${packageName}/`) ||
|
|
3594
|
+
if (normalized.includes(`node_modules/${packageName}/`) || /\/packages\/(rsc-router|rangojs-router)\/(src|dist)\//.test(normalized)) {
|
|
3318
3595
|
return "router";
|
|
3319
3596
|
}
|
|
3320
3597
|
return void 0;
|
|
3321
3598
|
}
|
|
3322
3599
|
|
|
3323
|
-
// src/vite/
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
const banner = `
|
|
3333
|
-
${dim} \u2726 \u2726 \u2727. . .${reset}
|
|
3334
|
-
${dim} \u2571${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2571 \u2726 *${reset}
|
|
3335
|
-
${dim} ${reset}${bold}\u2551 \u2551${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2727. \u2571${reset}
|
|
3336
|
-
${dim} ${reset}${bold}\u2554\u2557 \u2551 \u2551 \u2551 \u2551${reset}${dim} * \u2571${reset}
|
|
3337
|
-
${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2551 \u2551 \u2551 \u2566\u2550\u2557\u2554\u2550\u2557\u2554\u2557\u2554\u2554\u2550\u2557\u2554\u2550\u2557${reset}${dim} \u2727 \u2726${reset}
|
|
3338
|
-
${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2560\u2550\u255D \u2551 \u2560\u2566\u255D\u2560\u2550\u2563\u2551\u2551\u2551\u2551 \u2566\u2551 \u2551${reset}${dim} * \u2727${reset}
|
|
3339
|
-
${dim} ${reset}${bold}\u2551\u255A\u2550\u255D \u2554\u2550\u2550\u2550\u255D \u2569\u255A\u2550\u2569 \u2569\u255D\u255A\u255D\u255A\u2550\u255D\u255A\u2550\u255D${reset}${dim} \u2726 . *${reset}
|
|
3340
|
-
${dim} ${reset}${bold}\u255A\u2550\u2550\u2557 \u2551${reset}${dim} * RSC Wrangler \u2727 \u2726${reset}
|
|
3341
|
-
${dim} * ${reset}${bold}\u2551 \u2551${reset}${dim} * \u2727. \u2571${reset}
|
|
3342
|
-
${dim} ${reset}${bold}\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550${reset}${dim} \u2726 *${reset}
|
|
3343
|
-
|
|
3344
|
-
v${version} \xB7 ${preset} \xB7 ${mode}
|
|
3345
|
-
`;
|
|
3346
|
-
console.log(banner);
|
|
3600
|
+
// src/vite/plugins/client-ref-hashing.ts
|
|
3601
|
+
import { relative as relative2 } from "node:path";
|
|
3602
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
3603
|
+
var debug7 = createRangoDebugger(NS.transform);
|
|
3604
|
+
var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
|
|
3605
|
+
var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
|
|
3606
|
+
var FS_PREFIX = "/@fs/";
|
|
3607
|
+
function hashRefKey(relativeId) {
|
|
3608
|
+
return createHash2("sha256").update(relativeId).digest("hex").slice(0, 12);
|
|
3347
3609
|
}
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3610
|
+
function computeProductionHash(projectRoot, refKey) {
|
|
3611
|
+
let toHash;
|
|
3612
|
+
if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
|
|
3613
|
+
toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
|
|
3614
|
+
} else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
|
|
3615
|
+
const absPath = decodeURIComponent(
|
|
3616
|
+
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
|
|
3617
|
+
);
|
|
3618
|
+
toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
|
|
3619
|
+
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
3620
|
+
const absPath = refKey.slice(FS_PREFIX.length - 1);
|
|
3621
|
+
toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
|
|
3622
|
+
} else if (refKey.startsWith("/")) {
|
|
3623
|
+
toHash = refKey.slice(1);
|
|
3624
|
+
} else {
|
|
3625
|
+
return refKey;
|
|
3626
|
+
}
|
|
3627
|
+
return hashRefKey(toHash);
|
|
3628
|
+
}
|
|
3629
|
+
var REGISTER_CLIENT_REF_RE = /registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
|
|
3630
|
+
function transformClientRefs(code, projectRoot) {
|
|
3631
|
+
if (!code.includes("registerClientReference")) return null;
|
|
3632
|
+
let hasReplacement = false;
|
|
3633
|
+
const result = code.replace(
|
|
3634
|
+
REGISTER_CLIENT_REF_RE,
|
|
3635
|
+
(match, refKey) => {
|
|
3636
|
+
const hash = computeProductionHash(projectRoot, refKey);
|
|
3637
|
+
if (hash === refKey) return match;
|
|
3638
|
+
hasReplacement = true;
|
|
3639
|
+
return match.replace(`"${refKey}"`, `"${hash}"`);
|
|
3640
|
+
}
|
|
3641
|
+
);
|
|
3642
|
+
return hasReplacement ? result : null;
|
|
3643
|
+
}
|
|
3644
|
+
function hashClientRefs(projectRoot) {
|
|
3645
|
+
const counter = createCounter(debug7, "hash-client-refs");
|
|
3354
3646
|
return {
|
|
3355
|
-
name: "@rangojs/router:
|
|
3356
|
-
enforce: "
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
if (typeof entries === "string") {
|
|
3363
|
-
entryPath = entries;
|
|
3364
|
-
} else if (Array.isArray(entries) && entries.length > 0) {
|
|
3365
|
-
entryPath = entries[0];
|
|
3366
|
-
}
|
|
3367
|
-
}
|
|
3368
|
-
if (entryPath) {
|
|
3369
|
-
resolvedEntryPath = resolve4(config.root, entryPath);
|
|
3370
|
-
}
|
|
3647
|
+
name: "@rangojs/router:hash-client-refs",
|
|
3648
|
+
enforce: "post",
|
|
3649
|
+
applyToEnvironment(env) {
|
|
3650
|
+
return env.name === "rsc";
|
|
3651
|
+
},
|
|
3652
|
+
buildEnd() {
|
|
3653
|
+
counter?.flush();
|
|
3371
3654
|
},
|
|
3372
3655
|
transform(code, id) {
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
return null;
|
|
3378
|
-
}
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3656
|
+
const start = counter ? performance.now() : 0;
|
|
3657
|
+
try {
|
|
3658
|
+
const result = transformClientRefs(code, projectRoot);
|
|
3659
|
+
if (result === null) return;
|
|
3660
|
+
return { code: result, map: null };
|
|
3661
|
+
} finally {
|
|
3662
|
+
counter?.record(id, performance.now() - start);
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
};
|
|
3666
|
+
}
|
|
3667
|
+
|
|
3668
|
+
// src/vite/utils/client-chunks.ts
|
|
3669
|
+
var debugChunks = createRangoDebugger(NS.chunks);
|
|
3670
|
+
function isSharedRuntime(meta) {
|
|
3671
|
+
return [meta.id, meta.normalizedId].some(
|
|
3672
|
+
(path6) => path6.includes("/node_modules/") || /\/@rangojs\/router\//.test(path6) || /\/packages\/(rangojs-router|rsc-router)\/(src|dist)\//.test(path6)
|
|
3673
|
+
);
|
|
3674
|
+
}
|
|
3675
|
+
function sanitizeGroup(name) {
|
|
3676
|
+
return name.replace(/[^a-zA-Z0-9_-]+/g, "_").replace(/^_+|_+$/g, "") || "app";
|
|
3677
|
+
}
|
|
3678
|
+
var ROUTE_ROOT_DIRS = /* @__PURE__ */ new Set([
|
|
3679
|
+
"routes",
|
|
3680
|
+
"route",
|
|
3681
|
+
"pages",
|
|
3682
|
+
"page",
|
|
3683
|
+
"app",
|
|
3684
|
+
"features",
|
|
3685
|
+
"feature",
|
|
3686
|
+
"views",
|
|
3687
|
+
"view",
|
|
3688
|
+
"handlers",
|
|
3689
|
+
"urls",
|
|
3690
|
+
"modules",
|
|
3691
|
+
"screens",
|
|
3692
|
+
"sections"
|
|
3693
|
+
]);
|
|
3694
|
+
function directoryClientChunks(meta, ctx) {
|
|
3695
|
+
if (isSharedRuntime(meta)) {
|
|
3696
|
+
return void 0;
|
|
3697
|
+
}
|
|
3698
|
+
if (ctx?.fallbackRefs.size && ctx.fallbackRefs.has(hashRefKey(meta.normalizedId))) {
|
|
3699
|
+
debugChunks?.("fallback %s -> app-fallback", meta.normalizedId);
|
|
3700
|
+
return "app-fallback";
|
|
3701
|
+
}
|
|
3702
|
+
const segments = meta.normalizedId.split("/").filter(Boolean);
|
|
3703
|
+
const dirCount = segments.length - 1;
|
|
3704
|
+
if (dirCount >= 1) {
|
|
3705
|
+
for (let i = 0; i < dirCount - 1; i++) {
|
|
3706
|
+
if (ROUTE_ROOT_DIRS.has(segments[i].toLowerCase())) {
|
|
3707
|
+
const group = `app-${sanitizeGroup(segments[i + 1])}`;
|
|
3708
|
+
debugChunks?.("split %s -> %s", meta.normalizedId, group);
|
|
3709
|
+
return group;
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
debugChunks?.(
|
|
3714
|
+
"shared %s (no route-root marker; inherits default grouping)",
|
|
3715
|
+
meta.normalizedId
|
|
3716
|
+
);
|
|
3717
|
+
return void 0;
|
|
3718
|
+
}
|
|
3719
|
+
function resolveClientChunks(option, ctx) {
|
|
3720
|
+
if (!option) return void 0;
|
|
3721
|
+
if (option === true) return (meta) => directoryClientChunks(meta, ctx);
|
|
3722
|
+
return option;
|
|
3723
|
+
}
|
|
3724
|
+
|
|
3725
|
+
// src/vite/plugins/vercel-output.ts
|
|
3726
|
+
import { rm, mkdir, cp, writeFile } from "node:fs/promises";
|
|
3727
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
3728
|
+
import { resolve as resolve4, join as join3 } from "node:path";
|
|
3729
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
3730
|
+
import { pathToFileURL } from "node:url";
|
|
3731
|
+
var LAUNCHER_SOURCE = `import { toNodeHandler } from "srvx/node";
|
|
3732
|
+
import { waitUntil } from "@vercel/functions";
|
|
3733
|
+
import rscHandler from "./rsc/index.js";
|
|
3734
|
+
|
|
3735
|
+
// The Vercel Node launcher invokes a Node (req, res) handler, not a Web fetch
|
|
3736
|
+
// handler. srvx's toNodeHandler bridges the Rango Web fetch handler and pipes
|
|
3737
|
+
// the streamed Response to the Node response (set supportsResponseStreaming).
|
|
3738
|
+
const onVercel = Boolean(process.env.VERCEL);
|
|
3739
|
+
|
|
3740
|
+
const fetchHandler = (request) =>
|
|
3741
|
+
rscHandler(request, {
|
|
3742
|
+
env: process.env,
|
|
3743
|
+
// Forward Vercel's waitUntil so cache writes / revalidation run off the
|
|
3744
|
+
// response path. Omitted off-platform so those writes settle inline.
|
|
3745
|
+
ctx: onVercel ? { waitUntil } : undefined,
|
|
3746
|
+
});
|
|
3747
|
+
|
|
3748
|
+
export default toNodeHandler(fetchHandler);
|
|
3749
|
+
`;
|
|
3750
|
+
async function assemble(root, options) {
|
|
3751
|
+
const dist = join3(root, "dist");
|
|
3752
|
+
for (const dir of ["client", "rsc", "ssr"]) {
|
|
3753
|
+
if (!existsSync4(join3(dist, dir))) {
|
|
3754
|
+
throw new Error(
|
|
3755
|
+
`[rango] preset "vercel": missing dist/${dir}. Run the production build first.`
|
|
3756
|
+
);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
const vercel = options.vercel ?? {};
|
|
3760
|
+
const functionName = vercel.functionName ?? "index";
|
|
3761
|
+
const out = join3(root, ".vercel", "output");
|
|
3762
|
+
const funcDir = join3(out, "functions", `${functionName}.func`);
|
|
3763
|
+
await rm(out, { recursive: true, force: true });
|
|
3764
|
+
await mkdir(funcDir, { recursive: true });
|
|
3765
|
+
await cp(join3(dist, "client"), join3(out, "static"), { recursive: true });
|
|
3766
|
+
await cp(join3(dist, "rsc"), join3(funcDir, "rsc"), { recursive: true });
|
|
3767
|
+
await cp(join3(dist, "ssr"), join3(funcDir, "ssr"), { recursive: true });
|
|
3768
|
+
if (existsSync4(join3(dist, "static"))) {
|
|
3769
|
+
await cp(join3(dist, "static"), join3(funcDir, "static"), {
|
|
3770
|
+
recursive: true
|
|
3771
|
+
});
|
|
3772
|
+
}
|
|
3773
|
+
const rangoRequire = createRequire2(import.meta.url);
|
|
3774
|
+
let srvxNodePath;
|
|
3775
|
+
try {
|
|
3776
|
+
srvxNodePath = rangoRequire.resolve("srvx/node");
|
|
3777
|
+
} catch {
|
|
3778
|
+
throw new Error(
|
|
3779
|
+
'[rango] preset "vercel" requires "srvx" (a dependency of @rangojs/router). Reinstall dependencies.'
|
|
3780
|
+
);
|
|
3781
|
+
}
|
|
3782
|
+
const appRequire = createRequire2(join3(root, "package.json"));
|
|
3783
|
+
let esbuildModule;
|
|
3784
|
+
try {
|
|
3785
|
+
esbuildModule = await import(pathToFileURL(appRequire.resolve("esbuild")).href);
|
|
3786
|
+
} catch {
|
|
3787
|
+
throw new Error(
|
|
3788
|
+
'[rango] preset "vercel" requires "esbuild" to bundle the function launcher. It ships with Vite; reinstall dependencies.'
|
|
3789
|
+
);
|
|
3790
|
+
}
|
|
3791
|
+
const esbuildBuild = esbuildModule.build ?? esbuildModule.default?.build;
|
|
3792
|
+
if (typeof esbuildBuild !== "function") {
|
|
3793
|
+
throw new Error('[rango] preset "vercel": could not load esbuild.build.');
|
|
3794
|
+
}
|
|
3795
|
+
try {
|
|
3796
|
+
await esbuildBuild({
|
|
3797
|
+
stdin: {
|
|
3798
|
+
contents: LAUNCHER_SOURCE,
|
|
3799
|
+
resolveDir: root,
|
|
3800
|
+
sourcefile: "func-entry.mjs",
|
|
3801
|
+
loader: "js"
|
|
3802
|
+
},
|
|
3803
|
+
outfile: join3(funcDir, "index.mjs"),
|
|
3804
|
+
bundle: true,
|
|
3805
|
+
format: "esm",
|
|
3806
|
+
platform: "node",
|
|
3807
|
+
target: "node18",
|
|
3808
|
+
alias: { "srvx/node": srvxNodePath },
|
|
3809
|
+
plugins: [
|
|
3810
|
+
{
|
|
3811
|
+
name: "external-rsc-entry",
|
|
3812
|
+
setup(b) {
|
|
3813
|
+
b.onResolve({ filter: /^\.\/rsc\/index\.js$/ }, () => ({
|
|
3814
|
+
path: "./rsc/index.js",
|
|
3815
|
+
external: true
|
|
3816
|
+
}));
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
]
|
|
3820
|
+
});
|
|
3821
|
+
} catch (error) {
|
|
3822
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3823
|
+
if (/@vercel\/functions/.test(message)) {
|
|
3824
|
+
throw new Error(
|
|
3825
|
+
'[rango] preset "vercel": could not resolve "@vercel/functions". Add it to your app dependencies (it also backs VercelCacheStore).\n' + message
|
|
3826
|
+
);
|
|
3827
|
+
}
|
|
3828
|
+
throw error;
|
|
3829
|
+
}
|
|
3830
|
+
await writeFile(
|
|
3831
|
+
join3(funcDir, "package.json"),
|
|
3832
|
+
JSON.stringify({ type: "module" }, null, 2) + "\n"
|
|
3833
|
+
);
|
|
3834
|
+
const vcConfig = {
|
|
3835
|
+
runtime: vercel.runtime ?? "nodejs22.x",
|
|
3836
|
+
handler: "index.mjs",
|
|
3837
|
+
launcherType: "Nodejs",
|
|
3838
|
+
shouldAddHelpers: false,
|
|
3839
|
+
supportsResponseStreaming: true,
|
|
3840
|
+
maxDuration: vercel.maxDuration ?? 30
|
|
3841
|
+
};
|
|
3842
|
+
if (vercel.memory != null) vcConfig.memory = vercel.memory;
|
|
3843
|
+
if (vercel.regions != null) vcConfig.regions = vercel.regions;
|
|
3844
|
+
await writeFile(
|
|
3845
|
+
join3(funcDir, ".vc-config.json"),
|
|
3846
|
+
JSON.stringify(vcConfig, null, 2) + "\n"
|
|
3847
|
+
);
|
|
3848
|
+
await writeFile(
|
|
3849
|
+
join3(out, "config.json"),
|
|
3850
|
+
JSON.stringify(
|
|
3851
|
+
{
|
|
3852
|
+
version: 3,
|
|
3853
|
+
routes: [
|
|
3854
|
+
{ handle: "filesystem" },
|
|
3855
|
+
{ src: "/(.*)", dest: `/${functionName}` }
|
|
3856
|
+
]
|
|
3857
|
+
},
|
|
3858
|
+
null,
|
|
3859
|
+
2
|
|
3860
|
+
) + "\n"
|
|
3861
|
+
);
|
|
3862
|
+
console.log(
|
|
3863
|
+
`[rango] assembled .vercel/output (function: ${functionName}.func)`
|
|
3864
|
+
);
|
|
3865
|
+
}
|
|
3866
|
+
function createVercelOutputPlugin(options) {
|
|
3867
|
+
let root = process.cwd();
|
|
3868
|
+
let isBuild = false;
|
|
3869
|
+
return {
|
|
3870
|
+
name: "@rangojs/router:vercel-output",
|
|
3871
|
+
configResolved(config) {
|
|
3872
|
+
root = resolve4(config.root);
|
|
3873
|
+
isBuild = config.command === "build";
|
|
3874
|
+
},
|
|
3875
|
+
// buildApp runs once after the whole multi-environment build (rsc, client,
|
|
3876
|
+
// ssr), so dist/ is complete here. closeBundle is unusable for this: it
|
|
3877
|
+
// fires per environment, and twice for ssr (the server-reference scan and
|
|
3878
|
+
// the real build), so it would run before dist/client exists.
|
|
3879
|
+
buildApp: {
|
|
3880
|
+
order: "post",
|
|
3881
|
+
async handler() {
|
|
3882
|
+
if (!isBuild) return;
|
|
3883
|
+
await assemble(root, options);
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3886
|
+
};
|
|
3887
|
+
}
|
|
3888
|
+
|
|
3889
|
+
// src/vite/utils/banner.ts
|
|
3890
|
+
var rangoVersion = package_default.version;
|
|
3891
|
+
var _bannerPrinted = false;
|
|
3892
|
+
function printBanner(mode, preset, version) {
|
|
3893
|
+
if (_bannerPrinted) return;
|
|
3894
|
+
_bannerPrinted = true;
|
|
3895
|
+
const dim = "\x1B[2m";
|
|
3896
|
+
const bold = "\x1B[1m";
|
|
3897
|
+
const reset = "\x1B[0m";
|
|
3898
|
+
const banner = `
|
|
3899
|
+
${dim} \u2726 \u2726 \u2727. . .${reset}
|
|
3900
|
+
${dim} \u2571${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2571 \u2726 *${reset}
|
|
3901
|
+
${dim} ${reset}${bold}\u2551 \u2551${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2727. \u2571${reset}
|
|
3902
|
+
${dim} ${reset}${bold}\u2554\u2557 \u2551 \u2551 \u2551 \u2551${reset}${dim} * \u2571${reset}
|
|
3903
|
+
${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2551 \u2551 \u2551 \u2566\u2550\u2557\u2554\u2550\u2557\u2554\u2557\u2554\u2554\u2550\u2557\u2554\u2550\u2557${reset}${dim} \u2727 \u2726${reset}
|
|
3904
|
+
${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2560\u2550\u255D \u2551 \u2560\u2566\u255D\u2560\u2550\u2563\u2551\u2551\u2551\u2551 \u2566\u2551 \u2551${reset}${dim} * \u2727${reset}
|
|
3905
|
+
${dim} ${reset}${bold}\u2551\u255A\u2550\u255D \u2554\u2550\u2550\u2550\u255D \u2569\u255A\u2550\u2569 \u2569\u255D\u255A\u255D\u255A\u2550\u255D\u255A\u2550\u255D${reset}${dim} \u2726 . *${reset}
|
|
3906
|
+
${dim} ${reset}${bold}\u255A\u2550\u2550\u2557 \u2551${reset}${dim} * RSC Wrangler \u2727 \u2726${reset}
|
|
3907
|
+
${dim} * ${reset}${bold}\u2551 \u2551${reset}${dim} * \u2727. \u2571${reset}
|
|
3908
|
+
${dim} ${reset}${bold}\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550${reset}${dim} \u2726 *${reset}
|
|
3909
|
+
|
|
3910
|
+
v${version} \xB7 ${preset} \xB7 ${mode}
|
|
3911
|
+
`;
|
|
3912
|
+
console.log(banner);
|
|
3913
|
+
}
|
|
3914
|
+
|
|
3915
|
+
// src/vite/plugins/version-injector.ts
|
|
3916
|
+
import { resolve as resolve5 } from "node:path";
|
|
3917
|
+
import * as Vite2 from "vite";
|
|
3918
|
+
function createVersionInjectorPlugin(rscEntryPath) {
|
|
3919
|
+
let resolvedEntryPath = "";
|
|
3920
|
+
return {
|
|
3921
|
+
name: "@rangojs/router:version-injector",
|
|
3922
|
+
enforce: "pre",
|
|
3923
|
+
configResolved(config) {
|
|
3924
|
+
let entryPath = rscEntryPath;
|
|
3925
|
+
if (!entryPath) entryPath = resolveRscEntryFromConfig(config);
|
|
3926
|
+
if (entryPath) {
|
|
3927
|
+
resolvedEntryPath = resolve5(config.root, entryPath);
|
|
3928
|
+
}
|
|
3929
|
+
},
|
|
3930
|
+
transform(code, id) {
|
|
3931
|
+
if (!resolvedEntryPath) return null;
|
|
3932
|
+
const normalizedId = Vite2.normalizePath(id);
|
|
3933
|
+
const normalizedEntry = Vite2.normalizePath(resolvedEntryPath);
|
|
3934
|
+
if (normalizedId !== normalizedEntry) {
|
|
3935
|
+
return null;
|
|
3936
|
+
}
|
|
3937
|
+
const prepend = [
|
|
3938
|
+
`import "virtual:rsc-router/routes-manifest";`
|
|
3939
|
+
];
|
|
3940
|
+
let newCode = code;
|
|
3941
|
+
const needsVersion = code.includes("createRSCHandler") && !code.includes("@rangojs/router:version") && /createRSCHandler\s*\(\s*\{/.test(code);
|
|
3384
3942
|
if (needsVersion) {
|
|
3385
3943
|
prepend.push(`import { VERSION } from "@rangojs/router:version";`);
|
|
3386
3944
|
newCode = newCode.replace(
|
|
@@ -3412,23 +3970,23 @@ function createVersionInjectorPlugin(rscEntryPath) {
|
|
|
3412
3970
|
}
|
|
3413
3971
|
|
|
3414
3972
|
// src/vite/plugins/cjs-to-esm.ts
|
|
3415
|
-
var
|
|
3973
|
+
var debug8 = createRangoDebugger(NS.transform);
|
|
3416
3974
|
function createCjsToEsmPlugin() {
|
|
3417
3975
|
return {
|
|
3418
3976
|
name: "@rangojs/router:cjs-to-esm",
|
|
3419
3977
|
enforce: "pre",
|
|
3420
3978
|
transform(code, id) {
|
|
3421
|
-
const cleanId = id.split("?")[0];
|
|
3422
|
-
if (cleanId.includes("vendor/react-server-dom/client.browser.js")
|
|
3979
|
+
const cleanId = id.split("?")[0].replaceAll("\\", "/");
|
|
3980
|
+
if (cleanId.includes("vendor/react-server-dom/client.browser.js")) {
|
|
3423
3981
|
const isProd = process.env.NODE_ENV === "production";
|
|
3424
3982
|
const cjsFile = isProd ? "./cjs/react-server-dom-webpack-client.browser.production.js" : "./cjs/react-server-dom-webpack-client.browser.development.js";
|
|
3425
|
-
|
|
3983
|
+
debug8?.("cjs-to-esm entry redirect %s", id);
|
|
3426
3984
|
return {
|
|
3427
3985
|
code: `export * from "${cjsFile}";`,
|
|
3428
3986
|
map: null
|
|
3429
3987
|
};
|
|
3430
3988
|
}
|
|
3431
|
-
if (
|
|
3989
|
+
if (cleanId.includes("vendor/react-server-dom/cjs/") && cleanId.includes("client.browser")) {
|
|
3432
3990
|
let transformed = code;
|
|
3433
3991
|
const licenseMatch = transformed.match(/^\/\*\*[\s\S]*?\*\//);
|
|
3434
3992
|
const license = licenseMatch ? licenseMatch[0] : "";
|
|
@@ -3458,7 +4016,7 @@ function createCjsToEsmPlugin() {
|
|
|
3458
4016
|
"export const $1 ="
|
|
3459
4017
|
);
|
|
3460
4018
|
transformed = license + "\n" + transformed;
|
|
3461
|
-
|
|
4019
|
+
debug8?.("cjs-to-esm body rewrite %s", id);
|
|
3462
4020
|
return {
|
|
3463
4021
|
code: transformed,
|
|
3464
4022
|
map: null
|
|
@@ -3471,10 +4029,10 @@ function createCjsToEsmPlugin() {
|
|
|
3471
4029
|
|
|
3472
4030
|
// src/vite/router-discovery.ts
|
|
3473
4031
|
import { createServer as createViteServer } from "vite";
|
|
3474
|
-
import { resolve as
|
|
4032
|
+
import { resolve as resolve9 } from "node:path";
|
|
3475
4033
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
3476
|
-
import { createRequire as
|
|
3477
|
-
import { pathToFileURL } from "node:url";
|
|
4034
|
+
import { createRequire as createRequire3, register } from "node:module";
|
|
4035
|
+
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
3478
4036
|
|
|
3479
4037
|
// src/vite/plugins/virtual-stub-plugin.ts
|
|
3480
4038
|
function createVirtualStubPlugin() {
|
|
@@ -3547,7 +4105,7 @@ function createCloudflareProtocolStubPlugin() {
|
|
|
3547
4105
|
if (!code.includes(CF_PREFIX)) return null;
|
|
3548
4106
|
let ast;
|
|
3549
4107
|
try {
|
|
3550
|
-
ast = this.parse(code);
|
|
4108
|
+
ast = this.parse(code, { lang: "tsx" });
|
|
3551
4109
|
} catch {
|
|
3552
4110
|
return null;
|
|
3553
4111
|
}
|
|
@@ -3607,72 +4165,6 @@ function walk(node, visit) {
|
|
|
3607
4165
|
}
|
|
3608
4166
|
}
|
|
3609
4167
|
|
|
3610
|
-
// src/vite/plugins/client-ref-hashing.ts
|
|
3611
|
-
import { relative } from "node:path";
|
|
3612
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
3613
|
-
var debug8 = createRangoDebugger(NS.transform);
|
|
3614
|
-
var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
|
|
3615
|
-
var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
|
|
3616
|
-
var FS_PREFIX = "/@fs/";
|
|
3617
|
-
function computeProductionHash(projectRoot, refKey) {
|
|
3618
|
-
let toHash;
|
|
3619
|
-
if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
|
|
3620
|
-
toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
|
|
3621
|
-
} else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
|
|
3622
|
-
const absPath = decodeURIComponent(
|
|
3623
|
-
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
|
|
3624
|
-
);
|
|
3625
|
-
toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
|
|
3626
|
-
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
3627
|
-
const absPath = refKey.slice(FS_PREFIX.length - 1);
|
|
3628
|
-
toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
|
|
3629
|
-
} else if (refKey.startsWith("/")) {
|
|
3630
|
-
toHash = refKey.slice(1);
|
|
3631
|
-
} else {
|
|
3632
|
-
return refKey;
|
|
3633
|
-
}
|
|
3634
|
-
return createHash2("sha256").update(toHash).digest("hex").slice(0, 12);
|
|
3635
|
-
}
|
|
3636
|
-
var REGISTER_CLIENT_REF_RE = /registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
|
|
3637
|
-
function transformClientRefs(code, projectRoot) {
|
|
3638
|
-
if (!code.includes("registerClientReference")) return null;
|
|
3639
|
-
let hasReplacement = false;
|
|
3640
|
-
const result = code.replace(
|
|
3641
|
-
REGISTER_CLIENT_REF_RE,
|
|
3642
|
-
(match, refKey) => {
|
|
3643
|
-
const hash = computeProductionHash(projectRoot, refKey);
|
|
3644
|
-
if (hash === refKey) return match;
|
|
3645
|
-
hasReplacement = true;
|
|
3646
|
-
return match.replace(`"${refKey}"`, `"${hash}"`);
|
|
3647
|
-
}
|
|
3648
|
-
);
|
|
3649
|
-
return hasReplacement ? result : null;
|
|
3650
|
-
}
|
|
3651
|
-
function hashClientRefs(projectRoot) {
|
|
3652
|
-
const counter = createCounter(debug8, "hash-client-refs");
|
|
3653
|
-
return {
|
|
3654
|
-
name: "@rangojs/router:hash-client-refs",
|
|
3655
|
-
// Run after the RSC plugin's transform (default enforce is normal)
|
|
3656
|
-
enforce: "post",
|
|
3657
|
-
applyToEnvironment(env) {
|
|
3658
|
-
return env.name === "rsc";
|
|
3659
|
-
},
|
|
3660
|
-
buildEnd() {
|
|
3661
|
-
counter?.flush();
|
|
3662
|
-
},
|
|
3663
|
-
transform(code, id) {
|
|
3664
|
-
const start = counter ? performance.now() : 0;
|
|
3665
|
-
try {
|
|
3666
|
-
const result = transformClientRefs(code, projectRoot);
|
|
3667
|
-
if (result === null) return;
|
|
3668
|
-
return { code: result, map: null };
|
|
3669
|
-
} finally {
|
|
3670
|
-
counter?.record(id, performance.now() - start);
|
|
3671
|
-
}
|
|
3672
|
-
}
|
|
3673
|
-
};
|
|
3674
|
-
}
|
|
3675
|
-
|
|
3676
4168
|
// src/vite/utils/bundle-analysis.ts
|
|
3677
4169
|
function findMatchingParenInBundle(code, openParenPos) {
|
|
3678
4170
|
let depth = 1;
|
|
@@ -3703,7 +4195,7 @@ function extractHandlerExportsFromChunk(chunkCode, handlerModules, fnName, detec
|
|
|
3703
4195
|
if (detectPassthrough) {
|
|
3704
4196
|
const eFnName = escapeRegExp(fnName);
|
|
3705
4197
|
const callStartRe = new RegExp(
|
|
3706
|
-
`const\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
|
|
4198
|
+
`(?:const|let|var)\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
|
|
3707
4199
|
);
|
|
3708
4200
|
const callStart = callStartRe.exec(chunkCode);
|
|
3709
4201
|
if (callStart) {
|
|
@@ -3728,7 +4220,7 @@ function evictHandlerCode(code, exports, fnName, brand) {
|
|
|
3728
4220
|
if (passthrough) continue;
|
|
3729
4221
|
const eName = escapeRegExp(name);
|
|
3730
4222
|
const callStartRe = new RegExp(
|
|
3731
|
-
`const\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
|
|
4223
|
+
`(?:const|let|var)\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
|
|
3732
4224
|
);
|
|
3733
4225
|
const startMatch = callStartRe.exec(modified);
|
|
3734
4226
|
if (!startMatch) continue;
|
|
@@ -3763,6 +4255,8 @@ function createDiscoveryState(entryPath, opts) {
|
|
|
3763
4255
|
projectRoot: "",
|
|
3764
4256
|
isBuildMode: false,
|
|
3765
4257
|
userResolveAlias: void 0,
|
|
4258
|
+
userRunnerConfig: void 0,
|
|
4259
|
+
userResolvePlugins: [],
|
|
3766
4260
|
scanFilter: void 0,
|
|
3767
4261
|
cachedRouterFiles: void 0,
|
|
3768
4262
|
opts,
|
|
@@ -3784,7 +4278,8 @@ function createDiscoveryState(entryPath, opts) {
|
|
|
3784
4278
|
devServerOrigin: null,
|
|
3785
4279
|
devServer: null,
|
|
3786
4280
|
selfWrittenGenFiles: /* @__PURE__ */ new Map(),
|
|
3787
|
-
SELF_WRITE_WINDOW_MS: 5e3
|
|
4281
|
+
SELF_WRITE_WINDOW_MS: 5e3,
|
|
4282
|
+
lastDiscoveryError: null
|
|
3788
4283
|
};
|
|
3789
4284
|
}
|
|
3790
4285
|
|
|
@@ -3822,11 +4317,57 @@ function checkSelfGenWrite(state, filePath, consume) {
|
|
|
3822
4317
|
}
|
|
3823
4318
|
}
|
|
3824
4319
|
|
|
3825
|
-
// src/
|
|
4320
|
+
// src/router/logging.ts
|
|
4321
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4322
|
+
|
|
4323
|
+
// src/internal-debug.ts
|
|
4324
|
+
var INTERNAL_RANGO_DEBUG = typeof __RANGO_DEBUG__ !== "undefined" ? __RANGO_DEBUG__ : typeof process !== "undefined" && Boolean(process.env?.INTERNAL_RANGO_DEBUG);
|
|
4325
|
+
|
|
4326
|
+
// src/router/logging.ts
|
|
4327
|
+
var routerLogContext = new AsyncLocalStorage();
|
|
4328
|
+
|
|
4329
|
+
// src/router/pattern-matching.ts
|
|
4330
|
+
function parsePattern(pattern) {
|
|
4331
|
+
const segments = [];
|
|
4332
|
+
const segmentRegex = /\/(:([a-zA-Z_][a-zA-Z0-9_]*)(\(([^)]+)\))?(\?)?([^/]*)|(\*)|([^/]+))/g;
|
|
4333
|
+
let match;
|
|
4334
|
+
while ((match = segmentRegex.exec(pattern)) !== null) {
|
|
4335
|
+
const [
|
|
4336
|
+
,
|
|
4337
|
+
,
|
|
4338
|
+
paramName,
|
|
4339
|
+
,
|
|
4340
|
+
constraint,
|
|
4341
|
+
optional,
|
|
4342
|
+
suffix,
|
|
4343
|
+
wildcard,
|
|
4344
|
+
staticText
|
|
4345
|
+
] = match;
|
|
4346
|
+
if (wildcard) {
|
|
4347
|
+
segments.push({ type: "wildcard", value: "*", optional: false });
|
|
4348
|
+
} else if (paramName) {
|
|
4349
|
+
segments.push({
|
|
4350
|
+
type: "param",
|
|
4351
|
+
value: paramName,
|
|
4352
|
+
optional: optional === "?",
|
|
4353
|
+
constraint: constraint ? constraint.split("|") : void 0,
|
|
4354
|
+
suffix: suffix || void 0
|
|
4355
|
+
});
|
|
4356
|
+
} else if (staticText) {
|
|
4357
|
+
segments.push({ type: "static", value: staticText, optional: false });
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
return segments;
|
|
4361
|
+
}
|
|
4362
|
+
|
|
4363
|
+
// src/build/prefix-tree-utils.ts
|
|
3826
4364
|
function flattenLeafEntries(prefixTree, routeManifest, result) {
|
|
3827
|
-
function visit(node) {
|
|
4365
|
+
function visit(node, ancestorStaticPrefixes) {
|
|
3828
4366
|
const children = node.children || {};
|
|
3829
4367
|
if (Object.keys(children).length === 0 && node.routes && node.routes.length > 0) {
|
|
4368
|
+
if (ancestorStaticPrefixes.has(node.staticPrefix)) {
|
|
4369
|
+
return;
|
|
4370
|
+
}
|
|
3830
4371
|
const routes = {};
|
|
3831
4372
|
for (const name of node.routes) {
|
|
3832
4373
|
if (name in routeManifest) {
|
|
@@ -3835,13 +4376,15 @@ function flattenLeafEntries(prefixTree, routeManifest, result) {
|
|
|
3835
4376
|
}
|
|
3836
4377
|
result.push({ staticPrefix: node.staticPrefix, routes });
|
|
3837
4378
|
} else {
|
|
4379
|
+
const nextAncestors = new Set(ancestorStaticPrefixes);
|
|
4380
|
+
nextAncestors.add(node.staticPrefix);
|
|
3838
4381
|
for (const child of Object.values(children)) {
|
|
3839
|
-
visit(child);
|
|
4382
|
+
visit(child, nextAncestors);
|
|
3840
4383
|
}
|
|
3841
4384
|
}
|
|
3842
4385
|
}
|
|
3843
4386
|
for (const node of Object.values(prefixTree)) {
|
|
3844
|
-
visit(node);
|
|
4387
|
+
visit(node, /* @__PURE__ */ new Set());
|
|
3845
4388
|
}
|
|
3846
4389
|
}
|
|
3847
4390
|
function buildRouteToStaticPrefix(prefixTree, result) {
|
|
@@ -3858,6 +4401,218 @@ function buildRouteToStaticPrefix(prefixTree, result) {
|
|
|
3858
4401
|
visit(node);
|
|
3859
4402
|
}
|
|
3860
4403
|
}
|
|
4404
|
+
|
|
4405
|
+
// src/build/route-trie.ts
|
|
4406
|
+
function buildRouteTrie(routeManifest, routeAncestry, routeToStaticPrefix, routeTrailingSlash, prerenderRouteNames, passthroughRouteNames, responseTypeRoutes) {
|
|
4407
|
+
const root = {};
|
|
4408
|
+
for (const [routeName, pattern] of Object.entries(routeManifest)) {
|
|
4409
|
+
const ancestry = routeAncestry[routeName] || [];
|
|
4410
|
+
const staticPrefix = routeToStaticPrefix[routeName] || "";
|
|
4411
|
+
const trailingSlash = routeTrailingSlash?.[routeName];
|
|
4412
|
+
const responseType = responseTypeRoutes?.[routeName];
|
|
4413
|
+
const hasTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
|
|
4414
|
+
const normalizedPattern = hasTrailingSlash ? pattern.slice(0, -1) : pattern;
|
|
4415
|
+
const segments = parsePattern(normalizedPattern);
|
|
4416
|
+
insertRoute(root, segments, 0, {
|
|
4417
|
+
n: routeName,
|
|
4418
|
+
sp: staticPrefix,
|
|
4419
|
+
a: ancestry,
|
|
4420
|
+
...trailingSlash ? { ts: trailingSlash } : {},
|
|
4421
|
+
...prerenderRouteNames?.has(routeName) ? { pr: true } : {},
|
|
4422
|
+
...passthroughRouteNames?.has(routeName) ? { pt: true } : {},
|
|
4423
|
+
...responseType ? { rt: responseType } : {}
|
|
4424
|
+
});
|
|
4425
|
+
}
|
|
4426
|
+
sortSuffixParams(root);
|
|
4427
|
+
return root;
|
|
4428
|
+
}
|
|
4429
|
+
function sortSuffixParams(node) {
|
|
4430
|
+
if (node.xp) {
|
|
4431
|
+
const sorted = {};
|
|
4432
|
+
for (const suffix of Object.keys(node.xp).sort(
|
|
4433
|
+
(a, b) => b.length - a.length
|
|
4434
|
+
)) {
|
|
4435
|
+
sorted[suffix] = node.xp[suffix];
|
|
4436
|
+
}
|
|
4437
|
+
node.xp = sorted;
|
|
4438
|
+
}
|
|
4439
|
+
if (node.s) {
|
|
4440
|
+
for (const child of Object.values(node.s)) {
|
|
4441
|
+
sortSuffixParams(child);
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4444
|
+
if (node.p) {
|
|
4445
|
+
sortSuffixParams(node.p.c);
|
|
4446
|
+
}
|
|
4447
|
+
if (node.xp) {
|
|
4448
|
+
for (const child of Object.values(node.xp)) {
|
|
4449
|
+
sortSuffixParams(child.c);
|
|
4450
|
+
}
|
|
4451
|
+
}
|
|
4452
|
+
}
|
|
4453
|
+
function buildPerRouterTrie(manifest) {
|
|
4454
|
+
const ancestry = manifest._routeAncestry;
|
|
4455
|
+
if (!ancestry || Object.keys(ancestry).length === 0) {
|
|
4456
|
+
return null;
|
|
4457
|
+
}
|
|
4458
|
+
const routeToStaticPrefix = {};
|
|
4459
|
+
for (const name of Object.keys(manifest.routeManifest)) {
|
|
4460
|
+
routeToStaticPrefix[name] = "";
|
|
4461
|
+
}
|
|
4462
|
+
if (manifest.prefixTree) {
|
|
4463
|
+
buildRouteToStaticPrefix(manifest.prefixTree, routeToStaticPrefix);
|
|
4464
|
+
}
|
|
4465
|
+
return buildRouteTrie(
|
|
4466
|
+
manifest.routeManifest,
|
|
4467
|
+
ancestry,
|
|
4468
|
+
routeToStaticPrefix,
|
|
4469
|
+
manifest.routeTrailingSlash,
|
|
4470
|
+
manifest.prerenderRoutes ? new Set(manifest.prerenderRoutes) : void 0,
|
|
4471
|
+
manifest.passthroughRoutes ? new Set(manifest.passthroughRoutes) : void 0,
|
|
4472
|
+
manifest.responseTypeRoutes
|
|
4473
|
+
);
|
|
4474
|
+
}
|
|
4475
|
+
function insertRoute(node, segments, index, leaf) {
|
|
4476
|
+
const constraints = {};
|
|
4477
|
+
for (const seg of segments) {
|
|
4478
|
+
if (seg.type === "param") {
|
|
4479
|
+
if (seg.constraint) {
|
|
4480
|
+
constraints[seg.value] = seg.constraint;
|
|
4481
|
+
}
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4484
|
+
const leafBase = {
|
|
4485
|
+
...leaf,
|
|
4486
|
+
...Object.keys(constraints).length > 0 ? { cv: constraints } : {}
|
|
4487
|
+
};
|
|
4488
|
+
insertSegments(node, segments, index, leafBase, []);
|
|
4489
|
+
}
|
|
4490
|
+
function mergeLeaves(existing, leaf) {
|
|
4491
|
+
if (!existing) return leaf;
|
|
4492
|
+
if (existing.rt && leaf.rt) {
|
|
4493
|
+
const merged = leaf;
|
|
4494
|
+
merged.nv = existing.nv || [];
|
|
4495
|
+
merged.nv.push({ routeKey: existing.n, responseType: existing.rt });
|
|
4496
|
+
return merged;
|
|
4497
|
+
}
|
|
4498
|
+
if (leaf.rt && !existing.rt) {
|
|
4499
|
+
if (!existing.nv) {
|
|
4500
|
+
existing.nv = [];
|
|
4501
|
+
existing.rf = true;
|
|
4502
|
+
}
|
|
4503
|
+
existing.nv.push({ routeKey: leaf.n, responseType: leaf.rt });
|
|
4504
|
+
return existing;
|
|
4505
|
+
}
|
|
4506
|
+
if (!leaf.rt && existing.rt) {
|
|
4507
|
+
if (!leaf.nv) leaf.nv = [];
|
|
4508
|
+
if (existing.nv) leaf.nv.push(...existing.nv);
|
|
4509
|
+
leaf.nv.push({ routeKey: existing.n, responseType: existing.rt });
|
|
4510
|
+
return leaf;
|
|
4511
|
+
}
|
|
4512
|
+
return leaf;
|
|
4513
|
+
}
|
|
4514
|
+
function mergeLeaf(node, leaf) {
|
|
4515
|
+
node.r = mergeLeaves(node.r, leaf);
|
|
4516
|
+
}
|
|
4517
|
+
function buildLeaf(leafBase, paramNames) {
|
|
4518
|
+
return paramNames.length > 0 ? { ...leafBase, pa: [...paramNames] } : { ...leafBase };
|
|
4519
|
+
}
|
|
4520
|
+
function insertSegments(node, segments, index, leafBase, paramNames) {
|
|
4521
|
+
if (index >= segments.length) {
|
|
4522
|
+
mergeLeaf(node, buildLeaf(leafBase, paramNames));
|
|
4523
|
+
return;
|
|
4524
|
+
}
|
|
4525
|
+
const segment = segments[index];
|
|
4526
|
+
if (segment.type === "static") {
|
|
4527
|
+
if (!node.s) node.s = {};
|
|
4528
|
+
if (!node.s[segment.value]) node.s[segment.value] = {};
|
|
4529
|
+
insertSegments(
|
|
4530
|
+
node.s[segment.value],
|
|
4531
|
+
segments,
|
|
4532
|
+
index + 1,
|
|
4533
|
+
leafBase,
|
|
4534
|
+
paramNames
|
|
4535
|
+
);
|
|
4536
|
+
} else if (segment.type === "param") {
|
|
4537
|
+
if (segment.optional) {
|
|
4538
|
+
insertSegments(node, segments, index + 1, leafBase, paramNames);
|
|
4539
|
+
}
|
|
4540
|
+
if (segment.suffix) {
|
|
4541
|
+
if (!node.xp) node.xp = {};
|
|
4542
|
+
if (!node.xp[segment.suffix]) {
|
|
4543
|
+
node.xp[segment.suffix] = { n: segment.value, c: {} };
|
|
4544
|
+
}
|
|
4545
|
+
insertSegments(node.xp[segment.suffix].c, segments, index + 1, leafBase, [
|
|
4546
|
+
...paramNames,
|
|
4547
|
+
segment.value
|
|
4548
|
+
]);
|
|
4549
|
+
} else {
|
|
4550
|
+
if (!node.p) {
|
|
4551
|
+
node.p = { n: segment.value, c: {} };
|
|
4552
|
+
}
|
|
4553
|
+
insertSegments(node.p.c, segments, index + 1, leafBase, [
|
|
4554
|
+
...paramNames,
|
|
4555
|
+
segment.value
|
|
4556
|
+
]);
|
|
4557
|
+
}
|
|
4558
|
+
} else if (segment.type === "wildcard") {
|
|
4559
|
+
const wildLeaf = {
|
|
4560
|
+
...buildLeaf(leafBase, paramNames),
|
|
4561
|
+
pn: "*"
|
|
4562
|
+
};
|
|
4563
|
+
const existing = node.w ? { ...node.w } : void 0;
|
|
4564
|
+
const merged = mergeLeaves(existing, wildLeaf);
|
|
4565
|
+
node.w = merged;
|
|
4566
|
+
}
|
|
4567
|
+
}
|
|
4568
|
+
|
|
4569
|
+
// src/build/collect-fallback-refs.ts
|
|
4570
|
+
var CLIENT_REF = /* @__PURE__ */ Symbol.for("react.client.reference");
|
|
4571
|
+
var MAX_DEPTH = 40;
|
|
4572
|
+
var SYNTHETIC_PROPS = {
|
|
4573
|
+
error: new Error("rango: build-time fallback-chunk discovery"),
|
|
4574
|
+
reset: () => {
|
|
4575
|
+
},
|
|
4576
|
+
pathname: "/",
|
|
4577
|
+
info: { componentStack: "" }
|
|
4578
|
+
};
|
|
4579
|
+
function isReactNodeLike(v) {
|
|
4580
|
+
return Array.isArray(v) || typeof v === "object" && v !== null && "$$typeof" in v;
|
|
4581
|
+
}
|
|
4582
|
+
function walkElementTree(node, report, depth) {
|
|
4583
|
+
if (node == null || depth > MAX_DEPTH) return;
|
|
4584
|
+
if (Array.isArray(node)) {
|
|
4585
|
+
for (const child of node) walkElementTree(child, report, depth + 1);
|
|
4586
|
+
return;
|
|
4587
|
+
}
|
|
4588
|
+
if (typeof node !== "object") return;
|
|
4589
|
+
const el = node;
|
|
4590
|
+
const type = el.type;
|
|
4591
|
+
if (type?.$$typeof === CLIENT_REF && typeof type.$$id === "string") {
|
|
4592
|
+
report(type.$$id.split("#")[0]);
|
|
4593
|
+
}
|
|
4594
|
+
const props = el.props;
|
|
4595
|
+
if (props && typeof props === "object") {
|
|
4596
|
+
walkElementTree(props.children, report, depth + 1);
|
|
4597
|
+
for (const key in props) {
|
|
4598
|
+
if (key === "children") continue;
|
|
4599
|
+
const value = props[key];
|
|
4600
|
+
if (isReactNodeLike(value)) walkElementTree(value, report, depth + 1);
|
|
4601
|
+
}
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
function collectFallbackClientRefs(boundary, report) {
|
|
4605
|
+
try {
|
|
4606
|
+
let node = boundary;
|
|
4607
|
+
if (typeof node === "function") {
|
|
4608
|
+
node = node(SYNTHETIC_PROPS);
|
|
4609
|
+
}
|
|
4610
|
+
walkElementTree(node, report, 0);
|
|
4611
|
+
} catch {
|
|
4612
|
+
}
|
|
4613
|
+
}
|
|
4614
|
+
|
|
4615
|
+
// src/vite/utils/manifest-utils.ts
|
|
3861
4616
|
function jsonParseExpression(value) {
|
|
3862
4617
|
const json = JSON.stringify(value);
|
|
3863
4618
|
const escaped = json.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
@@ -3865,6 +4620,9 @@ function jsonParseExpression(value) {
|
|
|
3865
4620
|
}
|
|
3866
4621
|
|
|
3867
4622
|
// src/context-var.ts
|
|
4623
|
+
function hasContextVars(variables) {
|
|
4624
|
+
return Object.keys(variables).length > 0 || Object.getOwnPropertySymbols(variables).length > 0;
|
|
4625
|
+
}
|
|
3868
4626
|
var NON_CACHEABLE_KEYS = /* @__PURE__ */ Symbol.for(
|
|
3869
4627
|
"rango:non-cacheable-keys"
|
|
3870
4628
|
);
|
|
@@ -3898,13 +4656,13 @@ function contextSet(variables, keyOrVar, value, options) {
|
|
|
3898
4656
|
import { createHash as createHash4 } from "node:crypto";
|
|
3899
4657
|
import {
|
|
3900
4658
|
copyFileSync,
|
|
3901
|
-
existsSync as
|
|
4659
|
+
existsSync as existsSync5,
|
|
3902
4660
|
mkdirSync,
|
|
3903
4661
|
rmSync,
|
|
3904
4662
|
statSync,
|
|
3905
4663
|
writeFileSync as writeFileSync2
|
|
3906
4664
|
} from "node:fs";
|
|
3907
|
-
import { resolve as
|
|
4665
|
+
import { resolve as resolve6 } from "node:path";
|
|
3908
4666
|
function escapeRegExp2(str) {
|
|
3909
4667
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3910
4668
|
}
|
|
@@ -4002,7 +4760,7 @@ function notifyOnError(registry, error, phase, routeKey, pathname, skipped) {
|
|
|
4002
4760
|
}
|
|
4003
4761
|
}
|
|
4004
4762
|
function getStagedAssetDir(projectRoot) {
|
|
4005
|
-
return
|
|
4763
|
+
return resolve6(projectRoot, "node_modules/.rangojs-router-build/rsc-assets");
|
|
4006
4764
|
}
|
|
4007
4765
|
function resetStagedBuildAssets(projectRoot) {
|
|
4008
4766
|
rmSync(getStagedAssetDir(projectRoot), { recursive: true, force: true });
|
|
@@ -4012,8 +4770,8 @@ function stageBuildAssetModule(projectRoot, prefix, exportValue) {
|
|
|
4012
4770
|
mkdirSync(stagedDir, { recursive: true });
|
|
4013
4771
|
const contentHash = createHash4("sha256").update(exportValue).digest("hex").slice(0, 8);
|
|
4014
4772
|
const fileName = `${prefix}-${contentHash}.js`;
|
|
4015
|
-
const filePath =
|
|
4016
|
-
if (!
|
|
4773
|
+
const filePath = resolve6(stagedDir, fileName);
|
|
4774
|
+
if (!existsSync5(filePath)) {
|
|
4017
4775
|
writeFileSync2(filePath, `export default ${exportValue};
|
|
4018
4776
|
`);
|
|
4019
4777
|
}
|
|
@@ -4021,12 +4779,12 @@ function stageBuildAssetModule(projectRoot, prefix, exportValue) {
|
|
|
4021
4779
|
}
|
|
4022
4780
|
function copyStagedBuildAssets(projectRoot, fileNames) {
|
|
4023
4781
|
const stagedDir = getStagedAssetDir(projectRoot);
|
|
4024
|
-
const distAssetsDir =
|
|
4782
|
+
const distAssetsDir = resolve6(projectRoot, "dist/rsc/assets");
|
|
4025
4783
|
mkdirSync(distAssetsDir, { recursive: true });
|
|
4026
4784
|
let totalBytes = 0;
|
|
4027
4785
|
for (const fileName of new Set(fileNames)) {
|
|
4028
|
-
const stagedPath =
|
|
4029
|
-
const distPath =
|
|
4786
|
+
const stagedPath = resolve6(stagedDir, fileName);
|
|
4787
|
+
const distPath = resolve6(distAssetsDir, fileName);
|
|
4030
4788
|
copyFileSync(stagedPath, distPath);
|
|
4031
4789
|
totalBytes += statSync(stagedPath).size;
|
|
4032
4790
|
}
|
|
@@ -4068,7 +4826,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4068
4826
|
const progressInterval = totalDynamic > 0 ? setInterval(() => {
|
|
4069
4827
|
const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
|
|
4070
4828
|
console.log(
|
|
4071
|
-
`[
|
|
4829
|
+
`[rango] Resolving prerender params... ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
|
|
4072
4830
|
);
|
|
4073
4831
|
}, 5e3) : void 0;
|
|
4074
4832
|
try {
|
|
@@ -4105,7 +4863,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4105
4863
|
get env() {
|
|
4106
4864
|
if (buildEnv !== void 0) return buildEnv;
|
|
4107
4865
|
throw new Error(
|
|
4108
|
-
"[
|
|
4866
|
+
"[rango] ctx.env is not available during build-time getParams(). Configure buildEnv in your rango() plugin options to enable build-time env access."
|
|
4109
4867
|
);
|
|
4110
4868
|
}
|
|
4111
4869
|
};
|
|
@@ -4117,7 +4875,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4117
4875
|
(performance.now() - getParamsStart).toFixed(1)
|
|
4118
4876
|
);
|
|
4119
4877
|
const concurrency = def.options?.concurrency ?? 1;
|
|
4120
|
-
const hasBuildVars =
|
|
4878
|
+
const hasBuildVars = hasContextVars(buildVars);
|
|
4121
4879
|
for (const params of paramsList) {
|
|
4122
4880
|
let url = substituteRouteParams(
|
|
4123
4881
|
pattern,
|
|
@@ -4146,7 +4904,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4146
4904
|
resolvedRoutes++;
|
|
4147
4905
|
if (err.name === "Skip") {
|
|
4148
4906
|
console.log(
|
|
4149
|
-
`[
|
|
4907
|
+
`[rango] SKIP route "${routeName}" - ${err.message}`
|
|
4150
4908
|
);
|
|
4151
4909
|
notifyOnError(
|
|
4152
4910
|
registry,
|
|
@@ -4159,14 +4917,14 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4159
4917
|
continue;
|
|
4160
4918
|
}
|
|
4161
4919
|
console.error(
|
|
4162
|
-
`[
|
|
4920
|
+
`[rango] Failed to get params for prerender route "${routeName}": ${err.message}`
|
|
4163
4921
|
);
|
|
4164
4922
|
notifyOnError(registry, err, "prerender", routeName);
|
|
4165
4923
|
throw err;
|
|
4166
4924
|
}
|
|
4167
4925
|
} else {
|
|
4168
4926
|
console.warn(
|
|
4169
|
-
`[
|
|
4927
|
+
`[rango] Dynamic prerender route "${routeName}" has no getParams(), skipping`
|
|
4170
4928
|
);
|
|
4171
4929
|
}
|
|
4172
4930
|
}
|
|
@@ -4177,7 +4935,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4177
4935
|
clearInterval(progressInterval);
|
|
4178
4936
|
const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
|
|
4179
4937
|
console.log(
|
|
4180
|
-
`[
|
|
4938
|
+
`[rango] Resolved prerender params: ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
|
|
4181
4939
|
);
|
|
4182
4940
|
}
|
|
4183
4941
|
}
|
|
@@ -4191,7 +4949,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4191
4949
|
const maxConcurrency = Math.max(...entries.map((e) => e.concurrency));
|
|
4192
4950
|
const concurrencyNote = maxConcurrency > 1 ? ` (concurrency: ${maxConcurrency})` : "";
|
|
4193
4951
|
console.log(
|
|
4194
|
-
`[
|
|
4952
|
+
`[rango] Pre-rendering ${entries.length} URL(s)${concurrencyNote}...`
|
|
4195
4953
|
);
|
|
4196
4954
|
debug9?.(
|
|
4197
4955
|
"prerender loop: %d entries, max concurrency %d",
|
|
@@ -4224,7 +4982,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4224
4982
|
if (result.passthrough) {
|
|
4225
4983
|
const elapsed2 = (performance.now() - startUrl).toFixed(0);
|
|
4226
4984
|
console.log(
|
|
4227
|
-
`[
|
|
4985
|
+
`[rango] PASS ${entry.urlPath.padEnd(40)} (${elapsed2}ms) - live fallback`
|
|
4228
4986
|
);
|
|
4229
4987
|
doneCount++;
|
|
4230
4988
|
break;
|
|
@@ -4244,10 +5002,9 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4244
5002
|
const interceptKey = `${result.routeName}/${paramHash}/i`;
|
|
4245
5003
|
const interceptValue = JSON.stringify({
|
|
4246
5004
|
segments: [...result.segments, ...result.interceptSegments],
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
}
|
|
5005
|
+
// interceptHandles is the pre-encoded MERGED (main + intercept)
|
|
5006
|
+
// handle string (the producer merged before encoding).
|
|
5007
|
+
handles: result.interceptHandles ?? ""
|
|
4251
5008
|
});
|
|
4252
5009
|
manifestEntries[interceptKey] = stageBuildAssetModule(
|
|
4253
5010
|
state.projectRoot,
|
|
@@ -4257,7 +5014,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4257
5014
|
}
|
|
4258
5015
|
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
4259
5016
|
console.log(
|
|
4260
|
-
`[
|
|
5017
|
+
`[rango] OK ${entry.urlPath.padEnd(40)} (${elapsed}ms)`
|
|
4261
5018
|
);
|
|
4262
5019
|
doneCount++;
|
|
4263
5020
|
break;
|
|
@@ -4265,7 +5022,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4265
5022
|
if (err.name === "Skip") {
|
|
4266
5023
|
const elapsed2 = (performance.now() - startUrl).toFixed(0);
|
|
4267
5024
|
console.log(
|
|
4268
|
-
`[
|
|
5025
|
+
`[rango] SKIP ${entry.urlPath.padEnd(40)} (${elapsed2}ms) - ${err.message}`
|
|
4269
5026
|
);
|
|
4270
5027
|
skipCount++;
|
|
4271
5028
|
notifyOnError(
|
|
@@ -4280,7 +5037,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4280
5037
|
}
|
|
4281
5038
|
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
4282
5039
|
console.error(
|
|
4283
|
-
`[
|
|
5040
|
+
`[rango] FAIL ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`
|
|
4284
5041
|
);
|
|
4285
5042
|
notifyOnError(
|
|
4286
5043
|
registry,
|
|
@@ -4302,7 +5059,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4302
5059
|
const parts = [`${doneCount} done`];
|
|
4303
5060
|
if (skipCount > 0) parts.push(`${skipCount} skipped`);
|
|
4304
5061
|
console.log(
|
|
4305
|
-
`[
|
|
5062
|
+
`[rango] Pre-render complete: ${parts.join(", ")} (${totalElapsed}ms total)`
|
|
4306
5063
|
);
|
|
4307
5064
|
debug9?.(
|
|
4308
5065
|
"expandPrerenderRoutes done: %d done, %d skipped, %sms (overall %sms)",
|
|
@@ -4328,16 +5085,14 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4328
5085
|
totalStaticCount += exportNames.length;
|
|
4329
5086
|
}
|
|
4330
5087
|
const startStatic = performance.now();
|
|
4331
|
-
console.log(
|
|
4332
|
-
`[rsc-router] Rendering ${totalStaticCount} static handler(s)...`
|
|
4333
|
-
);
|
|
5088
|
+
console.log(`[rango] Rendering ${totalStaticCount} static handler(s)...`);
|
|
4334
5089
|
for (const [moduleId, exportNames] of state.resolvedStaticModules) {
|
|
4335
5090
|
let mod;
|
|
4336
5091
|
try {
|
|
4337
5092
|
mod = await rscEnv.runner.import(moduleId);
|
|
4338
5093
|
} catch (err) {
|
|
4339
5094
|
console.error(
|
|
4340
|
-
`[
|
|
5095
|
+
`[rango] Failed to import static module ${moduleId}: ${err.message}`
|
|
4341
5096
|
);
|
|
4342
5097
|
notifyOnError(registry, err, "static");
|
|
4343
5098
|
throw err;
|
|
@@ -4359,7 +5114,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4359
5114
|
!state.isBuildMode
|
|
4360
5115
|
);
|
|
4361
5116
|
if (result) {
|
|
4362
|
-
const hasHandles =
|
|
5117
|
+
const hasHandles = result.handles !== "";
|
|
4363
5118
|
const exportValue = hasHandles ? JSON.stringify(result) : JSON.stringify(result.encoded);
|
|
4364
5119
|
manifestEntries[def.$$id] = stageBuildAssetModule(
|
|
4365
5120
|
state.projectRoot,
|
|
@@ -4367,9 +5122,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4367
5122
|
exportValue
|
|
4368
5123
|
);
|
|
4369
5124
|
const elapsed = (performance.now() - startHandler).toFixed(0);
|
|
4370
|
-
console.log(
|
|
4371
|
-
`[rsc-router] OK ${name.padEnd(40)} (${elapsed}ms)`
|
|
4372
|
-
);
|
|
5125
|
+
console.log(`[rango] OK ${name.padEnd(40)} (${elapsed}ms)`);
|
|
4373
5126
|
staticDone++;
|
|
4374
5127
|
handled = true;
|
|
4375
5128
|
break;
|
|
@@ -4378,7 +5131,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4378
5131
|
if (err.name === "Skip") {
|
|
4379
5132
|
const elapsed2 = (performance.now() - startHandler).toFixed(0);
|
|
4380
5133
|
console.log(
|
|
4381
|
-
`[
|
|
5134
|
+
`[rango] SKIP ${name.padEnd(40)} (${elapsed2}ms) - ${err.message}`
|
|
4382
5135
|
);
|
|
4383
5136
|
staticSkip++;
|
|
4384
5137
|
notifyOnError(registry, err, "static", void 0, void 0, true);
|
|
@@ -4387,16 +5140,14 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4387
5140
|
}
|
|
4388
5141
|
const elapsed = (performance.now() - startHandler).toFixed(0);
|
|
4389
5142
|
console.error(
|
|
4390
|
-
`[
|
|
5143
|
+
`[rango] FAIL ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`
|
|
4391
5144
|
);
|
|
4392
5145
|
notifyOnError(registry, err, "static");
|
|
4393
5146
|
throw err;
|
|
4394
5147
|
}
|
|
4395
5148
|
}
|
|
4396
5149
|
if (!handled) {
|
|
4397
|
-
console.warn(
|
|
4398
|
-
`[rsc-router] No router could render static handler "${name}"`
|
|
4399
|
-
);
|
|
5150
|
+
console.warn(`[rango] No router could render static handler "${name}"`);
|
|
4400
5151
|
}
|
|
4401
5152
|
}
|
|
4402
5153
|
}
|
|
@@ -4407,7 +5158,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4407
5158
|
const staticParts = [`${staticDone} done`];
|
|
4408
5159
|
if (staticSkip > 0) staticParts.push(`${staticSkip} skipped`);
|
|
4409
5160
|
console.log(
|
|
4410
|
-
`[
|
|
5161
|
+
`[rango] Static render complete: ${staticParts.join(", ")} (${totalStaticElapsed}ms total)`
|
|
4411
5162
|
);
|
|
4412
5163
|
debug9?.(
|
|
4413
5164
|
"renderStaticHandlers done: %d done, %d skipped, %sms (overall %sms)",
|
|
@@ -4418,6 +5169,80 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4418
5169
|
);
|
|
4419
5170
|
}
|
|
4420
5171
|
|
|
5172
|
+
// src/vite/discovery/discovery-errors.ts
|
|
5173
|
+
function indent(text, pad) {
|
|
5174
|
+
return text.split("\n").map((line) => line.length > 0 ? pad + line : line).join("\n");
|
|
5175
|
+
}
|
|
5176
|
+
async function invokeLazyMount(loader, context, errors) {
|
|
5177
|
+
try {
|
|
5178
|
+
await loader();
|
|
5179
|
+
} catch (error) {
|
|
5180
|
+
errors.push({ context, error });
|
|
5181
|
+
}
|
|
5182
|
+
}
|
|
5183
|
+
function isLazyMount(route) {
|
|
5184
|
+
return !!route && route.kind === "lazy" && typeof route.handler === "function";
|
|
5185
|
+
}
|
|
5186
|
+
async function resolveHostRouterHandlers(hostRegistry) {
|
|
5187
|
+
const errors = [];
|
|
5188
|
+
for (const [hostId, entry] of hostRegistry) {
|
|
5189
|
+
for (const route of entry.routes) {
|
|
5190
|
+
if (isLazyMount(route)) {
|
|
5191
|
+
await invokeLazyMount(
|
|
5192
|
+
route.handler,
|
|
5193
|
+
`host "${hostId}" route handler`,
|
|
5194
|
+
errors
|
|
5195
|
+
);
|
|
5196
|
+
}
|
|
5197
|
+
}
|
|
5198
|
+
if (isLazyMount(entry.fallback)) {
|
|
5199
|
+
await invokeLazyMount(
|
|
5200
|
+
entry.fallback.handler,
|
|
5201
|
+
`host "${hostId}" fallback handler`,
|
|
5202
|
+
errors
|
|
5203
|
+
);
|
|
5204
|
+
}
|
|
5205
|
+
}
|
|
5206
|
+
return errors;
|
|
5207
|
+
}
|
|
5208
|
+
function formatNoRoutersError(entryPath, errors) {
|
|
5209
|
+
const base = `[rango] No routers found in registry after importing ${entryPath}`;
|
|
5210
|
+
if (errors.length === 0) {
|
|
5211
|
+
return base;
|
|
5212
|
+
}
|
|
5213
|
+
const formatted = errors.map(({ context, error }) => {
|
|
5214
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
5215
|
+
const detail = err.stack ?? err.message;
|
|
5216
|
+
return ` - while resolving ${context}:
|
|
5217
|
+
${indent(detail, " ")}`;
|
|
5218
|
+
}).join("\n");
|
|
5219
|
+
return `${base}
|
|
5220
|
+
|
|
5221
|
+
${errors.length} error(s) were caught during host-router discovery and likely explain why no routers were registered:
|
|
5222
|
+
${formatted}`;
|
|
5223
|
+
}
|
|
5224
|
+
function toCause(errors) {
|
|
5225
|
+
if (errors.length === 0) return void 0;
|
|
5226
|
+
if (errors.length === 1) return errors[0].error;
|
|
5227
|
+
return new AggregateError(
|
|
5228
|
+
errors.map((e) => e.error),
|
|
5229
|
+
"Multiple host-router handlers failed during discovery"
|
|
5230
|
+
);
|
|
5231
|
+
}
|
|
5232
|
+
var DiscoveryError = class _DiscoveryError extends Error {
|
|
5233
|
+
constructor(entryPath, caught) {
|
|
5234
|
+
super(formatNoRoutersError(entryPath, caught));
|
|
5235
|
+
const cause = toCause(caught);
|
|
5236
|
+
if (cause !== void 0) {
|
|
5237
|
+
this.cause = cause;
|
|
5238
|
+
}
|
|
5239
|
+
this.name = "DiscoveryError";
|
|
5240
|
+
this.entryPath = entryPath;
|
|
5241
|
+
this.caught = caught;
|
|
5242
|
+
Object.setPrototypeOf(this, _DiscoveryError.prototype);
|
|
5243
|
+
}
|
|
5244
|
+
};
|
|
5245
|
+
|
|
4421
5246
|
// src/vite/discovery/discover-routers.ts
|
|
4422
5247
|
var debug10 = createRangoDebugger(NS.discovery);
|
|
4423
5248
|
async function discoverRouters(state, rscEnv) {
|
|
@@ -4434,27 +5259,17 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4434
5259
|
);
|
|
4435
5260
|
let registry = serverMod.RouterRegistry;
|
|
4436
5261
|
if (!registry || registry.size === 0) {
|
|
5262
|
+
const discoveryErrors = [];
|
|
4437
5263
|
try {
|
|
4438
5264
|
const hostRegistry = serverMod.HostRouterRegistry;
|
|
4439
5265
|
if (hostRegistry && hostRegistry.size > 0) {
|
|
4440
5266
|
console.log(
|
|
4441
|
-
`[
|
|
5267
|
+
`[rango] Found ${hostRegistry.size} host router(s), resolving lazy handlers...`
|
|
4442
5268
|
);
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
await route.handler();
|
|
4448
|
-
} catch {
|
|
4449
|
-
}
|
|
4450
|
-
}
|
|
4451
|
-
}
|
|
4452
|
-
if (entry.fallback && typeof entry.fallback.handler === "function") {
|
|
4453
|
-
try {
|
|
4454
|
-
await entry.fallback.handler();
|
|
4455
|
-
} catch {
|
|
4456
|
-
}
|
|
4457
|
-
}
|
|
5269
|
+
const handlerErrors = await resolveHostRouterHandlers(hostRegistry);
|
|
5270
|
+
discoveryErrors.push(...handlerErrors);
|
|
5271
|
+
for (const { context, error } of handlerErrors) {
|
|
5272
|
+
debug10?.("caught error while resolving %s: %O", context, error);
|
|
4458
5273
|
}
|
|
4459
5274
|
const freshServerMod = await rscEnv.runner.import(
|
|
4460
5275
|
"@rangojs/router/server"
|
|
@@ -4465,12 +5280,11 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4465
5280
|
registry = freshRegistry;
|
|
4466
5281
|
}
|
|
4467
5282
|
}
|
|
4468
|
-
} catch {
|
|
5283
|
+
} catch (error) {
|
|
5284
|
+
discoveryErrors.push({ context: "host-router discovery", error });
|
|
4469
5285
|
}
|
|
4470
5286
|
if (!registry || registry.size === 0) {
|
|
4471
|
-
throw new
|
|
4472
|
-
`[rsc-router] No routers found in registry after importing ${state.resolvedEntryPath}`
|
|
4473
|
-
);
|
|
5287
|
+
throw new DiscoveryError(state.resolvedEntryPath, discoveryErrors);
|
|
4474
5288
|
}
|
|
4475
5289
|
}
|
|
4476
5290
|
const buildMod = await timed(
|
|
@@ -4498,6 +5312,15 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4498
5312
|
let mergedRouteTrailingSlash = {};
|
|
4499
5313
|
let routerMountIndex = 0;
|
|
4500
5314
|
const allManifests = [];
|
|
5315
|
+
const clientChunkCtx = state.opts?.clientChunkCtx;
|
|
5316
|
+
const collectClientFallbackRef = clientChunkCtx ? (refKey) => clientChunkCtx.fallbackRefs.add(
|
|
5317
|
+
computeProductionHash(state.projectRoot, refKey)
|
|
5318
|
+
) : void 0;
|
|
5319
|
+
const collectFromBoundaryNode = (node) => {
|
|
5320
|
+
if (collectClientFallbackRef) {
|
|
5321
|
+
collectFallbackClientRefs(node, collectClientFallbackRef);
|
|
5322
|
+
}
|
|
5323
|
+
};
|
|
4501
5324
|
const manifestGenStart = debug10 ? performance.now() : 0;
|
|
4502
5325
|
for (const [id, router] of registry) {
|
|
4503
5326
|
if (!router.urlpatterns || !generateManifestFull) {
|
|
@@ -4506,10 +5329,18 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4506
5329
|
const manifest = generateManifestFull(
|
|
4507
5330
|
router.urlpatterns,
|
|
4508
5331
|
routerMountIndex,
|
|
4509
|
-
|
|
5332
|
+
{
|
|
5333
|
+
...router.__basename ? { urlPrefix: router.__basename } : {},
|
|
5334
|
+
...collectClientFallbackRef ? { collectClientFallbackRef } : {}
|
|
5335
|
+
}
|
|
4510
5336
|
);
|
|
4511
5337
|
routerMountIndex++;
|
|
4512
5338
|
allManifests.push({ id, manifest });
|
|
5339
|
+
if (collectClientFallbackRef) {
|
|
5340
|
+
collectFromBoundaryNode(router.__defaultErrorBoundary);
|
|
5341
|
+
collectFromBoundaryNode(router.__defaultNotFoundBoundary);
|
|
5342
|
+
collectFromBoundaryNode(router.__notFound);
|
|
5343
|
+
}
|
|
4513
5344
|
const routeCount = Object.keys(manifest.routeManifest).length;
|
|
4514
5345
|
const staticRoutes = Object.values(manifest.routeManifest).filter(
|
|
4515
5346
|
(p) => !p.includes(":") && !p.includes("*")
|
|
@@ -4546,21 +5377,17 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4546
5377
|
if (manifest.routeTrailingSlash) {
|
|
4547
5378
|
Object.assign(mergedRouteTrailingSlash, manifest.routeTrailingSlash);
|
|
4548
5379
|
}
|
|
4549
|
-
flattenLeafEntries(
|
|
4550
|
-
manifest.prefixTree,
|
|
4551
|
-
manifest.routeManifest,
|
|
4552
|
-
newMergedPrecomputedEntries
|
|
4553
|
-
);
|
|
4554
|
-
newPerRouterManifestDataMap.set(id, manifest.routeManifest);
|
|
4555
5380
|
const routerPrecomputed = [];
|
|
4556
5381
|
flattenLeafEntries(
|
|
4557
5382
|
manifest.prefixTree,
|
|
4558
5383
|
manifest.routeManifest,
|
|
4559
5384
|
routerPrecomputed
|
|
4560
5385
|
);
|
|
5386
|
+
newMergedPrecomputedEntries.push(...routerPrecomputed);
|
|
5387
|
+
newPerRouterManifestDataMap.set(id, manifest.routeManifest);
|
|
4561
5388
|
newPerRouterPrecomputedMap.set(id, routerPrecomputed);
|
|
4562
5389
|
console.log(
|
|
4563
|
-
`[
|
|
5390
|
+
`[rango] Router "${id}" -> ${routeCount} routes (${staticRoutes} static, ${dynamicRoutes} dynamic)`
|
|
4564
5391
|
);
|
|
4565
5392
|
}
|
|
4566
5393
|
if (registry.size > 1) {
|
|
@@ -4569,7 +5396,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4569
5396
|
);
|
|
4570
5397
|
if (autoIds.length > 1) {
|
|
4571
5398
|
console.warn(
|
|
4572
|
-
`[
|
|
5399
|
+
`[rango] WARNING: ${autoIds.length} routers use auto-generated IDs (${autoIds.join(", ")}). In multi-router setups, each createRouter() must have an explicit \`id\` option to ensure per-router manifest data is matched correctly at runtime. Example: createRouter({ id: "site", ... })`
|
|
4573
5400
|
);
|
|
4574
5401
|
}
|
|
4575
5402
|
}
|
|
@@ -4581,8 +5408,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4581
5408
|
let newMergedRouteTrie = null;
|
|
4582
5409
|
const trieStart = debug10 ? performance.now() : 0;
|
|
4583
5410
|
if (Object.keys(newMergedRouteManifest).length > 0) {
|
|
4584
|
-
|
|
4585
|
-
if (buildRouteTrie && mergedRouteAncestry) {
|
|
5411
|
+
if (mergedRouteAncestry) {
|
|
4586
5412
|
const routeToStaticPrefix = {};
|
|
4587
5413
|
for (const { manifest } of allManifests) {
|
|
4588
5414
|
for (const name of Object.keys(manifest.routeManifest)) {
|
|
@@ -4614,31 +5440,16 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4614
5440
|
newMergedRouteManifest,
|
|
4615
5441
|
mergedRouteAncestry,
|
|
4616
5442
|
routeToStaticPrefix,
|
|
4617
|
-
|
|
4618
|
-
prerenderRouteNames
|
|
4619
|
-
passthroughRouteNames
|
|
4620
|
-
|
|
5443
|
+
mergedRouteTrailingSlash,
|
|
5444
|
+
prerenderRouteNames,
|
|
5445
|
+
passthroughRouteNames,
|
|
5446
|
+
mergedResponseTypeRoutes
|
|
4621
5447
|
);
|
|
4622
5448
|
for (const { id, manifest } of allManifests) {
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
for (const name of Object.keys(manifest.routeManifest)) {
|
|
4627
|
-
perRouterStaticPrefix[name] = "";
|
|
5449
|
+
const perRouterTrie = buildPerRouterTrie(manifest);
|
|
5450
|
+
if (perRouterTrie) {
|
|
5451
|
+
newPerRouterTrieMap.set(id, perRouterTrie);
|
|
4628
5452
|
}
|
|
4629
|
-
buildRouteToStaticPrefix(manifest.prefixTree, perRouterStaticPrefix);
|
|
4630
|
-
const perRouterPrerenderNames = manifest.prerenderRoutes ? new Set(manifest.prerenderRoutes) : void 0;
|
|
4631
|
-
const perRouterPassthroughNames = manifest.passthroughRoutes ? new Set(manifest.passthroughRoutes) : void 0;
|
|
4632
|
-
const perRouterTrie = buildRouteTrie(
|
|
4633
|
-
manifest.routeManifest,
|
|
4634
|
-
manifest._routeAncestry,
|
|
4635
|
-
perRouterStaticPrefix,
|
|
4636
|
-
manifest.routeTrailingSlash && Object.keys(manifest.routeTrailingSlash).length > 0 ? manifest.routeTrailingSlash : void 0,
|
|
4637
|
-
perRouterPrerenderNames && perRouterPrerenderNames.size > 0 ? perRouterPrerenderNames : void 0,
|
|
4638
|
-
perRouterPassthroughNames && perRouterPassthroughNames.size > 0 ? perRouterPassthroughNames : void 0,
|
|
4639
|
-
manifest.responseTypeRoutes && Object.keys(manifest.responseTypeRoutes).length > 0 ? manifest.responseTypeRoutes : void 0
|
|
4640
|
-
);
|
|
4641
|
-
newPerRouterTrieMap.set(id, perRouterTrie);
|
|
4642
5453
|
}
|
|
4643
5454
|
}
|
|
4644
5455
|
}
|
|
@@ -4659,8 +5470,8 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4659
5470
|
}
|
|
4660
5471
|
|
|
4661
5472
|
// src/vite/discovery/route-types-writer.ts
|
|
4662
|
-
import { dirname as dirname3,
|
|
4663
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as
|
|
5473
|
+
import { dirname as dirname3, join as join4, resolve as resolve7 } from "node:path";
|
|
5474
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync6, unlinkSync as unlinkSync2 } from "node:fs";
|
|
4664
5475
|
function filterUserNamedRoutes(manifest) {
|
|
4665
5476
|
const filtered = {};
|
|
4666
5477
|
for (const [name, pattern] of Object.entries(manifest)) {
|
|
@@ -4670,51 +5481,32 @@ function filterUserNamedRoutes(manifest) {
|
|
|
4670
5481
|
}
|
|
4671
5482
|
return filtered;
|
|
4672
5483
|
}
|
|
5484
|
+
function writeGenFileIfChanged(state, outPath, source, opts) {
|
|
5485
|
+
const existing = existsSync6(outPath) ? readFileSync4(outPath, "utf-8") : null;
|
|
5486
|
+
if (existing === source) return;
|
|
5487
|
+
markSelfGenWrite(state, outPath, source);
|
|
5488
|
+
writeFileSync3(outPath, source);
|
|
5489
|
+
if (opts?.log) console.log(`[rango] Generated route types -> ${outPath}`);
|
|
5490
|
+
}
|
|
4673
5491
|
function writeCombinedRouteTypesWithTracking(state, opts) {
|
|
4674
5492
|
const routerFiles = state.cachedRouterFiles ?? findRouterFiles(state.projectRoot, state.scanFilter);
|
|
4675
5493
|
state.cachedRouterFiles = routerFiles;
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
/\.(tsx?|jsx?)$/,
|
|
4681
|
-
""
|
|
4682
|
-
);
|
|
4683
|
-
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4684
|
-
try {
|
|
4685
|
-
preContent.set(outPath, readFileSync4(outPath, "utf-8"));
|
|
4686
|
-
} catch {
|
|
4687
|
-
}
|
|
4688
|
-
}
|
|
4689
|
-
writeCombinedRouteTypes(state.projectRoot, routerFiles, opts);
|
|
4690
|
-
for (const routerFilePath of routerFiles) {
|
|
4691
|
-
const routerDir = dirname3(routerFilePath);
|
|
4692
|
-
const routerBasename = basename(routerFilePath).replace(
|
|
4693
|
-
/\.(tsx?|jsx?)$/,
|
|
4694
|
-
""
|
|
4695
|
-
);
|
|
4696
|
-
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4697
|
-
if (!existsSync5(outPath)) continue;
|
|
4698
|
-
try {
|
|
4699
|
-
const content = readFileSync4(outPath, "utf-8");
|
|
4700
|
-
if (content !== preContent.get(outPath)) {
|
|
4701
|
-
markSelfGenWrite(state, outPath, content);
|
|
4702
|
-
}
|
|
4703
|
-
} catch {
|
|
4704
|
-
}
|
|
4705
|
-
}
|
|
5494
|
+
writeCombinedRouteTypes(state.projectRoot, routerFiles, {
|
|
5495
|
+
...opts,
|
|
5496
|
+
onWrite: (outPath, content) => markSelfGenWrite(state, outPath, content)
|
|
5497
|
+
});
|
|
4706
5498
|
}
|
|
4707
5499
|
function writeRouteTypesFiles(state) {
|
|
4708
5500
|
if (state.perRouterManifests.length === 0) return;
|
|
4709
5501
|
try {
|
|
4710
5502
|
const entryDir = dirname3(
|
|
4711
|
-
|
|
5503
|
+
resolve7(state.projectRoot, state.resolvedEntryPath)
|
|
4712
5504
|
);
|
|
4713
|
-
const oldCombinedPath =
|
|
4714
|
-
if (
|
|
5505
|
+
const oldCombinedPath = join4(entryDir, "named-routes.gen.ts");
|
|
5506
|
+
if (existsSync6(oldCombinedPath)) {
|
|
4715
5507
|
unlinkSync2(oldCombinedPath);
|
|
4716
5508
|
console.log(
|
|
4717
|
-
`[
|
|
5509
|
+
`[rango] Removed stale combined route types: ${oldCombinedPath}`
|
|
4718
5510
|
);
|
|
4719
5511
|
}
|
|
4720
5512
|
} catch {
|
|
@@ -4728,39 +5520,23 @@ function writeRouteTypesFiles(state) {
|
|
|
4728
5520
|
if (!sourceFile) continue;
|
|
4729
5521
|
if (sourceFile.includes("node_modules")) {
|
|
4730
5522
|
throw new Error(
|
|
4731
|
-
`[
|
|
5523
|
+
`[rango] Router "${id}" has sourceFile inside node_modules: ${sourceFile}
|
|
4732
5524
|
This means createRouter() stack trace parsing matched a Vite internal frame.
|
|
4733
5525
|
Set an explicit \`id\` on createRouter() or check the call site.`
|
|
4734
5526
|
);
|
|
4735
5527
|
}
|
|
4736
|
-
const
|
|
4737
|
-
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
4738
|
-
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
5528
|
+
const outPath = genFileTsPath(sourceFile);
|
|
4739
5529
|
const userRoutes = filterUserNamedRoutes(routeManifest);
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
for (const name of Object.keys(userRoutes)) {
|
|
4746
|
-
const schema = staticParsed.searchSchemas[name];
|
|
4747
|
-
if (schema) filtered[name] = schema;
|
|
4748
|
-
}
|
|
4749
|
-
if (Object.keys(filtered).length > 0) {
|
|
4750
|
-
effectiveSearchSchemas = filtered;
|
|
4751
|
-
}
|
|
4752
|
-
}
|
|
4753
|
-
}
|
|
5530
|
+
const effectiveSearchSchemas = resolveSearchSchemas(
|
|
5531
|
+
Object.keys(userRoutes),
|
|
5532
|
+
routeSearchSchemas,
|
|
5533
|
+
sourceFile
|
|
5534
|
+
);
|
|
4754
5535
|
const source = generateRouteTypesSource(
|
|
4755
5536
|
userRoutes,
|
|
4756
5537
|
effectiveSearchSchemas && Object.keys(effectiveSearchSchemas).length > 0 ? effectiveSearchSchemas : void 0
|
|
4757
5538
|
);
|
|
4758
|
-
|
|
4759
|
-
if (existing !== source) {
|
|
4760
|
-
markSelfGenWrite(state, outPath, source);
|
|
4761
|
-
writeFileSync3(outPath, source);
|
|
4762
|
-
console.log(`[rsc-router] Generated route types -> ${outPath}`);
|
|
4763
|
-
}
|
|
5539
|
+
writeGenFileIfChanged(state, outPath, source, { log: true });
|
|
4764
5540
|
}
|
|
4765
5541
|
}
|
|
4766
5542
|
function supplementGenFilesWithRuntimeRoutes(state) {
|
|
@@ -4798,23 +5574,17 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
4798
5574
|
}
|
|
4799
5575
|
}
|
|
4800
5576
|
}
|
|
4801
|
-
const
|
|
4802
|
-
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
4803
|
-
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
5577
|
+
const outPath = genFileTsPath(sourceFile);
|
|
4804
5578
|
const source = generateRouteTypesSource(
|
|
4805
5579
|
mergedRoutes,
|
|
4806
5580
|
Object.keys(mergedSearchSchemas).length > 0 ? mergedSearchSchemas : void 0
|
|
4807
5581
|
);
|
|
4808
|
-
|
|
4809
|
-
if (existing !== source) {
|
|
4810
|
-
markSelfGenWrite(state, outPath, source);
|
|
4811
|
-
writeFileSync3(outPath, source);
|
|
4812
|
-
}
|
|
5582
|
+
writeGenFileIfChanged(state, outPath, source);
|
|
4813
5583
|
}
|
|
4814
5584
|
}
|
|
4815
5585
|
|
|
4816
5586
|
// src/vite/discovery/virtual-module-codegen.ts
|
|
4817
|
-
import { dirname as dirname4, basename
|
|
5587
|
+
import { dirname as dirname4, basename, join as join5 } from "node:path";
|
|
4818
5588
|
function generateRoutesManifestModule(state) {
|
|
4819
5589
|
const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
|
|
4820
5590
|
if (hasManifest) {
|
|
@@ -4825,11 +5595,11 @@ function generateRoutesManifestModule(state) {
|
|
|
4825
5595
|
for (const entry of state.perRouterManifests) {
|
|
4826
5596
|
if (entry.sourceFile) {
|
|
4827
5597
|
const routerDir = dirname4(entry.sourceFile);
|
|
4828
|
-
const routerBasename =
|
|
5598
|
+
const routerBasename = basename(entry.sourceFile).replace(
|
|
4829
5599
|
/\.(tsx?|jsx?)$/,
|
|
4830
5600
|
""
|
|
4831
5601
|
);
|
|
4832
|
-
const genPath =
|
|
5602
|
+
const genPath = join5(
|
|
4833
5603
|
routerDir,
|
|
4834
5604
|
`${routerBasename}.named-routes.gen.js`
|
|
4835
5605
|
).replaceAll("\\", "/");
|
|
@@ -4846,7 +5616,7 @@ function generateRoutesManifestModule(state) {
|
|
|
4846
5616
|
}
|
|
4847
5617
|
}
|
|
4848
5618
|
const lines = [
|
|
4849
|
-
`import { setCachedManifest,
|
|
5619
|
+
`import { setCachedManifest, setRouterManifest, registerRouterManifestLoader, clearAllRouterData } from "@rangojs/router/server";`,
|
|
4850
5620
|
...genFileImports,
|
|
4851
5621
|
// Clear stale per-router cached data (manifest, trie, precomputed entries)
|
|
4852
5622
|
// before re-populating. In Cloudflare dev mode, program reloads re-evaluate
|
|
@@ -4882,18 +5652,6 @@ function generateRoutesManifestModule(state) {
|
|
|
4882
5652
|
);
|
|
4883
5653
|
}
|
|
4884
5654
|
}
|
|
4885
|
-
if (state.isBuildMode) {
|
|
4886
|
-
if (state.mergedPrecomputedEntries && state.mergedPrecomputedEntries.length > 0) {
|
|
4887
|
-
lines.push(
|
|
4888
|
-
`setPrecomputedEntries(${jsonParseExpression(state.mergedPrecomputedEntries)});`
|
|
4889
|
-
);
|
|
4890
|
-
}
|
|
4891
|
-
if (state.mergedRouteTrie) {
|
|
4892
|
-
lines.push(
|
|
4893
|
-
`setRouteTrie(${jsonParseExpression(state.mergedRouteTrie)});`
|
|
4894
|
-
);
|
|
4895
|
-
}
|
|
4896
|
-
}
|
|
4897
5655
|
for (const routerId of state.perRouterManifestDataMap.keys()) {
|
|
4898
5656
|
lines.push(
|
|
4899
5657
|
`registerRouterManifestLoader(${JSON.stringify(routerId)}, () => import(${JSON.stringify(VIRTUAL_ROUTES_MANIFEST_ID + "/" + routerId)}));`
|
|
@@ -4922,11 +5680,11 @@ function generatePerRouterModule(state, routerId) {
|
|
|
4922
5680
|
const lines = [];
|
|
4923
5681
|
if (routerEntry?.sourceFile) {
|
|
4924
5682
|
const routerDir = dirname4(routerEntry.sourceFile);
|
|
4925
|
-
const routerBasename =
|
|
5683
|
+
const routerBasename = basename(routerEntry.sourceFile).replace(
|
|
4926
5684
|
/\.(tsx?|jsx?)$/,
|
|
4927
5685
|
""
|
|
4928
5686
|
);
|
|
4929
|
-
const genPath =
|
|
5687
|
+
const genPath = join5(
|
|
4930
5688
|
routerDir,
|
|
4931
5689
|
`${routerBasename}.named-routes.gen.js`
|
|
4932
5690
|
).replaceAll("\\", "/");
|
|
@@ -4949,17 +5707,17 @@ function generatePerRouterModule(state, routerId) {
|
|
|
4949
5707
|
`export const precomputedEntries = ${jsonParseExpression(entries)};`
|
|
4950
5708
|
);
|
|
4951
5709
|
}
|
|
4952
|
-
return lines.join("\n") || "
|
|
5710
|
+
return lines.join("\n") || "";
|
|
4953
5711
|
}
|
|
4954
5712
|
|
|
4955
5713
|
// src/vite/discovery/bundle-postprocess.ts
|
|
4956
|
-
import { resolve as
|
|
4957
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as
|
|
5714
|
+
import { resolve as resolve8 } from "node:path";
|
|
5715
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync7 } from "node:fs";
|
|
4958
5716
|
function postprocessBundle(state) {
|
|
4959
5717
|
const hasPrerenderData = state.prerenderManifestEntries && Object.keys(state.prerenderManifestEntries).length > 0;
|
|
4960
5718
|
const hasStaticData = state.staticManifestEntries && Object.keys(state.staticManifestEntries).length > 0;
|
|
4961
5719
|
if (!hasPrerenderData && !hasStaticData) return;
|
|
4962
|
-
const rscEntryPath =
|
|
5720
|
+
const rscEntryPath = resolve8(
|
|
4963
5721
|
state.projectRoot,
|
|
4964
5722
|
"dist/rsc",
|
|
4965
5723
|
state.rscEntryFileName ?? "index.js"
|
|
@@ -4980,7 +5738,7 @@ function postprocessBundle(state) {
|
|
|
4980
5738
|
];
|
|
4981
5739
|
for (const target of evictionTargets) {
|
|
4982
5740
|
for (const info of target.infos) {
|
|
4983
|
-
const chunkPath =
|
|
5741
|
+
const chunkPath = resolve8(state.projectRoot, "dist/rsc", info.fileName);
|
|
4984
5742
|
try {
|
|
4985
5743
|
const code = readFileSync5(chunkPath, "utf-8");
|
|
4986
5744
|
const result = evictHandlerCode(
|
|
@@ -4993,19 +5751,19 @@ function postprocessBundle(state) {
|
|
|
4993
5751
|
writeFileSync4(chunkPath, result.code);
|
|
4994
5752
|
const savedKB = (result.savedBytes / 1024).toFixed(1);
|
|
4995
5753
|
console.log(
|
|
4996
|
-
`[
|
|
5754
|
+
`[rango] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
|
|
4997
5755
|
);
|
|
4998
5756
|
}
|
|
4999
5757
|
} catch (replaceErr) {
|
|
5000
5758
|
console.warn(
|
|
5001
|
-
`[
|
|
5759
|
+
`[rango] Failed to evict ${target.label}: ${replaceErr.message}`
|
|
5002
5760
|
);
|
|
5003
5761
|
}
|
|
5004
5762
|
}
|
|
5005
5763
|
}
|
|
5006
5764
|
state.handlerChunkInfoMap.clear();
|
|
5007
5765
|
state.staticHandlerChunkInfoMap.clear();
|
|
5008
|
-
if (hasPrerenderData &&
|
|
5766
|
+
if (hasPrerenderData && existsSync7(rscEntryPath)) {
|
|
5009
5767
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
5010
5768
|
if (!rscCode.includes("__prerender-manifest.js")) {
|
|
5011
5769
|
try {
|
|
@@ -5020,12 +5778,12 @@ function postprocessBundle(state) {
|
|
|
5020
5778
|
manifestMap[key] = `./assets/${assetFileName}`;
|
|
5021
5779
|
}
|
|
5022
5780
|
const manifestCode = [
|
|
5023
|
-
`const m
|
|
5781
|
+
`const m=${jsonParseExpression(manifestMap)};`,
|
|
5024
5782
|
`export function loadPrerenderAsset(s){return import(s)}`,
|
|
5025
5783
|
`export default m;`,
|
|
5026
5784
|
""
|
|
5027
5785
|
].join("\n");
|
|
5028
|
-
const manifestPath =
|
|
5786
|
+
const manifestPath = resolve8(
|
|
5029
5787
|
state.projectRoot,
|
|
5030
5788
|
"dist/rsc/__prerender-manifest.js"
|
|
5031
5789
|
);
|
|
@@ -5036,16 +5794,16 @@ function postprocessBundle(state) {
|
|
|
5036
5794
|
writeFileSync4(rscEntryPath, injection + rscCode);
|
|
5037
5795
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
5038
5796
|
console.log(
|
|
5039
|
-
`[
|
|
5797
|
+
`[rango] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.prerenderManifestEntries).length} entries)`
|
|
5040
5798
|
);
|
|
5041
5799
|
} catch (err) {
|
|
5042
5800
|
throw new Error(
|
|
5043
|
-
`[
|
|
5801
|
+
`[rango] Failed to write prerender assets: ${err.message}`
|
|
5044
5802
|
);
|
|
5045
5803
|
}
|
|
5046
5804
|
}
|
|
5047
5805
|
}
|
|
5048
|
-
if (hasStaticData &&
|
|
5806
|
+
if (hasStaticData && existsSync7(rscEntryPath)) {
|
|
5049
5807
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
5050
5808
|
if (!rscCode.includes("__static-manifest.js")) {
|
|
5051
5809
|
try {
|
|
@@ -5063,7 +5821,7 @@ function postprocessBundle(state) {
|
|
|
5063
5821
|
}
|
|
5064
5822
|
const manifestCode = `const m={${manifestEntries.join(",")}};globalThis.__STATIC_MANIFEST=m;export default m;
|
|
5065
5823
|
`;
|
|
5066
|
-
const manifestPath =
|
|
5824
|
+
const manifestPath = resolve8(
|
|
5067
5825
|
state.projectRoot,
|
|
5068
5826
|
"dist/rsc/__static-manifest.js"
|
|
5069
5827
|
);
|
|
@@ -5074,11 +5832,11 @@ function postprocessBundle(state) {
|
|
|
5074
5832
|
writeFileSync4(rscEntryPath, injection + rscCode);
|
|
5075
5833
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
5076
5834
|
console.log(
|
|
5077
|
-
`[
|
|
5835
|
+
`[rango] Wrote static assets (${totalKB} KB total, ${Object.keys(state.staticManifestEntries).length} entries)`
|
|
5078
5836
|
);
|
|
5079
5837
|
} catch (err) {
|
|
5080
5838
|
throw new Error(
|
|
5081
|
-
`[
|
|
5839
|
+
`[rango] Failed to write static assets: ${err.message}`
|
|
5082
5840
|
);
|
|
5083
5841
|
}
|
|
5084
5842
|
}
|
|
@@ -5095,8 +5853,8 @@ function createDiscoveryGate(s, debug11) {
|
|
|
5095
5853
|
let pendingEvents = false;
|
|
5096
5854
|
const beginGate = () => {
|
|
5097
5855
|
if (gatePending) return;
|
|
5098
|
-
s.discoveryDone = new Promise((
|
|
5099
|
-
gateResolver =
|
|
5856
|
+
s.discoveryDone = new Promise((resolve11) => {
|
|
5857
|
+
gateResolver = resolve11;
|
|
5100
5858
|
});
|
|
5101
5859
|
gatePending = true;
|
|
5102
5860
|
};
|
|
@@ -5159,6 +5917,57 @@ function createDiscoveryGate(s, debug11) {
|
|
|
5159
5917
|
};
|
|
5160
5918
|
}
|
|
5161
5919
|
|
|
5920
|
+
// src/vite/utils/forward-user-plugins.ts
|
|
5921
|
+
function isDenied(name) {
|
|
5922
|
+
return name.startsWith("vite:") || name === "rsc" || name.startsWith("rsc:") || name.startsWith("@rangojs/router") || name.startsWith("@cloudflare/vite-plugin") || name.startsWith("vite-plugin-cloudflare");
|
|
5923
|
+
}
|
|
5924
|
+
function hasResolutionHooks(p) {
|
|
5925
|
+
return Boolean(p.resolveId || p.load);
|
|
5926
|
+
}
|
|
5927
|
+
function stripToResolutionHooks(p) {
|
|
5928
|
+
const stripped = { name: p.name };
|
|
5929
|
+
if (p.enforce) stripped.enforce = p.enforce;
|
|
5930
|
+
if (p.applyToEnvironment)
|
|
5931
|
+
stripped.applyToEnvironment = p.applyToEnvironment;
|
|
5932
|
+
if (p.resolveId) stripped.resolveId = p.resolveId;
|
|
5933
|
+
if (p.load) stripped.load = p.load;
|
|
5934
|
+
return stripped;
|
|
5935
|
+
}
|
|
5936
|
+
function selectForwardableResolvePlugins(plugins) {
|
|
5937
|
+
if (!plugins) return [];
|
|
5938
|
+
const forwarded = [];
|
|
5939
|
+
for (const p of plugins) {
|
|
5940
|
+
const name = p?.name;
|
|
5941
|
+
if (!name || isDenied(name)) continue;
|
|
5942
|
+
if (!hasResolutionHooks(p)) continue;
|
|
5943
|
+
forwarded.push(stripToResolutionHooks(p));
|
|
5944
|
+
}
|
|
5945
|
+
return forwarded;
|
|
5946
|
+
}
|
|
5947
|
+
function pickForwardedRunnerConfig(config) {
|
|
5948
|
+
const r = config.resolve ?? {};
|
|
5949
|
+
const resolve11 = {};
|
|
5950
|
+
if (r.alias !== void 0) resolve11.alias = r.alias;
|
|
5951
|
+
if (r.dedupe !== void 0) resolve11.dedupe = r.dedupe;
|
|
5952
|
+
if (r.conditions !== void 0) resolve11.conditions = r.conditions;
|
|
5953
|
+
if (r.mainFields !== void 0) resolve11.mainFields = r.mainFields;
|
|
5954
|
+
if (r.extensions !== void 0) resolve11.extensions = r.extensions;
|
|
5955
|
+
if (r.preserveSymlinks !== void 0)
|
|
5956
|
+
resolve11.preserveSymlinks = r.preserveSymlinks;
|
|
5957
|
+
if (r.tsconfigPaths !== void 0) resolve11.tsconfigPaths = r.tsconfigPaths;
|
|
5958
|
+
const userOxc = config.oxc;
|
|
5959
|
+
const userJsx = userOxc && typeof userOxc === "object" && typeof userOxc.jsx === "object" && userOxc.jsx !== null ? userOxc.jsx : {};
|
|
5960
|
+
const oxc = userOxc && typeof userOxc === "object" ? {
|
|
5961
|
+
...userOxc,
|
|
5962
|
+
jsx: { ...userJsx, runtime: "automatic", importSource: "react" }
|
|
5963
|
+
} : { jsx: { runtime: "automatic", importSource: "react" } };
|
|
5964
|
+
return {
|
|
5965
|
+
resolve: resolve11,
|
|
5966
|
+
define: config.define,
|
|
5967
|
+
oxc
|
|
5968
|
+
};
|
|
5969
|
+
}
|
|
5970
|
+
|
|
5162
5971
|
// src/vite/router-discovery.ts
|
|
5163
5972
|
var debugDiscovery = createRangoDebugger(NS.discovery);
|
|
5164
5973
|
var debugRoutes = createRangoDebugger(NS.routes);
|
|
@@ -5174,21 +5983,29 @@ function ensureCloudflareProtocolLoaderRegistered() {
|
|
|
5174
5983
|
);
|
|
5175
5984
|
} catch (err) {
|
|
5176
5985
|
console.warn(
|
|
5177
|
-
`[
|
|
5986
|
+
`[rango] Could not register Node ESM loader hook for cloudflare:* imports (${err?.message ?? err}). Falling back to Vite transform only.`
|
|
5178
5987
|
);
|
|
5179
5988
|
}
|
|
5180
5989
|
}
|
|
5181
5990
|
async function createTempRscServer(state, options = {}) {
|
|
5182
5991
|
ensureCloudflareProtocolLoaderRegistered();
|
|
5183
5992
|
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
5993
|
+
const runnerConfig = state.userRunnerConfig;
|
|
5994
|
+
const resolveConfig = runnerConfig?.resolve ?? {
|
|
5995
|
+
alias: state.userResolveAlias
|
|
5996
|
+
};
|
|
5997
|
+
const oxcConfig = runnerConfig?.oxc ?? {
|
|
5998
|
+
jsx: { runtime: "automatic", importSource: "react" }
|
|
5999
|
+
};
|
|
5184
6000
|
return createViteServer({
|
|
5185
6001
|
root: state.projectRoot,
|
|
5186
6002
|
configFile: false,
|
|
5187
6003
|
server: { middlewareMode: true },
|
|
5188
6004
|
appType: "custom",
|
|
5189
6005
|
logLevel: "silent",
|
|
5190
|
-
resolve:
|
|
5191
|
-
|
|
6006
|
+
resolve: resolveConfig,
|
|
6007
|
+
...runnerConfig?.define ? { define: runnerConfig.define } : {},
|
|
6008
|
+
oxc: oxcConfig,
|
|
5192
6009
|
...options.cacheDir && { cacheDir: options.cacheDir },
|
|
5193
6010
|
plugins: [
|
|
5194
6011
|
rsc({
|
|
@@ -5206,7 +6023,11 @@ async function createTempRscServer(state, options = {}) {
|
|
|
5206
6023
|
// Dev prerender must use dev-mode IDs (path-based) to match the workerd
|
|
5207
6024
|
// runtime. forceBuild produces hashed IDs for production bundle consistency.
|
|
5208
6025
|
exposeInternalIds(options.forceBuild ? { forceBuild: true } : void 0),
|
|
5209
|
-
exposeRouterId()
|
|
6026
|
+
exposeRouterId(),
|
|
6027
|
+
// Forwarded user resolution plugins (e.g. vite-tsconfig-paths). Stripped
|
|
6028
|
+
// to resolveId/load and placed last so framework resolution runs first;
|
|
6029
|
+
// Vite re-sorts by `enforce`, so `enforce: "pre"` resolvers still lead.
|
|
6030
|
+
...state.userResolvePlugins
|
|
5210
6031
|
]
|
|
5211
6032
|
});
|
|
5212
6033
|
}
|
|
@@ -5215,15 +6036,15 @@ async function resolveBuildEnv(option, factoryCtx) {
|
|
|
5215
6036
|
if (option === "auto") {
|
|
5216
6037
|
if (factoryCtx.preset !== "cloudflare") {
|
|
5217
6038
|
throw new Error(
|
|
5218
|
-
'[
|
|
6039
|
+
'[rango] buildEnv: "auto" is only supported with preset: "cloudflare". Use a factory function or plain object for other presets.'
|
|
5219
6040
|
);
|
|
5220
6041
|
}
|
|
5221
6042
|
try {
|
|
5222
|
-
const userRequire =
|
|
5223
|
-
|
|
6043
|
+
const userRequire = createRequire3(
|
|
6044
|
+
resolve9(factoryCtx.root, "package.json")
|
|
5224
6045
|
);
|
|
5225
6046
|
const wranglerPath = userRequire.resolve("wrangler");
|
|
5226
|
-
const { getPlatformProxy } = await import(
|
|
6047
|
+
const { getPlatformProxy } = await import(pathToFileURL2(wranglerPath).href);
|
|
5227
6048
|
const proxy = await getPlatformProxy();
|
|
5228
6049
|
return {
|
|
5229
6050
|
env: proxy.env,
|
|
@@ -5231,7 +6052,7 @@ async function resolveBuildEnv(option, factoryCtx) {
|
|
|
5231
6052
|
};
|
|
5232
6053
|
} catch (err) {
|
|
5233
6054
|
throw new Error(
|
|
5234
|
-
`[
|
|
6055
|
+
`[rango] buildEnv: "auto" requires wrangler to be installed.
|
|
5235
6056
|
Install it with: pnpm add -D wrangler
|
|
5236
6057
|
${err.message}`
|
|
5237
6058
|
);
|
|
@@ -5262,7 +6083,7 @@ async function releaseBuildEnv(s) {
|
|
|
5262
6083
|
try {
|
|
5263
6084
|
await s.buildEnvDispose();
|
|
5264
6085
|
} catch (err) {
|
|
5265
|
-
console.warn(`[
|
|
6086
|
+
console.warn(`[rango] buildEnv dispose failed: ${err.message}`);
|
|
5266
6087
|
}
|
|
5267
6088
|
s.buildEnvDispose = null;
|
|
5268
6089
|
}
|
|
@@ -5285,21 +6106,21 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
5285
6106
|
},
|
|
5286
6107
|
configResolved(config) {
|
|
5287
6108
|
s.projectRoot = config.root;
|
|
6109
|
+
s.scanFilter = opts?.discovery ? createScanFilter(s.projectRoot, opts.discovery) : void 0;
|
|
5288
6110
|
s.isBuildMode = config.command === "build";
|
|
5289
6111
|
viteCommand = config.command;
|
|
5290
6112
|
viteMode = config.mode;
|
|
5291
6113
|
s.userResolveAlias = config.resolve.alias;
|
|
6114
|
+
s.userRunnerConfig = pickForwardedRunnerConfig(config);
|
|
6115
|
+
s.userResolvePlugins = selectForwardableResolvePlugins(
|
|
6116
|
+
config.plugins
|
|
6117
|
+
);
|
|
5292
6118
|
if (!s.resolvedEntryPath && opts?.routerPathRef?.path) {
|
|
5293
6119
|
s.resolvedEntryPath = opts.routerPathRef.path;
|
|
5294
6120
|
}
|
|
5295
6121
|
if (!s.resolvedEntryPath) {
|
|
5296
|
-
const
|
|
5297
|
-
|
|
5298
|
-
if (typeof entries === "string") {
|
|
5299
|
-
s.resolvedEntryPath = entries;
|
|
5300
|
-
} else if (Array.isArray(entries) && entries.length > 0) {
|
|
5301
|
-
s.resolvedEntryPath = entries[0];
|
|
5302
|
-
}
|
|
6122
|
+
const entry = resolveRscEntryFromConfig(config);
|
|
6123
|
+
if (entry) s.resolvedEntryPath = entry;
|
|
5303
6124
|
}
|
|
5304
6125
|
if (opts?.staticRouteTypesGeneration !== false) {
|
|
5305
6126
|
s.cachedRouterFiles = findRouterFiles(s.projectRoot, s.scanFilter);
|
|
@@ -5320,8 +6141,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
5320
6141
|
if (globalThis.__rscRouterDiscoveryActive) return;
|
|
5321
6142
|
s.devServer = server;
|
|
5322
6143
|
let resolveDiscovery;
|
|
5323
|
-
const discoveryPromise = new Promise((
|
|
5324
|
-
resolveDiscovery =
|
|
6144
|
+
const discoveryPromise = new Promise((resolve11) => {
|
|
6145
|
+
resolveDiscovery = resolve11;
|
|
5325
6146
|
});
|
|
5326
6147
|
const gate = createDiscoveryGate(s, debugDiscovery);
|
|
5327
6148
|
const beginDiscoveryGate = gate.beginGate;
|
|
@@ -5426,9 +6247,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
5426
6247
|
"getOrCreateTempServer: FAILED message=%s",
|
|
5427
6248
|
err.message
|
|
5428
6249
|
);
|
|
5429
|
-
console.warn(
|
|
5430
|
-
`[rsc-router] Failed to create temp runner: ${err.message}`
|
|
5431
|
-
);
|
|
6250
|
+
console.warn(`[rango] Failed to create temp runner: ${err.message}`);
|
|
5432
6251
|
}
|
|
5433
6252
|
return null;
|
|
5434
6253
|
}
|
|
@@ -5515,7 +6334,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
5515
6334
|
}
|
|
5516
6335
|
} catch (err) {
|
|
5517
6336
|
console.warn(
|
|
5518
|
-
`[
|
|
6337
|
+
`[rango] Cloudflare dev discovery failed: ${err.message}
|
|
5519
6338
|
${err.stack}`
|
|
5520
6339
|
);
|
|
5521
6340
|
}
|
|
@@ -5559,7 +6378,7 @@ ${err.stack}`
|
|
|
5559
6378
|
);
|
|
5560
6379
|
} catch (err) {
|
|
5561
6380
|
console.warn(
|
|
5562
|
-
`[
|
|
6381
|
+
`[rango] Router discovery failed: ${err.message}
|
|
5563
6382
|
${err.stack}`
|
|
5564
6383
|
);
|
|
5565
6384
|
} finally {
|
|
@@ -5592,20 +6411,15 @@ ${err.stack}`
|
|
|
5592
6411
|
if (s.mergedRouteTrie && serverMod.setRouteTrie) {
|
|
5593
6412
|
serverMod.setRouteTrie(s.mergedRouteTrie);
|
|
5594
6413
|
}
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
}
|
|
5605
|
-
if (serverMod.setRouterPrecomputedEntries) {
|
|
5606
|
-
for (const [routerId, entries] of s.perRouterPrecomputedMap) {
|
|
5607
|
-
serverMod.setRouterPrecomputedEntries(routerId, entries);
|
|
5608
|
-
}
|
|
6414
|
+
const perRouterSetters = [
|
|
6415
|
+
[s.perRouterManifestDataMap, "setRouterManifest"],
|
|
6416
|
+
[s.perRouterTrieMap, "setRouterTrie"],
|
|
6417
|
+
[s.perRouterPrecomputedMap, "setRouterPrecomputedEntries"]
|
|
6418
|
+
];
|
|
6419
|
+
for (const [map, fn] of perRouterSetters) {
|
|
6420
|
+
const setter = serverMod[fn];
|
|
6421
|
+
if (typeof setter !== "function") continue;
|
|
6422
|
+
for (const [routerId, value] of map) setter(routerId, value);
|
|
5609
6423
|
}
|
|
5610
6424
|
};
|
|
5611
6425
|
server.middlewares.use("/__rsc_prerender", async (req, res) => {
|
|
@@ -5639,7 +6453,7 @@ ${err.stack}`
|
|
|
5639
6453
|
registry = serverMod.RouterRegistry ?? null;
|
|
5640
6454
|
} catch (err) {
|
|
5641
6455
|
console.warn(
|
|
5642
|
-
`[
|
|
6456
|
+
`[rango] Dev prerender module refresh failed: ${err.message}`
|
|
5643
6457
|
);
|
|
5644
6458
|
res.statusCode = 500;
|
|
5645
6459
|
res.end(`Prerender handler error: ${err.message}`);
|
|
@@ -5684,10 +6498,9 @@ ${err.stack}`
|
|
|
5684
6498
|
if (wantIntercept && result.interceptSegments?.length) {
|
|
5685
6499
|
payload = {
|
|
5686
6500
|
segments: [...result.segments, ...result.interceptSegments],
|
|
5687
|
-
handles
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
}
|
|
6501
|
+
// Pre-encoded MERGED handle string from the producer (handles are
|
|
6502
|
+
// Flight-encoded so Promise/ReactNode values survive the wire).
|
|
6503
|
+
handles: result.interceptHandles ?? ""
|
|
5691
6504
|
};
|
|
5692
6505
|
} else {
|
|
5693
6506
|
payload = { segments: result.segments, handles: result.handles };
|
|
@@ -5697,7 +6510,7 @@ ${err.stack}`
|
|
|
5697
6510
|
return;
|
|
5698
6511
|
} catch (err) {
|
|
5699
6512
|
console.warn(
|
|
5700
|
-
`[
|
|
6513
|
+
`[rango] Dev prerender failed for ${pathname}: ${err.message}`
|
|
5701
6514
|
);
|
|
5702
6515
|
}
|
|
5703
6516
|
}
|
|
@@ -5768,9 +6581,25 @@ ${err.stack}`
|
|
|
5768
6581
|
() => writeRouteTypesFiles(s)
|
|
5769
6582
|
);
|
|
5770
6583
|
}
|
|
6584
|
+
if (s.lastDiscoveryError) {
|
|
6585
|
+
debugDiscovery?.(
|
|
6586
|
+
"hmr: cleared lastDiscoveryError (%s) after successful rediscovery",
|
|
6587
|
+
s.lastDiscoveryError.message
|
|
6588
|
+
);
|
|
6589
|
+
s.lastDiscoveryError = null;
|
|
6590
|
+
}
|
|
6591
|
+
if (rscEnv && !rscEnv.runner) forceCloudflareWorkerReload(rscEnv);
|
|
5771
6592
|
} catch (err) {
|
|
6593
|
+
s.lastDiscoveryError = {
|
|
6594
|
+
message: err?.message ?? String(err),
|
|
6595
|
+
at: Date.now()
|
|
6596
|
+
};
|
|
5772
6597
|
console.warn(
|
|
5773
|
-
`[
|
|
6598
|
+
`[rango] Runtime re-discovery failed: ${err.message}`
|
|
6599
|
+
);
|
|
6600
|
+
debugDiscovery?.(
|
|
6601
|
+
"hmr: lastDiscoveryError set (%s) \u2014 manifest preserved at last-good; recovery mode active (any in-scan source change will trigger rediscovery)",
|
|
6602
|
+
err?.message
|
|
5774
6603
|
);
|
|
5775
6604
|
} finally {
|
|
5776
6605
|
debugDiscovery?.(
|
|
@@ -5780,6 +6609,25 @@ ${err.stack}`
|
|
|
5780
6609
|
}
|
|
5781
6610
|
});
|
|
5782
6611
|
};
|
|
6612
|
+
const forceCloudflareWorkerReload = (rscEnv) => {
|
|
6613
|
+
if (!rscEnv?.hot) return;
|
|
6614
|
+
try {
|
|
6615
|
+
const graph = rscEnv.moduleGraph;
|
|
6616
|
+
if (graph?.invalidateAll) {
|
|
6617
|
+
graph.invalidateAll();
|
|
6618
|
+
debugDiscovery?.("hmr: invalidated workerd rsc module graph");
|
|
6619
|
+
}
|
|
6620
|
+
rscEnv.hot.send({ type: "full-reload" });
|
|
6621
|
+
debugDiscovery?.(
|
|
6622
|
+
"hmr: forced workerd rsc env reload (full-reload)"
|
|
6623
|
+
);
|
|
6624
|
+
} catch (err) {
|
|
6625
|
+
debugDiscovery?.(
|
|
6626
|
+
"hmr: workerd reload failed: %s",
|
|
6627
|
+
err?.message ?? err
|
|
6628
|
+
);
|
|
6629
|
+
}
|
|
6630
|
+
};
|
|
5783
6631
|
const scheduleRouteRegeneration = () => {
|
|
5784
6632
|
clearTimeout(routeChangeTimer);
|
|
5785
6633
|
routeChangeTimer = setTimeout(() => {
|
|
@@ -5799,9 +6647,7 @@ ${err.stack}`
|
|
|
5799
6647
|
}
|
|
5800
6648
|
}
|
|
5801
6649
|
} catch (err) {
|
|
5802
|
-
console.error(
|
|
5803
|
-
`[rsc-router] Route regeneration error: ${err.message}`
|
|
5804
|
-
);
|
|
6650
|
+
console.error(`[rango] Route regeneration error: ${err.message}`);
|
|
5805
6651
|
}
|
|
5806
6652
|
debugDiscovery?.(
|
|
5807
6653
|
"watcher: regenerated gen files (%sms)",
|
|
@@ -5810,7 +6656,7 @@ ${err.stack}`
|
|
|
5810
6656
|
if (s.perRouterManifests.length > 0) {
|
|
5811
6657
|
refreshRuntimeDiscovery().catch((err) => {
|
|
5812
6658
|
console.warn(
|
|
5813
|
-
`[
|
|
6659
|
+
`[rango] Runtime re-discovery error: ${err.message}`
|
|
5814
6660
|
);
|
|
5815
6661
|
resolveDiscoveryGate();
|
|
5816
6662
|
});
|
|
@@ -5819,27 +6665,60 @@ ${err.stack}`
|
|
|
5819
6665
|
};
|
|
5820
6666
|
const handleRouteFileChange = (filePath) => {
|
|
5821
6667
|
if (maybeHandleGeneratedRouteFileMutation(filePath)) return;
|
|
5822
|
-
if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx") && !filePath.endsWith(".js") && !filePath.endsWith(".jsx"))
|
|
6668
|
+
if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx") && !filePath.endsWith(".js") && !filePath.endsWith(".jsx")) {
|
|
6669
|
+
if (s.lastDiscoveryError) {
|
|
6670
|
+
debugDiscovery?.(
|
|
6671
|
+
"watcher: skip non-source %s [LASTERR %s]",
|
|
6672
|
+
filePath,
|
|
6673
|
+
s.lastDiscoveryError.message
|
|
6674
|
+
);
|
|
6675
|
+
}
|
|
5823
6676
|
return;
|
|
5824
|
-
|
|
6677
|
+
}
|
|
6678
|
+
if (s.scanFilter && !s.scanFilter(filePath)) {
|
|
6679
|
+
if (s.lastDiscoveryError) {
|
|
6680
|
+
debugDiscovery?.(
|
|
6681
|
+
"watcher: skip scan-filter %s [LASTERR %s]",
|
|
6682
|
+
filePath,
|
|
6683
|
+
s.lastDiscoveryError.message
|
|
6684
|
+
);
|
|
6685
|
+
}
|
|
6686
|
+
return;
|
|
6687
|
+
}
|
|
6688
|
+
const inRecoveryMode = !!s.lastDiscoveryError;
|
|
5825
6689
|
try {
|
|
5826
6690
|
const source = readFileSync6(filePath, "utf-8");
|
|
5827
6691
|
const trimmed = source.trimStart();
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
if (
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
6692
|
+
const isUseClient = trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'");
|
|
6693
|
+
if (!inRecoveryMode && isUseClient) return;
|
|
6694
|
+
let hasUrls = source.includes("urls(");
|
|
6695
|
+
let hasCreateRouter = /\bcreateRouter\s*[<(]/.test(source);
|
|
6696
|
+
if (hasUrls) hasUrls = firstCodeMatchIndex(source, /urls\(/g) >= 0;
|
|
6697
|
+
if (hasCreateRouter) {
|
|
6698
|
+
hasCreateRouter = firstCodeMatchIndex(source, /\bcreateRouter\s*[<(]/g) >= 0;
|
|
6699
|
+
}
|
|
6700
|
+
if (!inRecoveryMode && !hasUrls && !hasCreateRouter) return;
|
|
6701
|
+
if (inRecoveryMode) {
|
|
6702
|
+
debugDiscovery?.(
|
|
6703
|
+
"watcher: recovery rediscovery for %s (urls=%s, router=%s, useClient=%s) [LASTERR %s]",
|
|
6704
|
+
filePath,
|
|
6705
|
+
hasUrls,
|
|
6706
|
+
hasCreateRouter,
|
|
6707
|
+
isUseClient,
|
|
6708
|
+
s.lastDiscoveryError.message
|
|
6709
|
+
);
|
|
6710
|
+
} else {
|
|
6711
|
+
debugDiscovery?.(
|
|
6712
|
+
"watcher: %s matches (urls=%s, router=%s)",
|
|
6713
|
+
filePath,
|
|
6714
|
+
hasUrls,
|
|
6715
|
+
hasCreateRouter
|
|
6716
|
+
);
|
|
6717
|
+
}
|
|
5839
6718
|
if (hasCreateRouter) {
|
|
5840
6719
|
const nestedRouterConflict = findNestedRouterConflict([
|
|
5841
6720
|
...s.cachedRouterFiles ?? [],
|
|
5842
|
-
|
|
6721
|
+
resolve9(filePath)
|
|
5843
6722
|
]);
|
|
5844
6723
|
if (nestedRouterConflict) {
|
|
5845
6724
|
server.config.logger.error(
|
|
@@ -5853,7 +6732,15 @@ ${err.stack}`
|
|
|
5853
6732
|
gate.noteRouteEvent();
|
|
5854
6733
|
}
|
|
5855
6734
|
scheduleRouteRegeneration();
|
|
5856
|
-
} catch {
|
|
6735
|
+
} catch (readErr) {
|
|
6736
|
+
if (s.lastDiscoveryError) {
|
|
6737
|
+
debugDiscovery?.(
|
|
6738
|
+
"watcher: read error %s: %s [LASTERR %s]",
|
|
6739
|
+
filePath,
|
|
6740
|
+
readErr?.message,
|
|
6741
|
+
s.lastDiscoveryError.message
|
|
6742
|
+
);
|
|
6743
|
+
}
|
|
5857
6744
|
}
|
|
5858
6745
|
};
|
|
5859
6746
|
server.watcher.on("add", handleRouteFileChange);
|
|
@@ -5899,7 +6786,7 @@ ${err.stack}`
|
|
|
5899
6786
|
const rscEnv = tempServer.environments?.rsc;
|
|
5900
6787
|
if (!rscEnv?.runner) {
|
|
5901
6788
|
console.warn(
|
|
5902
|
-
"[
|
|
6789
|
+
"[rango] RSC environment runner not available during build, skipping manifest generation"
|
|
5903
6790
|
);
|
|
5904
6791
|
return;
|
|
5905
6792
|
}
|
|
@@ -5931,8 +6818,9 @@ ${err.stack}`
|
|
|
5931
6818
|
${err.stack}` : null
|
|
5932
6819
|
].filter(Boolean).join("\n");
|
|
5933
6820
|
throw new Error(
|
|
5934
|
-
`[
|
|
5935
|
-
${details}
|
|
6821
|
+
`[rango] Build-time router discovery failed:
|
|
6822
|
+
${details}`,
|
|
6823
|
+
{ cause: err }
|
|
5936
6824
|
);
|
|
5937
6825
|
} finally {
|
|
5938
6826
|
delete globalThis.__rscRouterDiscoveryActive;
|
|
@@ -5960,7 +6848,7 @@ ${details}`
|
|
|
5960
6848
|
// `consumeSelfGenWrite` inside `maybeHandleGeneratedRouteFileMutation`),
|
|
5961
6849
|
// AND vite's own HMR pipeline (which invalidates the gen file's
|
|
5962
6850
|
// importers and triggers a second workerd full reload — visible to the
|
|
5963
|
-
// user as a duplicate "[
|
|
6851
|
+
// user as a duplicate "[Rango] HMR: version changed" on the client).
|
|
5964
6852
|
//
|
|
5965
6853
|
// `peekSelfGenWrite` is the authoritative filter: its map only contains
|
|
5966
6854
|
// paths that `markSelfGenWrite` has registered, so it natively works
|
|
@@ -6120,6 +7008,10 @@ async function rango(options) {
|
|
|
6120
7008
|
const resolvedOptions = options ?? { preset: "node" };
|
|
6121
7009
|
const preset = resolvedOptions.preset ?? "node";
|
|
6122
7010
|
const showBanner = resolvedOptions.banner ?? true;
|
|
7011
|
+
const clientChunksOption = resolvedOptions.clientChunks ?? true;
|
|
7012
|
+
const useBuiltInClientChunks = clientChunksOption === true;
|
|
7013
|
+
const clientChunkCtx = useBuiltInClientChunks ? { fallbackRefs: /* @__PURE__ */ new Set() } : void 0;
|
|
7014
|
+
const clientChunks = resolveClientChunks(clientChunksOption, clientChunkCtx);
|
|
6123
7015
|
debugConfig?.("rango(%s) setup start", preset);
|
|
6124
7016
|
const plugins = [];
|
|
6125
7017
|
const rangoAliases = { ...getPackageAliases(), ...getVendorAliases() };
|
|
@@ -6138,7 +7030,11 @@ async function rango(options) {
|
|
|
6138
7030
|
];
|
|
6139
7031
|
const pkg = getPublishedPackageName();
|
|
6140
7032
|
const nested = (spec) => `${pkg} > ${spec}`;
|
|
6141
|
-
const routerRef = {
|
|
7033
|
+
const routerRef = {
|
|
7034
|
+
path: void 0,
|
|
7035
|
+
kind: "router"
|
|
7036
|
+
};
|
|
7037
|
+
const explicitHost = preset !== "cloudflare" ? resolvedOptions.host : void 0;
|
|
6142
7038
|
const prerenderEnabled = true;
|
|
6143
7039
|
if (preset === "cloudflare") {
|
|
6144
7040
|
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
@@ -6151,14 +7047,20 @@ async function rango(options) {
|
|
|
6151
7047
|
enforce: "pre",
|
|
6152
7048
|
config() {
|
|
6153
7049
|
return {
|
|
6154
|
-
// Exclude rsc-router modules from optimization to prevent module duplication
|
|
6155
|
-
// This ensures the same Context instance is used by both browser entry and RSC proxy modules
|
|
6156
7050
|
optimizeDeps: {
|
|
6157
7051
|
exclude: excludeDeps,
|
|
6158
|
-
|
|
7052
|
+
rolldownOptions: sharedRolldownOptions
|
|
6159
7053
|
},
|
|
6160
7054
|
resolve: {
|
|
6161
|
-
alias: rangoAliases
|
|
7055
|
+
alias: rangoAliases,
|
|
7056
|
+
// Force a single React/React-DOM copy across all three RSC
|
|
7057
|
+
// environments. RSC requires exactly one react/react-dom instance
|
|
7058
|
+
// per environment runtime; consumer install topologies (pnpm
|
|
7059
|
+
// strict layout, experimental React pins, third-party "use client"
|
|
7060
|
+
// packages) can otherwise resolve duplicate copies, causing
|
|
7061
|
+
// "Invalid hook call" / lost context. Child environments inherit
|
|
7062
|
+
// this root dedupe, and Vite merges it with any consumer dedupe.
|
|
7063
|
+
dedupe: ["react", "react-dom"]
|
|
6162
7064
|
},
|
|
6163
7065
|
build: {
|
|
6164
7066
|
rollupOptions: { onwarn }
|
|
@@ -6167,30 +7069,22 @@ async function rango(options) {
|
|
|
6167
7069
|
client: {
|
|
6168
7070
|
build: {
|
|
6169
7071
|
rollupOptions: {
|
|
7072
|
+
onwarn,
|
|
6170
7073
|
output: {
|
|
6171
7074
|
manualChunks: getManualChunks
|
|
6172
7075
|
}
|
|
6173
7076
|
}
|
|
6174
7077
|
},
|
|
6175
|
-
// Pre-bundle rsc-html-stream to prevent discovery during first request
|
|
6176
|
-
// Exclude rsc-router modules to ensure same Context instance
|
|
6177
7078
|
optimizeDeps: {
|
|
6178
7079
|
include: [nested("rsc-html-stream/client")],
|
|
6179
7080
|
exclude: excludeDeps,
|
|
6180
|
-
|
|
7081
|
+
rolldownOptions: sharedRolldownOptions
|
|
6181
7082
|
}
|
|
6182
7083
|
},
|
|
6183
7084
|
ssr: {
|
|
6184
|
-
// Build SSR inside RSC directory so wrangler can deploy self-contained dist/rsc
|
|
6185
7085
|
build: {
|
|
6186
7086
|
outDir: "./dist/rsc/ssr"
|
|
6187
7087
|
},
|
|
6188
|
-
resolve: {
|
|
6189
|
-
// Ensure single React instance in SSR child environment
|
|
6190
|
-
dedupe: ["react", "react-dom"]
|
|
6191
|
-
},
|
|
6192
|
-
// Pre-bundle SSR entry and React for proper module linking with childEnvironments
|
|
6193
|
-
// All deps must be listed to avoid late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
6194
7088
|
optimizeDeps: {
|
|
6195
7089
|
entries: [finalEntries.ssr],
|
|
6196
7090
|
include: [
|
|
@@ -6206,14 +7100,11 @@ async function rango(options) {
|
|
|
6206
7100
|
)
|
|
6207
7101
|
],
|
|
6208
7102
|
exclude: excludeDeps,
|
|
6209
|
-
|
|
7103
|
+
rolldownOptions: sharedRolldownOptions
|
|
6210
7104
|
}
|
|
6211
7105
|
},
|
|
6212
7106
|
rsc: {
|
|
6213
|
-
// RSC environment needs exclude list and esbuild options
|
|
6214
|
-
// Exclude rsc-router modules to prevent createContext in RSC environment
|
|
6215
7107
|
optimizeDeps: {
|
|
6216
|
-
// Pre-bundle all RSC deps to prevent late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
6217
7108
|
include: [
|
|
6218
7109
|
"react",
|
|
6219
7110
|
"react/jsx-runtime",
|
|
@@ -6223,7 +7114,7 @@ async function rango(options) {
|
|
|
6223
7114
|
)
|
|
6224
7115
|
],
|
|
6225
7116
|
exclude: excludeDeps,
|
|
6226
|
-
|
|
7117
|
+
rolldownOptions: sharedRolldownOptions
|
|
6227
7118
|
}
|
|
6228
7119
|
}
|
|
6229
7120
|
}
|
|
@@ -6241,7 +7132,8 @@ async function rango(options) {
|
|
|
6241
7132
|
plugins.push(
|
|
6242
7133
|
rsc({
|
|
6243
7134
|
entries: finalEntries,
|
|
6244
|
-
serverHandler: false
|
|
7135
|
+
serverHandler: false,
|
|
7136
|
+
clientChunks
|
|
6245
7137
|
})
|
|
6246
7138
|
);
|
|
6247
7139
|
plugins.push(clientRefDedup());
|
|
@@ -6250,17 +7142,44 @@ async function rango(options) {
|
|
|
6250
7142
|
name: "@rangojs/router:auto-discover",
|
|
6251
7143
|
config(userConfig) {
|
|
6252
7144
|
if (routerRef.path) return;
|
|
6253
|
-
const root = userConfig.root ?
|
|
7145
|
+
const root = userConfig.root ? resolve10(process.cwd(), userConfig.root) : process.cwd();
|
|
7146
|
+
const toRootRelative = (abs) => (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
|
|
7147
|
+
if (explicitHost) {
|
|
7148
|
+
routerRef.path = explicitHost.replaceAll("\\", "/");
|
|
7149
|
+
routerRef.kind = "host";
|
|
7150
|
+
return;
|
|
7151
|
+
}
|
|
6254
7152
|
const candidates = findRouterFiles(root);
|
|
6255
7153
|
if (candidates.length === 1) {
|
|
6256
|
-
|
|
6257
|
-
routerRef.
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
7154
|
+
routerRef.path = toRootRelative(candidates[0]);
|
|
7155
|
+
routerRef.kind = "router";
|
|
7156
|
+
return;
|
|
7157
|
+
}
|
|
7158
|
+
if (candidates.length !== 1) {
|
|
7159
|
+
const hostCandidates = findHostRouterFiles(root);
|
|
7160
|
+
if (hostCandidates.length === 1) {
|
|
7161
|
+
routerRef.path = toRootRelative(hostCandidates[0]);
|
|
7162
|
+
routerRef.kind = "host";
|
|
7163
|
+
return;
|
|
7164
|
+
}
|
|
7165
|
+
if (hostCandidates.length > 1) {
|
|
7166
|
+
const list = hostCandidates.map((f) => " - " + toRootRelative(f)).join("\n");
|
|
7167
|
+
throw new Error(
|
|
7168
|
+
`[rango] Multiple host routers found:
|
|
7169
|
+
${list}
|
|
7170
|
+
|
|
7171
|
+
Set the \`host\` option to the entry to serve, e.g. rango({ preset: "${preset}", host: "./src/worker.rsc.tsx" }).`
|
|
7172
|
+
);
|
|
7173
|
+
}
|
|
7174
|
+
}
|
|
7175
|
+
if (candidates.length > 1) {
|
|
7176
|
+
const list = candidates.map((f) => " - " + toRootRelative(f)).join("\n");
|
|
7177
|
+
throw new Error(
|
|
7178
|
+
`[rango] Multiple routers found:
|
|
7179
|
+
${list}
|
|
7180
|
+
|
|
7181
|
+
If this is a multi-app host router, export a createHostRouter() instance and set the \`host\` option (e.g. rango({ preset: "${preset}", host: "./src/worker.rsc.tsx" })), or use preset: "cloudflare" where you own the worker entry.`
|
|
7182
|
+
);
|
|
6264
7183
|
}
|
|
6265
7184
|
}
|
|
6266
7185
|
});
|
|
@@ -6274,22 +7193,34 @@ ${list}`);
|
|
|
6274
7193
|
plugins.push({
|
|
6275
7194
|
name: "@rangojs/router:rsc-integration",
|
|
6276
7195
|
enforce: "pre",
|
|
6277
|
-
config() {
|
|
7196
|
+
config(_userConfig, configEnv) {
|
|
7197
|
+
const vercelDefine = preset === "vercel" && configEnv.command === "build" ? { "process.env.NODE_ENV": JSON.stringify("production") } : void 0;
|
|
7198
|
+
const vercelServerEnv = preset === "vercel" ? { resolve: { noExternal: true } } : void 0;
|
|
6278
7199
|
return {
|
|
7200
|
+
...vercelDefine ? { define: vercelDefine } : {},
|
|
6279
7201
|
optimizeDeps: {
|
|
6280
7202
|
exclude: excludeDeps,
|
|
6281
|
-
|
|
7203
|
+
rolldownOptions: sharedRolldownOptions
|
|
6282
7204
|
},
|
|
6283
7205
|
build: {
|
|
6284
7206
|
rollupOptions: { onwarn }
|
|
6285
7207
|
},
|
|
6286
7208
|
resolve: {
|
|
6287
|
-
alias: rangoAliases
|
|
7209
|
+
alias: rangoAliases,
|
|
7210
|
+
// Force a single React/React-DOM copy across all three RSC
|
|
7211
|
+
// environments. RSC requires exactly one react/react-dom instance
|
|
7212
|
+
// per environment runtime; consumer install topologies (pnpm
|
|
7213
|
+
// strict layout, experimental React pins, third-party "use client"
|
|
7214
|
+
// packages) can otherwise resolve duplicate copies, causing
|
|
7215
|
+
// "Invalid hook call" / lost context. Child environments inherit
|
|
7216
|
+
// this root dedupe, and Vite merges it with any consumer dedupe.
|
|
7217
|
+
dedupe: ["react", "react-dom"]
|
|
6288
7218
|
},
|
|
6289
7219
|
environments: {
|
|
6290
7220
|
client: {
|
|
6291
7221
|
build: {
|
|
6292
7222
|
rollupOptions: {
|
|
7223
|
+
onwarn,
|
|
6293
7224
|
output: {
|
|
6294
7225
|
manualChunks: getManualChunks
|
|
6295
7226
|
}
|
|
@@ -6304,11 +7235,12 @@ ${list}`);
|
|
|
6304
7235
|
nested("rsc-html-stream/client")
|
|
6305
7236
|
],
|
|
6306
7237
|
exclude: excludeDeps,
|
|
6307
|
-
|
|
7238
|
+
rolldownOptions: sharedRolldownOptions,
|
|
6308
7239
|
entries: [VIRTUAL_IDS.browser]
|
|
6309
7240
|
}
|
|
6310
7241
|
},
|
|
6311
7242
|
ssr: {
|
|
7243
|
+
...vercelServerEnv ?? {},
|
|
6312
7244
|
optimizeDeps: {
|
|
6313
7245
|
entries: [VIRTUAL_IDS.ssr],
|
|
6314
7246
|
include: [
|
|
@@ -6323,10 +7255,11 @@ ${list}`);
|
|
|
6323
7255
|
)
|
|
6324
7256
|
],
|
|
6325
7257
|
exclude: excludeDeps,
|
|
6326
|
-
|
|
7258
|
+
rolldownOptions: sharedRolldownOptions
|
|
6327
7259
|
}
|
|
6328
7260
|
},
|
|
6329
7261
|
rsc: {
|
|
7262
|
+
...vercelServerEnv ?? {},
|
|
6330
7263
|
optimizeDeps: {
|
|
6331
7264
|
entries: [VIRTUAL_IDS.rsc],
|
|
6332
7265
|
include: [
|
|
@@ -6337,7 +7270,7 @@ ${list}`);
|
|
|
6337
7270
|
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
6338
7271
|
)
|
|
6339
7272
|
],
|
|
6340
|
-
|
|
7273
|
+
rolldownOptions: sharedRolldownOptions
|
|
6341
7274
|
}
|
|
6342
7275
|
}
|
|
6343
7276
|
}
|
|
@@ -6346,7 +7279,11 @@ ${list}`);
|
|
|
6346
7279
|
configResolved(config) {
|
|
6347
7280
|
if (showBanner) {
|
|
6348
7281
|
const mode = config.command === "serve" ? process.argv.includes("preview") ? "preview" : "dev" : "build";
|
|
6349
|
-
printBanner(
|
|
7282
|
+
printBanner(
|
|
7283
|
+
mode,
|
|
7284
|
+
preset === "vercel" ? "vercel" : "node",
|
|
7285
|
+
rangoVersion
|
|
7286
|
+
);
|
|
6350
7287
|
}
|
|
6351
7288
|
const rscMinimalCount = config.plugins.filter(
|
|
6352
7289
|
(p) => p.name === "rsc:minimal"
|
|
@@ -6354,7 +7291,7 @@ ${list}`);
|
|
|
6354
7291
|
if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
|
|
6355
7292
|
hasWarnedDuplicate = true;
|
|
6356
7293
|
console.warn(
|
|
6357
|
-
"[
|
|
7294
|
+
"[rango] Duplicate @vitejs/plugin-rsc detected. Remove rsc() from your vite config \u2014 rango() includes it automatically."
|
|
6358
7295
|
);
|
|
6359
7296
|
}
|
|
6360
7297
|
}
|
|
@@ -6363,7 +7300,8 @@ ${list}`);
|
|
|
6363
7300
|
plugins.push(performanceTracksPlugin());
|
|
6364
7301
|
plugins.push(
|
|
6365
7302
|
rsc({
|
|
6366
|
-
entries: finalEntries
|
|
7303
|
+
entries: finalEntries,
|
|
7304
|
+
clientChunks
|
|
6367
7305
|
})
|
|
6368
7306
|
);
|
|
6369
7307
|
plugins.push(clientRefDedup());
|
|
@@ -6402,9 +7340,16 @@ ${list}`);
|
|
|
6402
7340
|
routerPathRef: discoveryRouterRef,
|
|
6403
7341
|
enableBuildPrerender: prerenderEnabled,
|
|
6404
7342
|
buildEnv: options?.buildEnv,
|
|
6405
|
-
preset
|
|
7343
|
+
preset,
|
|
7344
|
+
discovery: options?.discovery,
|
|
7345
|
+
clientChunkCtx
|
|
6406
7346
|
})
|
|
6407
7347
|
);
|
|
7348
|
+
if (preset === "vercel") {
|
|
7349
|
+
plugins.push(
|
|
7350
|
+
createVercelOutputPlugin(resolvedOptions)
|
|
7351
|
+
);
|
|
7352
|
+
}
|
|
6408
7353
|
debugConfig?.(
|
|
6409
7354
|
"rango(%s) setup done: %d plugin(s) (%sms)",
|
|
6410
7355
|
preset,
|
|
@@ -6417,7 +7362,7 @@ ${list}`);
|
|
|
6417
7362
|
// src/vite/plugins/refresh-cmd.ts
|
|
6418
7363
|
function poke() {
|
|
6419
7364
|
return {
|
|
6420
|
-
name: "
|
|
7365
|
+
name: "@rangojs/router:poke",
|
|
6421
7366
|
apply: "serve",
|
|
6422
7367
|
configureServer(server) {
|
|
6423
7368
|
const stdin = process.stdin;
|