@rangojs/router 0.0.0-experimental.eb0645d3 → 0.0.0-experimental.f1468e3c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -0
- package/README.md +126 -16
- package/dist/bin/rango.js +319 -95
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +2724 -1053
- package/package.json +68 -14
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +64 -2
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +224 -32
- package/skills/caching/SKILL.md +279 -17
- package/skills/composability/SKILL.md +27 -3
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +4 -2
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +11 -9
- package/skills/hooks/SKILL.md +243 -29
- package/skills/host-router/SKILL.md +83 -23
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +68 -19
- package/skills/layout/SKILL.md +13 -9
- package/skills/links/SKILL.md +190 -23
- package/skills/loader/SKILL.md +235 -9
- package/skills/middleware/SKILL.md +18 -10
- package/skills/migrate-nextjs/SKILL.md +43 -19
- package/skills/migrate-react-router/SKILL.md +8 -2
- package/skills/mime-routes/SKILL.md +28 -1
- package/skills/observability/SKILL.md +172 -0
- package/skills/parallel/SKILL.md +18 -7
- package/skills/prerender/SKILL.md +65 -60
- package/skills/rango/SKILL.md +251 -24
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +115 -48
- package/skills/route/SKILL.md +46 -5
- package/skills/router-setup/SKILL.md +30 -8
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +130 -0
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -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 +122 -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 +123 -0
- package/skills/typesafety/SKILL.md +322 -29
- package/skills/use-cache/SKILL.md +57 -14
- package/skills/view-transitions/SKILL.md +337 -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 +39 -0
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +192 -150
- 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 +94 -25
- package/src/browser/navigation-client.ts +121 -84
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +115 -67
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +147 -128
- package/src/browser/prefetch/cache.ts +107 -56
- package/src/browser/prefetch/fetch.ts +204 -34
- package/src/browser/prefetch/queue.ts +6 -3
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +30 -7
- package/src/browser/react/NavigationProvider.tsx +283 -118
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/deferred-handle-resolution.ts +75 -0
- package/src/browser/react/filter-segment-order.ts +66 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +178 -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-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +10 -5
- 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 +25 -3
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +11 -21
- package/src/browser/response-adapter.ts +99 -8
- package/src/browser/rsc-router.tsx +91 -24
- package/src/browser/scroll-restoration.ts +30 -17
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +214 -55
- package/src/browser/types.ts +80 -9
- 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 +2 -1
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +117 -14
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +16 -5
- package/src/build/route-types/include-resolution.ts +117 -23
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +22 -6
- package/src/build/route-types/router-processing.ts +55 -28
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +29 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +224 -41
- package/src/cache/cache-scope.ts +188 -82
- package/src/cache/cache-tag.ts +103 -0
- package/src/cache/cf/cf-base64.ts +33 -0
- package/src/cache/cf/cf-cache-constants.ts +127 -0
- package/src/cache/cf/cf-cache-store.ts +1989 -378
- package/src/cache/cf/cf-cache-types.ts +349 -0
- package/src/cache/cf/cf-kv-utils.ts +46 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +89 -21
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +10 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +46 -31
- package/src/cache/read-through-swr.ts +56 -12
- package/src/cache/segment-codec.ts +9 -17
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +37 -100
- package/src/client.rsc.tsx +44 -21
- package/src/client.tsx +36 -61
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +109 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +18 -6
- package/src/decode-loader-results.ts +52 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +30 -4
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +31 -23
- package/src/handles/MetaTags.tsx +62 -19
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +37 -8
- package/src/handles/is-thenable.ts +19 -0
- package/src/handles/meta.ts +51 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -2
- package/src/host/pattern-matcher.ts +23 -52
- 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 +96 -12
- package/src/index.ts +94 -14
- package/src/internal-debug.ts +11 -10
- 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/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +61 -6
- package/src/redirect-origin.ts +100 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +34 -0
- package/src/reverse.ts +65 -40
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +19 -77
- package/src/route-definition/dsl-helpers.ts +304 -309
- package/src/route-definition/helper-factories.ts +28 -140
- package/src/route-definition/helpers-types.ts +82 -55
- package/src/route-definition/index.ts +1 -2
- package/src/route-definition/redirect.ts +44 -11
- package/src/route-definition/resolve-handler-use.ts +12 -1
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-map-builder.ts +0 -16
- package/src/route-types.ts +19 -46
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +73 -25
- package/src/router/error-handling.ts +45 -18
- package/src/router/find-match.ts +44 -23
- package/src/router/handler-context.ts +27 -43
- package/src/router/instrument.ts +350 -0
- package/src/router/intercept-resolution.ts +39 -20
- package/src/router/lazy-includes.ts +10 -47
- package/src/router/loader-resolution.ts +155 -72
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +18 -29
- package/src/router/match-api.ts +9 -24
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +58 -58
- package/src/router/match-middleware/background-revalidation.ts +40 -24
- package/src/router/match-middleware/cache-lookup.ts +159 -285
- package/src/router/match-middleware/cache-store.ts +64 -52
- 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 +44 -74
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +7 -134
- package/src/router/middleware.ts +247 -166
- package/src/router/navigation-snapshot.ts +0 -51
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +85 -94
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prerender-match.ts +104 -65
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +28 -62
- package/src/router/revalidation.ts +123 -73
- package/src/router/route-snapshot.ts +0 -1
- package/src/router/router-context.ts +3 -28
- package/src/router/router-interfaces.ts +83 -35
- package/src/router/router-options.ts +136 -5
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +97 -84
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +76 -39
- package/src/router/segment-resolution/revalidation.ts +272 -320
- 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 +56 -0
- package/src/router/segment-resolution.ts +5 -1
- package/src/router/segment-wrappers.ts +6 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +161 -199
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +206 -0
- package/src/router/trie-matching.ts +162 -64
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +0 -5
- package/src/router.ts +110 -55
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +264 -220
- package/src/rsc/helpers.ts +100 -6
- package/src/rsc/index.ts +2 -5
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +114 -38
- package/src/rsc/manifest-init.ts +28 -41
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +117 -11
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +88 -188
- package/src/rsc/rsc-rendering.ts +98 -76
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +281 -117
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +23 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +35 -30
- package/src/segment-loader-promise.ts +31 -4
- package/src/segment-system.tsx +254 -143
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +163 -51
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +21 -38
- package/src/server/loader-registry.ts +33 -42
- package/src/server/request-context.ts +287 -178
- package/src/ssr/index.tsx +21 -16
- 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 +701 -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 +257 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +105 -0
- package/src/testing/internal/context.ts +371 -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 +357 -0
- package/src/testing/render-route.tsx +581 -0
- package/src/testing/run-loader.ts +385 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/run-transition-when.ts +164 -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 +20 -58
- package/src/theme/ThemeScript.tsx +7 -9
- package/src/theme/constants.ts +52 -13
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +22 -21
- 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 +110 -62
- package/src/types/index.ts +3 -10
- package/src/types/loader-types.ts +11 -9
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +135 -14
- package/src/urls/include-helper.ts +9 -56
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +29 -12
- package/src/urls/path-helper.ts +17 -106
- package/src/urls/pattern-types.ts +36 -19
- package/src/urls/response-types.ts +22 -29
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -19
- package/src/use-loader.tsx +292 -107
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +8 -7
- package/src/vite/discovery/discover-routers.ts +126 -85
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +96 -68
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +44 -0
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +2 -0
- package/src/vite/inject-client-debug.ts +36 -0
- package/src/vite/plugin-types.ts +126 -8
- package/src/vite/plugins/cjs-to-esm.ts +16 -19
- package/src/vite/plugins/client-ref-dedup.ts +16 -11
- package/src/vite/plugins/client-ref-hashing.ts +28 -15
- package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -21
- package/src/vite/plugins/expose-action-id.ts +48 -95
- package/src/vite/plugins/expose-id-utils.ts +88 -55
- package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +11 -90
- package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
- package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
- package/src/vite/plugins/expose-internal-ids.ts +505 -486
- package/src/vite/plugins/performance-tracks.ts +26 -25
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +73 -83
- package/src/vite/plugins/version-injector.ts +40 -29
- package/src/vite/plugins/version-plugin.ts +37 -40
- package/src/vite/plugins/virtual-entries.ts +39 -25
- package/src/vite/rango.ts +109 -118
- package/src/vite/router-discovery.ts +718 -119
- package/src/vite/utils/ast-handler-extract.ts +26 -35
- package/src/vite/utils/banner.ts +1 -1
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/directive-prologue.ts +40 -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 +20 -52
- package/src/vite/utils/prerender-utils.ts +54 -39
- package/src/vite/utils/shared-utils.ts +90 -41
- 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/network-error-thrower.tsx +0 -23
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -6,16 +6,20 @@
|
|
|
6
6
|
* generation.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { contextSet } from "../../context-var.js";
|
|
9
|
+
import { contextSet, hasContextVars } from "../../context-var.js";
|
|
10
10
|
import {
|
|
11
11
|
encodePathParam,
|
|
12
12
|
substituteRouteParams,
|
|
13
13
|
runWithConcurrency,
|
|
14
14
|
groupByConcurrency,
|
|
15
15
|
notifyOnError,
|
|
16
|
+
resolvePrerenderError,
|
|
16
17
|
stageBuildAssetModule,
|
|
17
18
|
} from "../utils/prerender-utils.js";
|
|
18
19
|
import type { DiscoveryState } from "./state.js";
|
|
20
|
+
import { createRangoDebugger, NS } from "../debug.js";
|
|
21
|
+
|
|
22
|
+
const debug = createRangoDebugger(NS.prerender);
|
|
19
23
|
|
|
20
24
|
/**
|
|
21
25
|
* Expand prerender routes into concrete URLs and render them via the
|
|
@@ -30,6 +34,12 @@ export async function expandPrerenderRoutes(
|
|
|
30
34
|
): Promise<void> {
|
|
31
35
|
if (!state.opts?.enableBuildPrerender || !state.isBuildMode) return;
|
|
32
36
|
|
|
37
|
+
const overallStart = debug ? performance.now() : 0;
|
|
38
|
+
debug?.(
|
|
39
|
+
"expandPrerenderRoutes: start (%d router manifest(s))",
|
|
40
|
+
allManifests.length,
|
|
41
|
+
);
|
|
42
|
+
|
|
33
43
|
type PrerenderEntry = {
|
|
34
44
|
urlPath: string;
|
|
35
45
|
routeName: string;
|
|
@@ -72,7 +82,7 @@ export async function expandPrerenderRoutes(
|
|
|
72
82
|
? setInterval(() => {
|
|
73
83
|
const elapsed = ((performance.now() - paramsStart) / 1000).toFixed(1);
|
|
74
84
|
console.log(
|
|
75
|
-
`[
|
|
85
|
+
`[rango] Resolving prerender params... ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`,
|
|
76
86
|
);
|
|
77
87
|
}, 5000)
|
|
78
88
|
: undefined;
|
|
@@ -99,6 +109,7 @@ export async function expandPrerenderRoutes(
|
|
|
99
109
|
} else {
|
|
100
110
|
// Dynamic route: call getParams() to enumerate param combinations
|
|
101
111
|
if (def?.getParams) {
|
|
112
|
+
const getParamsStart = debug ? performance.now() : 0;
|
|
102
113
|
try {
|
|
103
114
|
const buildVars: Record<string, any> = {};
|
|
104
115
|
const buildEnv = state.resolvedBuildEnv;
|
|
@@ -112,16 +123,20 @@ export async function expandPrerenderRoutes(
|
|
|
112
123
|
get env() {
|
|
113
124
|
if (buildEnv !== undefined) return buildEnv;
|
|
114
125
|
throw new Error(
|
|
115
|
-
"[
|
|
126
|
+
"[rango] ctx.env is not available during build-time getParams(). " +
|
|
116
127
|
"Configure buildEnv in your rango() plugin options to enable build-time env access.",
|
|
117
128
|
);
|
|
118
129
|
},
|
|
119
130
|
};
|
|
120
131
|
const paramsList = await def.getParams(getParamsCtx);
|
|
132
|
+
debug?.(
|
|
133
|
+
"getParams %s -> %d params (%sms)",
|
|
134
|
+
routeName,
|
|
135
|
+
paramsList.length,
|
|
136
|
+
(performance.now() - getParamsStart).toFixed(1),
|
|
137
|
+
);
|
|
121
138
|
const concurrency = def.options?.concurrency ?? 1;
|
|
122
|
-
const hasBuildVars =
|
|
123
|
-
Object.keys(buildVars).length > 0 ||
|
|
124
|
-
Object.getOwnPropertySymbols(buildVars).length > 0;
|
|
139
|
+
const hasBuildVars = hasContextVars(buildVars);
|
|
125
140
|
for (const params of paramsList) {
|
|
126
141
|
let url = substituteRouteParams(
|
|
127
142
|
pattern,
|
|
@@ -154,7 +169,7 @@ export async function expandPrerenderRoutes(
|
|
|
154
169
|
// Skip in getParams() skips the entire route
|
|
155
170
|
if (err.name === "Skip") {
|
|
156
171
|
console.log(
|
|
157
|
-
`[
|
|
172
|
+
`[rango] SKIP route "${routeName}" - ${err.message}`,
|
|
158
173
|
);
|
|
159
174
|
notifyOnError(
|
|
160
175
|
registry,
|
|
@@ -168,14 +183,14 @@ export async function expandPrerenderRoutes(
|
|
|
168
183
|
}
|
|
169
184
|
// Regular error: fail the build
|
|
170
185
|
console.error(
|
|
171
|
-
`[
|
|
186
|
+
`[rango] Failed to get params for prerender route "${routeName}": ${err.message}`,
|
|
172
187
|
);
|
|
173
188
|
notifyOnError(registry, err, "prerender", routeName);
|
|
174
189
|
throw err;
|
|
175
190
|
}
|
|
176
191
|
} else {
|
|
177
192
|
console.warn(
|
|
178
|
-
`[
|
|
193
|
+
`[rango] Dynamic prerender route "${routeName}" has no getParams(), skipping`,
|
|
179
194
|
);
|
|
180
195
|
}
|
|
181
196
|
}
|
|
@@ -186,19 +201,30 @@ export async function expandPrerenderRoutes(
|
|
|
186
201
|
clearInterval(progressInterval);
|
|
187
202
|
const elapsed = ((performance.now() - paramsStart) / 1000).toFixed(1);
|
|
188
203
|
console.log(
|
|
189
|
-
`[
|
|
204
|
+
`[rango] Resolved prerender params: ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`,
|
|
190
205
|
);
|
|
191
206
|
}
|
|
192
207
|
}
|
|
193
208
|
|
|
194
|
-
if (entries.length === 0)
|
|
209
|
+
if (entries.length === 0) {
|
|
210
|
+
debug?.(
|
|
211
|
+
"no prerender entries (done in %sms)",
|
|
212
|
+
(performance.now() - overallStart).toFixed(1),
|
|
213
|
+
);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
195
216
|
|
|
196
217
|
// Determine the max concurrency for the log header
|
|
197
218
|
const maxConcurrency = Math.max(...entries.map((e) => e.concurrency));
|
|
198
219
|
const concurrencyNote =
|
|
199
220
|
maxConcurrency > 1 ? ` (concurrency: ${maxConcurrency})` : "";
|
|
200
221
|
console.log(
|
|
201
|
-
`[
|
|
222
|
+
`[rango] Pre-rendering ${entries.length} URL(s)${concurrencyNote}...`,
|
|
223
|
+
);
|
|
224
|
+
debug?.(
|
|
225
|
+
"prerender loop: %d entries, max concurrency %d",
|
|
226
|
+
entries.length,
|
|
227
|
+
maxConcurrency,
|
|
202
228
|
);
|
|
203
229
|
|
|
204
230
|
const { hashParams } = await rscEnv.runner.import("@rangojs/router/build");
|
|
@@ -206,6 +232,10 @@ export async function expandPrerenderRoutes(
|
|
|
206
232
|
const manifestEntries: Record<string, string> = {};
|
|
207
233
|
let doneCount = 0;
|
|
208
234
|
let skipCount = 0;
|
|
235
|
+
// #587: a render error reaches here (matchForPrerender now re-throws it rather
|
|
236
|
+
// than baking the error boundary). Default "fail" fails the build; "warn" logs
|
|
237
|
+
// and skips baking the URL.
|
|
238
|
+
const prerenderOnError = state.opts?.prerenderOnError ?? "fail";
|
|
209
239
|
const startTotal = performance.now();
|
|
210
240
|
|
|
211
241
|
// Group entries by concurrency for batched rendering.
|
|
@@ -234,7 +264,7 @@ export async function expandPrerenderRoutes(
|
|
|
234
264
|
if (result.passthrough) {
|
|
235
265
|
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
236
266
|
console.log(
|
|
237
|
-
`[
|
|
267
|
+
`[rango] PASS ${entry.urlPath.padEnd(40)} (${elapsed}ms) - live fallback`,
|
|
238
268
|
);
|
|
239
269
|
doneCount++;
|
|
240
270
|
break;
|
|
@@ -255,10 +285,9 @@ export async function expandPrerenderRoutes(
|
|
|
255
285
|
const interceptKey = `${result.routeName}/${paramHash}/i`;
|
|
256
286
|
const interceptValue = JSON.stringify({
|
|
257
287
|
segments: [...result.segments, ...result.interceptSegments],
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
},
|
|
288
|
+
// interceptHandles is the pre-encoded MERGED (main + intercept)
|
|
289
|
+
// handle string (the producer merged before encoding).
|
|
290
|
+
handles: result.interceptHandles ?? "",
|
|
262
291
|
});
|
|
263
292
|
manifestEntries[interceptKey] = stageBuildAssetModule(
|
|
264
293
|
state.projectRoot,
|
|
@@ -268,40 +297,27 @@ export async function expandPrerenderRoutes(
|
|
|
268
297
|
}
|
|
269
298
|
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
270
299
|
console.log(
|
|
271
|
-
`[
|
|
300
|
+
`[rango] OK ${entry.urlPath.padEnd(40)} (${elapsed}ms)`,
|
|
272
301
|
);
|
|
273
302
|
doneCount++;
|
|
274
303
|
break;
|
|
275
304
|
} catch (err: any) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
`[rsc-router] SKIP ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`,
|
|
280
|
-
);
|
|
281
|
-
skipCount++;
|
|
282
|
-
notifyOnError(
|
|
283
|
-
registry,
|
|
284
|
-
err,
|
|
285
|
-
"prerender",
|
|
286
|
-
entry.routeName,
|
|
287
|
-
entry.urlPath,
|
|
288
|
-
true,
|
|
289
|
-
);
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
// Regular error: log, notify, and fail the build
|
|
305
|
+
// Skip, or a render error under prerender.onError "warn": skip the
|
|
306
|
+
// URL (never bake the error page, #587). A render error under the
|
|
307
|
+
// default "fail" re-throws below to fail the build.
|
|
293
308
|
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
294
|
-
|
|
295
|
-
`[rsc-router] FAIL ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`,
|
|
296
|
-
);
|
|
297
|
-
notifyOnError(
|
|
309
|
+
resolvePrerenderError(
|
|
298
310
|
registry,
|
|
299
311
|
err,
|
|
312
|
+
prerenderOnError,
|
|
313
|
+
entry.urlPath.padEnd(40),
|
|
314
|
+
elapsed,
|
|
300
315
|
"prerender",
|
|
301
316
|
entry.routeName,
|
|
302
317
|
entry.urlPath,
|
|
303
318
|
);
|
|
304
|
-
|
|
319
|
+
skipCount++;
|
|
320
|
+
break;
|
|
305
321
|
}
|
|
306
322
|
}
|
|
307
323
|
},
|
|
@@ -315,7 +331,14 @@ export async function expandPrerenderRoutes(
|
|
|
315
331
|
const parts = [`${doneCount} done`];
|
|
316
332
|
if (skipCount > 0) parts.push(`${skipCount} skipped`);
|
|
317
333
|
console.log(
|
|
318
|
-
`[
|
|
334
|
+
`[rango] Pre-render complete: ${parts.join(", ")} (${totalElapsed}ms total)`,
|
|
335
|
+
);
|
|
336
|
+
debug?.(
|
|
337
|
+
"expandPrerenderRoutes done: %d done, %d skipped, %sms (overall %sms)",
|
|
338
|
+
doneCount,
|
|
339
|
+
skipCount,
|
|
340
|
+
totalElapsed,
|
|
341
|
+
(performance.now() - overallStart).toFixed(1),
|
|
319
342
|
);
|
|
320
343
|
}
|
|
321
344
|
|
|
@@ -337,19 +360,24 @@ export async function renderStaticHandlers(
|
|
|
337
360
|
)
|
|
338
361
|
return;
|
|
339
362
|
|
|
363
|
+
const overallStart = debug ? performance.now() : 0;
|
|
364
|
+
debug?.(
|
|
365
|
+
"renderStaticHandlers: start (%d static module(s))",
|
|
366
|
+
state.resolvedStaticModules.size,
|
|
367
|
+
);
|
|
368
|
+
|
|
340
369
|
const manifestEntries: Record<string, string> = {};
|
|
341
370
|
let staticDone = 0;
|
|
342
371
|
let staticSkip = 0;
|
|
343
372
|
let totalStaticCount = 0;
|
|
373
|
+
const prerenderOnError = state.opts?.prerenderOnError ?? "fail";
|
|
344
374
|
|
|
345
375
|
// Count handlers for the log header
|
|
346
376
|
for (const [, exportNames] of state.resolvedStaticModules) {
|
|
347
377
|
totalStaticCount += exportNames.length;
|
|
348
378
|
}
|
|
349
379
|
const startStatic = performance.now();
|
|
350
|
-
console.log(
|
|
351
|
-
`[rsc-router] Rendering ${totalStaticCount} static handler(s)...`,
|
|
352
|
-
);
|
|
380
|
+
console.log(`[rango] Rendering ${totalStaticCount} static handler(s)...`);
|
|
353
381
|
|
|
354
382
|
for (const [moduleId, exportNames] of state.resolvedStaticModules) {
|
|
355
383
|
let mod: any;
|
|
@@ -357,7 +385,7 @@ export async function renderStaticHandlers(
|
|
|
357
385
|
mod = await rscEnv!.runner.import(moduleId);
|
|
358
386
|
} catch (err: any) {
|
|
359
387
|
console.error(
|
|
360
|
-
`[
|
|
388
|
+
`[rango] Failed to import static module ${moduleId}: ${err.message}`,
|
|
361
389
|
);
|
|
362
390
|
notifyOnError(registry, err, "static");
|
|
363
391
|
throw err;
|
|
@@ -382,7 +410,8 @@ export async function renderStaticHandlers(
|
|
|
382
410
|
!state.isBuildMode,
|
|
383
411
|
);
|
|
384
412
|
if (result) {
|
|
385
|
-
|
|
413
|
+
// result.handles is the pre-encoded handle string ("" when none).
|
|
414
|
+
const hasHandles = result.handles !== "";
|
|
386
415
|
const exportValue = hasHandles
|
|
387
416
|
? JSON.stringify(result)
|
|
388
417
|
: JSON.stringify(result.encoded);
|
|
@@ -392,37 +421,29 @@ export async function renderStaticHandlers(
|
|
|
392
421
|
exportValue,
|
|
393
422
|
);
|
|
394
423
|
const elapsed = (performance.now() - startHandler).toFixed(0);
|
|
395
|
-
console.log(
|
|
396
|
-
`[rsc-router] OK ${name.padEnd(40)} (${elapsed}ms)`,
|
|
397
|
-
);
|
|
424
|
+
console.log(`[rango] OK ${name.padEnd(40)} (${elapsed}ms)`);
|
|
398
425
|
staticDone++;
|
|
399
426
|
handled = true;
|
|
400
427
|
break;
|
|
401
428
|
}
|
|
402
429
|
} catch (err: any) {
|
|
403
|
-
|
|
404
|
-
const elapsed = (performance.now() - startHandler).toFixed(0);
|
|
405
|
-
console.log(
|
|
406
|
-
`[rsc-router] SKIP ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`,
|
|
407
|
-
);
|
|
408
|
-
staticSkip++;
|
|
409
|
-
notifyOnError(registry, err, "static", undefined, undefined, true);
|
|
410
|
-
handled = true;
|
|
411
|
-
break;
|
|
412
|
-
}
|
|
413
|
-
// Regular error: log, notify, and fail the build
|
|
430
|
+
// Same Skip/warn/fail policy as the prerender loop (shared helper).
|
|
414
431
|
const elapsed = (performance.now() - startHandler).toFixed(0);
|
|
415
|
-
|
|
416
|
-
|
|
432
|
+
resolvePrerenderError(
|
|
433
|
+
registry,
|
|
434
|
+
err,
|
|
435
|
+
prerenderOnError,
|
|
436
|
+
name.padEnd(40),
|
|
437
|
+
elapsed,
|
|
438
|
+
"static",
|
|
417
439
|
);
|
|
418
|
-
|
|
419
|
-
|
|
440
|
+
staticSkip++;
|
|
441
|
+
handled = true;
|
|
442
|
+
break;
|
|
420
443
|
}
|
|
421
444
|
}
|
|
422
445
|
if (!handled) {
|
|
423
|
-
console.warn(
|
|
424
|
-
`[rsc-router] No router could render static handler "${name}"`,
|
|
425
|
-
);
|
|
446
|
+
console.warn(`[rango] No router could render static handler "${name}"`);
|
|
426
447
|
}
|
|
427
448
|
}
|
|
428
449
|
}
|
|
@@ -434,6 +455,13 @@ export async function renderStaticHandlers(
|
|
|
434
455
|
const staticParts = [`${staticDone} done`];
|
|
435
456
|
if (staticSkip > 0) staticParts.push(`${staticSkip} skipped`);
|
|
436
457
|
console.log(
|
|
437
|
-
`[
|
|
458
|
+
`[rango] Static render complete: ${staticParts.join(", ")} (${totalStaticElapsed}ms total)`,
|
|
459
|
+
);
|
|
460
|
+
debug?.(
|
|
461
|
+
"renderStaticHandlers done: %d done, %d skipped, %sms (overall %sms)",
|
|
462
|
+
staticDone,
|
|
463
|
+
staticSkip,
|
|
464
|
+
totalStaticElapsed,
|
|
465
|
+
(performance.now() - overallStart).toFixed(1),
|
|
438
466
|
);
|
|
439
467
|
}
|
|
@@ -5,13 +5,15 @@
|
|
|
5
5
|
* from discovered router manifests and static source parsing.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { dirname,
|
|
8
|
+
import { dirname, join, resolve } from "node:path";
|
|
9
9
|
import { readFileSync, writeFileSync, existsSync, unlinkSync } from "node:fs";
|
|
10
10
|
import {
|
|
11
11
|
generateRouteTypesSource,
|
|
12
12
|
writeCombinedRouteTypes,
|
|
13
13
|
findRouterFiles,
|
|
14
14
|
buildCombinedRouteMapForRouterFile,
|
|
15
|
+
genFileTsPath,
|
|
16
|
+
resolveSearchSchemas,
|
|
15
17
|
} from "../../build/generate-route-types.js";
|
|
16
18
|
import type { DiscoveryState } from "./state.js";
|
|
17
19
|
import { markSelfGenWrite } from "./self-gen-tracking.js";
|
|
@@ -35,6 +37,22 @@ function filterUserNamedRoutes(
|
|
|
35
37
|
return filtered;
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
// Write a gen file only when content changed, marking the write as
|
|
41
|
+
// self-generated BEFORE writeFileSync so the watcher distinguishes it from a
|
|
42
|
+
// manual edit (the HMR self-gen-loop guard).
|
|
43
|
+
function writeGenFileIfChanged(
|
|
44
|
+
state: DiscoveryState,
|
|
45
|
+
outPath: string,
|
|
46
|
+
source: string,
|
|
47
|
+
opts?: { log?: boolean },
|
|
48
|
+
): void {
|
|
49
|
+
const existing = existsSync(outPath) ? readFileSync(outPath, "utf-8") : null;
|
|
50
|
+
if (existing === source) return;
|
|
51
|
+
markSelfGenWrite(state, outPath, source);
|
|
52
|
+
writeFileSync(outPath, source);
|
|
53
|
+
if (opts?.log) console.log(`[rango] Generated route types -> ${outPath}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
38
56
|
/**
|
|
39
57
|
* Write combined route types for all router files.
|
|
40
58
|
* Only writes when content has changed to avoid triggering HMR loops.
|
|
@@ -48,45 +66,16 @@ export function writeCombinedRouteTypesWithTracking(
|
|
|
48
66
|
findRouterFiles(state.projectRoot, state.scanFilter);
|
|
49
67
|
state.cachedRouterFiles = routerFiles;
|
|
50
68
|
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
preContent.set(outPath, readFileSync(outPath, "utf-8"));
|
|
62
|
-
} catch {
|
|
63
|
-
// File doesn't exist yet — any write is a real change.
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
writeCombinedRouteTypes(state.projectRoot, routerFiles, opts);
|
|
68
|
-
|
|
69
|
-
// Mark only files that were actually written so the watcher can
|
|
70
|
-
// distinguish self-triggered change events from manual edits.
|
|
71
|
-
// Marking unchanged files creates stale entries that interfere with
|
|
72
|
-
// multi-server setups (e.g. shared webServer + isolated HMR server).
|
|
73
|
-
for (const routerFilePath of routerFiles) {
|
|
74
|
-
const routerDir = dirname(routerFilePath);
|
|
75
|
-
const routerBasename = basename(routerFilePath).replace(
|
|
76
|
-
/\.(tsx?|jsx?)$/,
|
|
77
|
-
"",
|
|
78
|
-
);
|
|
79
|
-
const outPath = join(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
80
|
-
if (!existsSync(outPath)) continue;
|
|
81
|
-
try {
|
|
82
|
-
const content = readFileSync(outPath, "utf-8");
|
|
83
|
-
if (content !== preContent.get(outPath)) {
|
|
84
|
-
markSelfGenWrite(state, outPath, content);
|
|
85
|
-
}
|
|
86
|
-
} catch {
|
|
87
|
-
// Ignore transient fs errors while files are being rewritten.
|
|
88
|
-
}
|
|
89
|
-
}
|
|
69
|
+
// Mark each gen file as self-generated BEFORE it is written, via the onWrite
|
|
70
|
+
// callback fired at every writeFileSync site, so the watcher distinguishes
|
|
71
|
+
// self-triggered change events from manual edits. The callback fires only
|
|
72
|
+
// for files actually written, so unchanged files are never marked (stale
|
|
73
|
+
// entries interfere with multi-server setups such as a shared webServer plus
|
|
74
|
+
// an isolated HMR server).
|
|
75
|
+
writeCombinedRouteTypes(state.projectRoot, routerFiles, {
|
|
76
|
+
...opts,
|
|
77
|
+
onWrite: (outPath, content) => markSelfGenWrite(state, outPath, content),
|
|
78
|
+
});
|
|
90
79
|
}
|
|
91
80
|
|
|
92
81
|
/**
|
|
@@ -104,7 +93,7 @@ export function writeRouteTypesFiles(state: DiscoveryState): void {
|
|
|
104
93
|
if (existsSync(oldCombinedPath)) {
|
|
105
94
|
unlinkSync(oldCombinedPath);
|
|
106
95
|
console.log(
|
|
107
|
-
`[
|
|
96
|
+
`[rango] Removed stale combined route types: ${oldCombinedPath}`,
|
|
108
97
|
);
|
|
109
98
|
}
|
|
110
99
|
} catch {}
|
|
@@ -122,40 +111,22 @@ export function writeRouteTypesFiles(state: DiscoveryState): void {
|
|
|
122
111
|
// the wrong location, causing non-deterministic type resolution.
|
|
123
112
|
if (sourceFile.includes("node_modules")) {
|
|
124
113
|
throw new Error(
|
|
125
|
-
`[
|
|
114
|
+
`[rango] Router "${id}" has sourceFile inside node_modules: ${sourceFile}\n` +
|
|
126
115
|
`This means createRouter() stack trace parsing matched a Vite internal frame.\n` +
|
|
127
116
|
`Set an explicit \`id\` on createRouter() or check the call site.`,
|
|
128
117
|
);
|
|
129
118
|
}
|
|
130
119
|
|
|
131
|
-
const
|
|
132
|
-
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
133
|
-
const outPath = join(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
120
|
+
const outPath = genFileTsPath(sourceFile);
|
|
134
121
|
|
|
135
122
|
// Filter out auto-generated route names (e.g. "$path____debug_reverse-test")
|
|
136
123
|
// to match the static parser's output and prevent HMR oscillation.
|
|
137
124
|
const userRoutes = filterUserNamedRoutes(routeManifest);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
(!effectiveSearchSchemas ||
|
|
144
|
-
Object.keys(effectiveSearchSchemas).length === 0) &&
|
|
145
|
-
sourceFile
|
|
146
|
-
) {
|
|
147
|
-
const staticParsed = buildCombinedRouteMapForRouterFile(sourceFile);
|
|
148
|
-
if (Object.keys(staticParsed.searchSchemas).length > 0) {
|
|
149
|
-
const filtered: Record<string, Record<string, string>> = {};
|
|
150
|
-
for (const name of Object.keys(userRoutes)) {
|
|
151
|
-
const schema = staticParsed.searchSchemas[name];
|
|
152
|
-
if (schema) filtered[name] = schema;
|
|
153
|
-
}
|
|
154
|
-
if (Object.keys(filtered).length > 0) {
|
|
155
|
-
effectiveSearchSchemas = filtered;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
125
|
+
const effectiveSearchSchemas = resolveSearchSchemas(
|
|
126
|
+
Object.keys(userRoutes),
|
|
127
|
+
routeSearchSchemas,
|
|
128
|
+
sourceFile,
|
|
129
|
+
);
|
|
159
130
|
|
|
160
131
|
const source = generateRouteTypesSource(
|
|
161
132
|
userRoutes,
|
|
@@ -163,14 +134,7 @@ export function writeRouteTypesFiles(state: DiscoveryState): void {
|
|
|
163
134
|
? effectiveSearchSchemas
|
|
164
135
|
: undefined,
|
|
165
136
|
);
|
|
166
|
-
|
|
167
|
-
? readFileSync(outPath, "utf-8")
|
|
168
|
-
: null;
|
|
169
|
-
if (existing !== source) {
|
|
170
|
-
markSelfGenWrite(state, outPath, source);
|
|
171
|
-
writeFileSync(outPath, source);
|
|
172
|
-
console.log(`[rsc-router] Generated route types -> ${outPath}`);
|
|
173
|
-
}
|
|
137
|
+
writeGenFileIfChanged(state, outPath, source, { log: true });
|
|
174
138
|
}
|
|
175
139
|
}
|
|
176
140
|
|
|
@@ -236,22 +200,14 @@ export function supplementGenFilesWithRuntimeRoutes(
|
|
|
236
200
|
}
|
|
237
201
|
}
|
|
238
202
|
|
|
239
|
-
const
|
|
240
|
-
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
241
|
-
const outPath = join(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
203
|
+
const outPath = genFileTsPath(sourceFile);
|
|
242
204
|
const source = generateRouteTypesSource(
|
|
243
205
|
mergedRoutes,
|
|
244
206
|
Object.keys(mergedSearchSchemas).length > 0
|
|
245
207
|
? mergedSearchSchemas
|
|
246
208
|
: undefined,
|
|
247
209
|
);
|
|
248
|
-
|
|
249
|
-
? readFileSync(outPath, "utf-8")
|
|
250
|
-
: null;
|
|
251
|
-
if (existing !== source) {
|
|
252
|
-
markSelfGenWrite(state, outPath, source);
|
|
253
|
-
writeFileSync(outPath, source);
|
|
254
|
-
}
|
|
210
|
+
writeGenFileIfChanged(state, outPath, source);
|
|
255
211
|
}
|
|
256
212
|
// No manual manifest update needed: the virtual module imports the gen
|
|
257
213
|
// file, so Vite's HMR automatically re-evaluates it with fresh data.
|
|
@@ -22,6 +22,32 @@ export function markSelfGenWrite(
|
|
|
22
22
|
export function consumeSelfGenWrite(
|
|
23
23
|
state: DiscoveryState,
|
|
24
24
|
filePath: string,
|
|
25
|
+
): boolean {
|
|
26
|
+
return checkSelfGenWrite(state, filePath, true);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Non-consuming variant. Used by the `handleHotUpdate` plugin hook to
|
|
31
|
+
* suppress vite's HMR cascade for our own gen-file writes WITHOUT
|
|
32
|
+
* consuming the entry — `consumeSelfGenWrite` (called later from the
|
|
33
|
+
* chokidar `change` handler in `handleRouteFileChange`) still needs to
|
|
34
|
+
* see and consume the same entry to short-circuit our regen path.
|
|
35
|
+
*
|
|
36
|
+
* Both hooks fire for the same file change event:
|
|
37
|
+
* - `handleHotUpdate` runs first (vite's HMR pipeline).
|
|
38
|
+
* - chokidar `change` callback runs after (filesystem watcher).
|
|
39
|
+
*/
|
|
40
|
+
export function peekSelfGenWrite(
|
|
41
|
+
state: DiscoveryState,
|
|
42
|
+
filePath: string,
|
|
43
|
+
): boolean {
|
|
44
|
+
return checkSelfGenWrite(state, filePath, false);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function checkSelfGenWrite(
|
|
48
|
+
state: DiscoveryState,
|
|
49
|
+
filePath: string,
|
|
50
|
+
consume: boolean,
|
|
25
51
|
): boolean {
|
|
26
52
|
const info = state.selfWrittenGenFiles.get(filePath);
|
|
27
53
|
if (!info) return false;
|
|
@@ -33,7 +59,7 @@ export function consumeSelfGenWrite(
|
|
|
33
59
|
const current = readFileSync(filePath, "utf-8");
|
|
34
60
|
const currentHash = createHash("sha256").update(current).digest("hex");
|
|
35
61
|
if (currentHash === info.hash) {
|
|
36
|
-
state.selfWrittenGenFiles.delete(filePath);
|
|
62
|
+
if (consume) state.selfWrittenGenFiles.delete(filePath);
|
|
37
63
|
return true;
|
|
38
64
|
}
|
|
39
65
|
// Hash mismatch: file was changed externally. Keep the entry so a
|
|
@@ -20,6 +20,24 @@ export interface PluginOptions {
|
|
|
20
20
|
buildEnv?: import("../plugin-types.js").BuildEnvOption;
|
|
21
21
|
/** Deployment preset (needed for buildEnv "auto" resolution). */
|
|
22
22
|
preset?: "node" | "cloudflare";
|
|
23
|
+
/**
|
|
24
|
+
* Route-discovery scan filter (glob include/exclude) from rango() config.
|
|
25
|
+
* Compiled into `DiscoveryState.scanFilter` once `projectRoot` is known.
|
|
26
|
+
*/
|
|
27
|
+
discovery?: { include?: string[]; exclude?: string[] };
|
|
28
|
+
/**
|
|
29
|
+
* What to do when a Prerender/Static render throws at build time, from
|
|
30
|
+
* rango({ prerender: { onError } }). "fail" (default) fails the build; "warn"
|
|
31
|
+
* logs and skips baking the URL. See {@link import("../plugin-types.js").RangoOptions}.
|
|
32
|
+
*/
|
|
33
|
+
prerenderOnError?: "fail" | "warn";
|
|
34
|
+
/**
|
|
35
|
+
* Shared context the built-in clientChunks strategy reads. Discovery populates
|
|
36
|
+
* it (registered fallback hashes + single-router name) before the client build
|
|
37
|
+
* invokes the strategy. Present only when the built-in strategy is active
|
|
38
|
+
* (`clientChunks: true`/default); undefined for `false` or a custom function.
|
|
39
|
+
*/
|
|
40
|
+
clientChunkCtx?: import("../utils/client-chunks.js").ClientChunkContext;
|
|
23
41
|
}
|
|
24
42
|
|
|
25
43
|
export interface PrecomputedEntry {
|
|
@@ -45,6 +63,21 @@ export interface DiscoveryState {
|
|
|
45
63
|
projectRoot: string;
|
|
46
64
|
isBuildMode: boolean;
|
|
47
65
|
userResolveAlias: any;
|
|
66
|
+
/**
|
|
67
|
+
* Data-only slice of the user's resolved config (resolve.* incl. native
|
|
68
|
+
* tsconfigPaths, define, oxc) mirrored into the discovery temp server so it
|
|
69
|
+
* resolves and transforms modules the same way the real environment does.
|
|
70
|
+
* See `utils/forward-user-plugins.ts`.
|
|
71
|
+
*/
|
|
72
|
+
userRunnerConfig:
|
|
73
|
+
| import("../utils/forward-user-plugins.js").ForwardedRunnerConfig
|
|
74
|
+
| undefined;
|
|
75
|
+
/**
|
|
76
|
+
* User resolution plugins (resolveId/load), stripped to their resolution
|
|
77
|
+
* surface, forwarded into the discovery temp server. Lets third-party
|
|
78
|
+
* resolvers such as vite-tsconfig-paths participate in discovery.
|
|
79
|
+
*/
|
|
80
|
+
userResolvePlugins: import("vite").Plugin[];
|
|
48
81
|
scanFilter: ScanFilter | undefined;
|
|
49
82
|
cachedRouterFiles: string[] | undefined;
|
|
50
83
|
opts: PluginOptions | undefined;
|
|
@@ -76,6 +109,14 @@ export interface DiscoveryState {
|
|
|
76
109
|
resolvedBuildEnv?: Record<string, unknown>;
|
|
77
110
|
/** Cleanup function for build-time env resources (e.g., miniflare). */
|
|
78
111
|
buildEnvDispose?: (() => Promise<void> | void) | null;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Set when the most recent HMR re-discovery threw. Cleared on the next
|
|
115
|
+
* successful discovery. Surfaced via debug logs so we can detect "manifest
|
|
116
|
+
* frozen at last-good after error → user fix in non-route file → no
|
|
117
|
+
* rediscovery trigger" scenarios.
|
|
118
|
+
*/
|
|
119
|
+
lastDiscoveryError?: { message: string; at: number } | null;
|
|
79
120
|
}
|
|
80
121
|
|
|
81
122
|
export function createDiscoveryState(
|
|
@@ -87,6 +128,8 @@ export function createDiscoveryState(
|
|
|
87
128
|
projectRoot: "",
|
|
88
129
|
isBuildMode: false,
|
|
89
130
|
userResolveAlias: undefined,
|
|
131
|
+
userRunnerConfig: undefined,
|
|
132
|
+
userResolvePlugins: [],
|
|
90
133
|
scanFilter: undefined,
|
|
91
134
|
cachedRouterFiles: undefined,
|
|
92
135
|
opts,
|
|
@@ -113,5 +156,6 @@ export function createDiscoveryState(
|
|
|
113
156
|
devServer: null,
|
|
114
157
|
selfWrittenGenFiles: new Map(),
|
|
115
158
|
SELF_WRITE_WINDOW_MS: 5_000,
|
|
159
|
+
lastDiscoveryError: null,
|
|
116
160
|
};
|
|
117
161
|
}
|