@rangojs/router 0.0.0-experimental.bd6e11bc → 0.0.0-experimental.bdaf10aa
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 -4
- package/README.md +296 -887
- package/dist/bin/rango.js +459 -91
- package/dist/testing/vitest.js +36 -2
- package/dist/vite/index.js +1708 -414
- package/package.json +35 -10
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +82 -5
- package/skills/bundle-analysis/SKILL.md +2 -2
- package/skills/cache-guide/SKILL.md +14 -9
- package/skills/caching/SKILL.md +221 -12
- package/skills/catalog.json +271 -0
- package/skills/comparison/SKILL.md +50 -0
- package/skills/comparison/agents/openai.yaml +4 -0
- package/skills/comparison/references/framework-comparison.md +837 -0
- package/skills/composability/SKILL.md +83 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +5 -3
- package/skills/defer-hydration/SKILL.md +235 -0
- package/skills/document-cache/SKILL.md +11 -3
- package/skills/fonts/SKILL.md +1 -1
- package/skills/handler-use/SKILL.md +9 -9
- package/skills/hooks/SKILL.md +73 -900
- package/skills/hooks/data.md +273 -0
- package/skills/hooks/handle-and-actions.md +103 -0
- package/skills/hooks/navigation.md +110 -0
- package/skills/hooks/outlets.md +41 -0
- package/skills/hooks/state.md +228 -0
- package/skills/hooks/urls.md +135 -0
- package/skills/host-router/SKILL.md +84 -7
- package/skills/i18n/SKILL.md +1 -1
- package/skills/intercept/SKILL.md +51 -17
- package/skills/layout/SKILL.md +38 -16
- package/skills/links/SKILL.md +1 -1
- package/skills/loader/SKILL.md +48 -20
- package/skills/middleware/SKILL.md +11 -5
- package/skills/migrate-nextjs/SKILL.md +203 -20
- package/skills/migrate-react-router/SKILL.md +59 -675
- package/skills/migrate-react-router/cloudflare-workers.md +129 -0
- package/skills/migrate-react-router/component-migration.md +196 -0
- package/skills/migrate-react-router/data-and-actions.md +225 -0
- package/skills/migrate-react-router/route-mapping.md +271 -0
- package/skills/mime-routes/SKILL.md +3 -3
- package/skills/observability/SKILL.md +70 -5
- package/skills/parallel/SKILL.md +32 -8
- package/skills/ppr/SKILL.md +622 -0
- package/skills/prerender/SKILL.md +59 -28
- package/skills/rango/SKILL.md +124 -50
- package/skills/response-routes/SKILL.md +78 -46
- package/skills/route/SKILL.md +85 -6
- package/skills/router-setup/SKILL.md +41 -6
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +28 -3
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +1 -1
- package/skills/tailwind/SKILL.md +28 -4
- package/skills/testing/SKILL.md +68 -654
- 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 +131 -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 +85 -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/theme/SKILL.md +1 -1
- package/skills/typesafety/SKILL.md +45 -918
- package/skills/typesafety/env-and-bindings.md +254 -0
- package/skills/typesafety/generated-files-and-cli.md +335 -0
- package/skills/typesafety/params-and-search.md +153 -0
- package/skills/typesafety/route-types.md +209 -0
- package/skills/use-cache/SKILL.md +47 -17
- package/skills/vercel/SKILL.md +128 -0
- package/skills/view-transitions/SKILL.md +44 -1
- package/src/__augment-tests__/augmented.check.ts +2 -3
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +1 -1
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +14 -27
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +178 -100
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/logging.ts +28 -0
- package/src/browser/merge-segment-loaders.ts +6 -4
- package/src/browser/navigation-bridge.ts +81 -68
- package/src/browser/navigation-client.ts +115 -70
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +153 -88
- package/src/browser/navigation-transaction.ts +0 -32
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +157 -144
- package/src/browser/prefetch/cache.ts +148 -81
- package/src/browser/prefetch/fetch.ts +231 -51
- package/src/browser/prefetch/queue.ts +25 -7
- package/src/browser/rango-state.ts +157 -115
- package/src/browser/react/Link.tsx +40 -7
- package/src/browser/react/NavigationProvider.tsx +140 -99
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +17 -2
- package/src/browser/react/index.ts +0 -51
- package/src/browser/react/location-state-shared.ts +14 -15
- package/src/browser/react/location-state.ts +0 -1
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +0 -5
- 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 +0 -2
- package/src/browser/react/use-router.ts +6 -4
- 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 +74 -8
- package/src/browser/rsc-router.tsx +97 -22
- package/src/browser/scroll-restoration.ts +15 -8
- package/src/browser/segment-reconciler.ts +31 -21
- package/src/browser/server-action-bridge.ts +216 -38
- package/src/browser/types.ts +94 -22
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/generate-manifest.ts +155 -131
- package/src/build/generate-route-types.ts +1 -1
- package/src/build/index.ts +11 -5
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +152 -22
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +12 -1
- package/src/build/route-types/include-resolution.ts +455 -61
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +15 -2
- package/src/build/route-types/router-processing.ts +77 -41
- package/src/build/route-types/source-scan.ts +105 -7
- package/src/build/runtime-discovery.ts +4 -1
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +58 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +454 -101
- package/src/cache/cache-scope.ts +159 -54
- package/src/cache/cache-tag.ts +149 -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 +2170 -377
- 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 +126 -41
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +23 -20
- package/src/cache/memory-segment-store.ts +243 -37
- package/src/cache/profile-registry.ts +46 -31
- package/src/cache/read-through-swr.ts +56 -12
- package/src/cache/segment-codec.ts +13 -21
- package/src/cache/shell-snapshot.ts +417 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +194 -99
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1132 -0
- package/src/client.rsc.tsx +39 -22
- package/src/client.tsx +28 -58
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +108 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +13 -1
- package/src/decode-loader-results.ts +18 -2
- package/src/defer.ts +185 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +0 -3
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +57 -40
- package/src/handles/MetaTags.tsx +24 -53
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +35 -8
- package/src/handles/deferred-resolution.ts +127 -0
- package/src/handles/is-thenable.ts +18 -0
- package/src/handles/meta.ts +14 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +13 -22
- package/src/host/index.ts +7 -0
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +1 -65
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +6 -2
- package/src/href-client.ts +7 -12
- package/src/index.rsc.ts +88 -8
- package/src/index.ts +90 -16
- package/src/internal-debug.ts +11 -10
- package/src/loader.rsc.ts +19 -9
- package/src/loader.ts +12 -4
- 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 +75 -7
- package/src/redirect-origin.ts +114 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +25 -0
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +13 -49
- package/src/route-definition/dsl-helpers.ts +60 -53
- package/src/route-definition/helper-factories.ts +0 -2
- package/src/route-definition/helpers-types.ts +46 -46
- package/src/route-definition/index.ts +1 -2
- package/src/route-definition/redirect.ts +44 -11
- package/src/route-definition/resolve-handler-use.ts +6 -1
- package/src/route-definition/use-item-types.ts +3 -6
- package/src/route-map-builder.ts +41 -20
- package/src/route-types.ts +0 -5
- package/src/router/content-negotiation.ts +58 -23
- package/src/router/error-handling.ts +44 -17
- package/src/router/find-match.ts +129 -30
- package/src/router/handler-context.ts +6 -1
- package/src/router/instrument.ts +355 -0
- package/src/router/intercept-resolution.ts +35 -2
- package/src/router/lazy-includes.ts +79 -56
- package/src/router/loader-resolution.ts +151 -73
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +74 -40
- package/src/router/match-api.ts +76 -52
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +181 -178
- package/src/router/match-middleware/background-revalidation.ts +40 -24
- package/src/router/match-middleware/cache-lookup.ts +115 -194
- package/src/router/match-middleware/cache-store.ts +61 -50
- 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 +36 -67
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +0 -116
- package/src/router/middleware.ts +231 -120
- package/src/router/navigation-snapshot.ts +7 -56
- package/src/router/params-util.ts +23 -0
- package/src/router/parse-pattern.ts +115 -0
- package/src/router/pattern-matching.ts +99 -152
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +111 -66
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +47 -42
- package/src/router/revalidation.ts +75 -81
- package/src/router/route-snapshot.ts +14 -3
- package/src/router/router-context.ts +6 -29
- package/src/router/router-interfaces.ts +70 -8
- package/src/router/router-options.ts +126 -4
- package/src/router/segment-resolution/fresh.ts +104 -80
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +155 -39
- package/src/router/segment-resolution/loader-mask.ts +60 -0
- package/src/router/segment-resolution/loader-snapshot.ts +259 -0
- package/src/router/segment-resolution/mask-nested.ts +83 -0
- package/src/router/segment-resolution/revalidation.ts +215 -304
- 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 +35 -15
- 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 +54 -35
- package/src/router/telemetry-otel.ts +160 -200
- package/src/router/telemetry.ts +9 -23
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +215 -0
- package/src/router/trie-matching.ts +171 -64
- package/src/router/types.ts +1 -63
- package/src/router/url-params.ts +13 -5
- package/src/router.ts +119 -48
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +1 -0
- package/src/rsc/handler.ts +267 -152
- package/src/rsc/helpers.ts +78 -4
- package/src/rsc/index.ts +1 -4
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +114 -38
- package/src/rsc/manifest-init.ts +29 -42
- package/src/rsc/nonce.ts +10 -1
- package/src/rsc/origin-guard.ts +11 -15
- package/src/rsc/progressive-enhancement.ts +120 -13
- package/src/rsc/redirect-guard.ts +100 -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 +58 -141
- package/src/rsc/rsc-rendering.ts +492 -49
- package/src/rsc/runtime-warnings.ts +14 -0
- package/src/rsc/server-action.ts +268 -82
- package/src/rsc/shell-capture.ts +1190 -0
- package/src/rsc/shell-serve.ts +181 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +45 -3
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +31 -26
- package/src/segment-loader-promise.ts +49 -4
- package/src/segment-system.tsx +260 -95
- package/src/server/context.ts +99 -9
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +125 -2
- package/src/server/handle-store.ts +21 -38
- package/src/server/loader-registry.ts +33 -42
- package/src/server/request-context.ts +379 -138
- package/src/ssr/index.tsx +491 -182
- package/src/ssr/inject-rsc-eager.ts +167 -0
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +44 -48
- package/src/testing/collect-handle.ts +14 -31
- package/src/testing/dispatch.ts +533 -160
- package/src/testing/e2e/fixture.ts +45 -11
- package/src/testing/e2e/index.ts +1 -22
- package/src/testing/e2e/matchers.ts +0 -16
- package/src/testing/e2e/parity.ts +85 -4
- package/src/testing/e2e/server.ts +12 -0
- package/src/testing/flight-matchers.ts +7 -14
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +36 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +30 -0
- package/src/testing/flight.ts +145 -70
- package/src/testing/generated-routes.ts +26 -50
- package/src/testing/index.ts +18 -19
- package/src/testing/internal/context.ts +184 -68
- 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 +134 -115
- package/src/testing/run-loader.ts +140 -51
- package/src/testing/run-middleware.ts +59 -33
- package/src/testing/run-transition-when.ts +164 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +1 -1
- package/src/testing/vitest-stubs/cloudflare-workers.ts +1 -1
- package/src/testing/vitest.ts +138 -16
- package/src/theme/ThemeProvider.tsx +56 -84
- 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 +15 -15
- package/src/types/handler-context.ts +45 -15
- package/src/types/index.ts +2 -10
- package/src/types/loader-types.ts +6 -3
- package/src/types/request-scope.ts +8 -22
- package/src/types/route-config.ts +20 -52
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +100 -13
- package/src/urls/include-helper.ts +10 -12
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +2 -8
- package/src/urls/path-helper-types.ts +52 -14
- package/src/urls/path-helper.ts +5 -54
- package/src/urls/pattern-types.ts +36 -0
- package/src/urls/type-extraction.ts +76 -42
- package/src/urls/urls-function.ts +0 -14
- package/src/use-loader.tsx +0 -186
- package/src/vercel/index.ts +11 -0
- package/src/vercel/tracing.ts +88 -0
- package/src/vite/discovery/bundle-postprocess.ts +2 -1
- package/src/vite/discovery/dev-prerender-cache.ts +117 -0
- package/src/vite/discovery/discover-routers.ts +34 -43
- package/src/vite/discovery/discovery-errors.ts +61 -0
- package/src/vite/discovery/prerender-collection.ts +33 -46
- package/src/vite/discovery/state.ts +12 -1
- package/src/vite/discovery/virtual-module-codegen.ts +1 -11
- package/src/vite/index.ts +9 -0
- package/src/vite/inject-client-debug.ts +88 -0
- package/src/vite/plugin-types.ts +143 -10
- package/src/vite/plugins/cjs-to-esm.ts +8 -12
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +0 -10
- package/src/vite/plugins/cloudflare-protocol-stub.ts +0 -20
- package/src/vite/plugins/expose-action-id.ts +2 -73
- package/src/vite/plugins/expose-id-utils.ts +85 -56
- package/src/vite/plugins/expose-ids/export-analysis.ts +30 -43
- package/src/vite/plugins/expose-ids/handler-transform.ts +5 -31
- package/src/vite/plugins/expose-ids/loader-transform.ts +12 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +98 -26
- package/src/vite/plugins/expose-internal-ids.ts +10 -1
- package/src/vite/plugins/performance-tracks.ts +0 -3
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +21 -46
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +22 -27
- package/src/vite/plugins/version-plugin.ts +6 -66
- package/src/vite/plugins/virtual-entries.ts +137 -26
- package/src/vite/rango.ts +146 -135
- package/src/vite/router-discovery.ts +189 -48
- package/src/vite/utils/ast-handler-extract.ts +11 -20
- package/src/vite/utils/bundle-analysis.ts +6 -13
- package/src/vite/utils/client-chunks.ts +0 -6
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +0 -22
- package/src/vite/utils/manifest-utils.ts +4 -75
- package/src/vite/utils/package-resolution.ts +1 -73
- package/src/vite/utils/prerender-utils.ts +71 -44
- package/src/vite/utils/shared-utils.ts +55 -37
- 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
package/dist/vite/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/vite/rango.ts
|
|
2
|
-
import { readFileSync as readFileSync7 } from "node:fs";
|
|
3
|
-
import { resolve as
|
|
2
|
+
import { readFileSync as readFileSync7, existsSync as existsSync8 } from "node:fs";
|
|
3
|
+
import { resolve as resolve11 } from "node:path";
|
|
4
4
|
|
|
5
5
|
// src/vite/plugins/expose-action-id.ts
|
|
6
6
|
import MagicString from "magic-string";
|
|
@@ -10,6 +10,13 @@ import fs from "node:fs";
|
|
|
10
10
|
// src/vite/plugins/expose-id-utils.ts
|
|
11
11
|
import path from "node:path";
|
|
12
12
|
import crypto from "node:crypto";
|
|
13
|
+
|
|
14
|
+
// src/regex-escape.ts
|
|
15
|
+
function escapeRegExp(input) {
|
|
16
|
+
return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// src/vite/plugins/expose-id-utils.ts
|
|
13
20
|
function normalizePath(p) {
|
|
14
21
|
return p.split(path.sep).join("/");
|
|
15
22
|
}
|
|
@@ -158,7 +165,9 @@ function countArgs(code, startPos, endPos) {
|
|
|
158
165
|
while (i < endPos) {
|
|
159
166
|
const skipped = skipStringOrComment(code, i);
|
|
160
167
|
if (skipped > i) {
|
|
161
|
-
|
|
168
|
+
const ch = code[i];
|
|
169
|
+
const isComment = ch === "/" && i + 1 < code.length && (code[i + 1] === "/" || code[i + 1] === "*");
|
|
170
|
+
if (!isComment) hasContent = true;
|
|
162
171
|
i = skipped;
|
|
163
172
|
continue;
|
|
164
173
|
}
|
|
@@ -187,8 +196,59 @@ function findStatementEnd(code, pos) {
|
|
|
187
196
|
}
|
|
188
197
|
return i;
|
|
189
198
|
}
|
|
190
|
-
function
|
|
191
|
-
|
|
199
|
+
function findCallParenAfterGenerics(code, afterCalleeIndex) {
|
|
200
|
+
let i = afterCalleeIndex;
|
|
201
|
+
while (i < code.length) {
|
|
202
|
+
const skipped = skipStringOrComment(code, i);
|
|
203
|
+
if (skipped > i) {
|
|
204
|
+
i = skipped;
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (/\s/.test(code[i])) {
|
|
208
|
+
i++;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
if (i >= code.length) return -1;
|
|
214
|
+
if (code[i] === "(") return i;
|
|
215
|
+
if (code[i] === "<") {
|
|
216
|
+
let depth = 0;
|
|
217
|
+
while (i < code.length) {
|
|
218
|
+
const skipped = skipStringOrComment(code, i);
|
|
219
|
+
if (skipped > i) {
|
|
220
|
+
i = skipped;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
const ch = code[i];
|
|
224
|
+
if (ch === "<") {
|
|
225
|
+
depth++;
|
|
226
|
+
} else if (ch === ">") {
|
|
227
|
+
depth--;
|
|
228
|
+
if (depth === 0) {
|
|
229
|
+
i++;
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
i++;
|
|
234
|
+
}
|
|
235
|
+
if (depth !== 0) return -1;
|
|
236
|
+
while (i < code.length) {
|
|
237
|
+
const skipped = skipStringOrComment(code, i);
|
|
238
|
+
if (skipped > i) {
|
|
239
|
+
i = skipped;
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (/\s/.test(code[i])) {
|
|
243
|
+
i++;
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
if (i < code.length && code[i] === "(") return i;
|
|
249
|
+
return -1;
|
|
250
|
+
}
|
|
251
|
+
return -1;
|
|
192
252
|
}
|
|
193
253
|
|
|
194
254
|
// src/vite/debug.ts
|
|
@@ -431,7 +491,6 @@ function exposeActionId() {
|
|
|
431
491
|
counterTransform?.record(id, performance.now() - start);
|
|
432
492
|
}
|
|
433
493
|
},
|
|
434
|
-
// Build mode: renderChunk runs after all transforms and bundling complete
|
|
435
494
|
renderChunk(code, chunk) {
|
|
436
495
|
const start = counterRender ? performance.now() : 0;
|
|
437
496
|
try {
|
|
@@ -473,10 +532,10 @@ import path4 from "node:path";
|
|
|
473
532
|
function isDirectivePrologueStatement(node) {
|
|
474
533
|
return node?.type === "ExpressionStatement" && typeof node.directive === "string";
|
|
475
534
|
}
|
|
476
|
-
function findImportInsertionPos(code,
|
|
535
|
+
function findImportInsertionPos(code, parseAst5) {
|
|
477
536
|
let program;
|
|
478
537
|
try {
|
|
479
|
-
program =
|
|
538
|
+
program = parseAst5(code, { lang: "tsx" });
|
|
480
539
|
} catch {
|
|
481
540
|
return 0;
|
|
482
541
|
}
|
|
@@ -513,10 +572,10 @@ function walkNode(node, parent, ancestors, enter) {
|
|
|
513
572
|
}
|
|
514
573
|
ancestors.pop();
|
|
515
574
|
}
|
|
516
|
-
function findHandlerCalls(code, fnName,
|
|
575
|
+
function findHandlerCalls(code, fnName, parseAst5) {
|
|
517
576
|
let program;
|
|
518
577
|
try {
|
|
519
|
-
program =
|
|
578
|
+
program = parseAst5(code, { lang: "tsx" });
|
|
520
579
|
} catch {
|
|
521
580
|
return [];
|
|
522
581
|
}
|
|
@@ -588,18 +647,18 @@ function getImportedLocalNamesFromProgram(program, importedName) {
|
|
|
588
647
|
}
|
|
589
648
|
return localNames;
|
|
590
649
|
}
|
|
591
|
-
function getImportedLocalNames(code, importedName,
|
|
650
|
+
function getImportedLocalNames(code, importedName, parseAst5) {
|
|
592
651
|
try {
|
|
593
|
-
const program =
|
|
652
|
+
const program = parseAst5(code, { lang: "tsx" });
|
|
594
653
|
return getImportedLocalNamesFromProgram(program, importedName);
|
|
595
654
|
} catch {
|
|
596
655
|
return /* @__PURE__ */ new Set();
|
|
597
656
|
}
|
|
598
657
|
}
|
|
599
|
-
function extractImportDeclarations(code,
|
|
658
|
+
function extractImportDeclarations(code, parseAst5) {
|
|
600
659
|
let program;
|
|
601
660
|
try {
|
|
602
|
-
program =
|
|
661
|
+
program = parseAst5(code, { lang: "tsx" });
|
|
603
662
|
} catch {
|
|
604
663
|
return [];
|
|
605
664
|
}
|
|
@@ -623,13 +682,18 @@ function isInertExpression(node) {
|
|
|
623
682
|
(e) => e === null || isInertExpression(e)
|
|
624
683
|
);
|
|
625
684
|
case "ObjectExpression":
|
|
626
|
-
return (node.properties ?? []).every(
|
|
627
|
-
(p
|
|
628
|
-
|
|
685
|
+
return (node.properties ?? []).every((p) => {
|
|
686
|
+
if (p.type === "SpreadElement" || p.type === "RestElement") {
|
|
687
|
+
return isInertExpression(p.argument);
|
|
688
|
+
}
|
|
689
|
+
return p.type === "Property" && (!p.computed || isInertExpression(p.key)) && isInertExpression(p.value);
|
|
690
|
+
});
|
|
629
691
|
case "UnaryExpression":
|
|
630
692
|
return isInertExpression(node.argument);
|
|
631
693
|
case "BinaryExpression":
|
|
632
694
|
return isInertExpression(node.left) && isInertExpression(node.right);
|
|
695
|
+
case "LogicalExpression":
|
|
696
|
+
return isInertExpression(node.left) && isInertExpression(node.right);
|
|
633
697
|
case "ConditionalExpression":
|
|
634
698
|
return isInertExpression(node.test) && isInertExpression(node.consequent) && isInertExpression(node.alternate);
|
|
635
699
|
case "SpreadElement":
|
|
@@ -651,10 +715,10 @@ function isSafeVariableDeclaration(node, handlerNames) {
|
|
|
651
715
|
(d) => isSafeDeclaratorInit(d.init) && !(d.init?.type === "CallExpression" && d.init.callee?.type === "Identifier" && handlerNames.has(d.init.callee.name))
|
|
652
716
|
);
|
|
653
717
|
}
|
|
654
|
-
function extractModuleLevelDeclarations(code,
|
|
718
|
+
function extractModuleLevelDeclarations(code, parseAst5, handlerNames) {
|
|
655
719
|
let program;
|
|
656
720
|
try {
|
|
657
|
-
program =
|
|
721
|
+
program = parseAst5(code, { lang: "tsx" });
|
|
658
722
|
} catch {
|
|
659
723
|
return [];
|
|
660
724
|
}
|
|
@@ -685,17 +749,17 @@ function extractModuleLevelDeclarations(code, parseAst4, handlerNames) {
|
|
|
685
749
|
}
|
|
686
750
|
return declarations;
|
|
687
751
|
}
|
|
688
|
-
function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtualRegistry, moduleId,
|
|
689
|
-
const sites = findHandlerCalls(code, fnName,
|
|
752
|
+
function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtualRegistry, moduleId, parseAst5) {
|
|
753
|
+
const sites = findHandlerCalls(code, fnName, parseAst5);
|
|
690
754
|
const inlineSites = sites.filter((site) => site.exportInfo === null);
|
|
691
755
|
if (inlineSites.length === 0) return false;
|
|
692
|
-
const imports = extractImportDeclarations(code,
|
|
693
|
-
const staticNames = getImportedLocalNames(code, "Static",
|
|
694
|
-
const prerenderNames = getImportedLocalNames(code, "Prerender",
|
|
756
|
+
const imports = extractImportDeclarations(code, parseAst5);
|
|
757
|
+
const staticNames = getImportedLocalNames(code, "Static", parseAst5);
|
|
758
|
+
const prerenderNames = getImportedLocalNames(code, "Prerender", parseAst5);
|
|
695
759
|
const handlerNames = /* @__PURE__ */ new Set([...staticNames, ...prerenderNames]);
|
|
696
760
|
const declarations = extractModuleLevelDeclarations(
|
|
697
761
|
code,
|
|
698
|
-
|
|
762
|
+
parseAst5,
|
|
699
763
|
handlerNames
|
|
700
764
|
);
|
|
701
765
|
const importStatements = [];
|
|
@@ -718,7 +782,7 @@ function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtu
|
|
|
718
782
|
}
|
|
719
783
|
if (importStatements.length > 0) {
|
|
720
784
|
const importBlock = importStatements.join("\n") + "\n";
|
|
721
|
-
const insertionPos = findImportInsertionPos(code,
|
|
785
|
+
const insertionPos = findImportInsertionPos(code, parseAst5);
|
|
722
786
|
if (insertionPos === 0) {
|
|
723
787
|
s.prepend(importBlock);
|
|
724
788
|
} else {
|
|
@@ -751,25 +815,55 @@ function isLineTerminator(ch) {
|
|
|
751
815
|
const c = ch.charCodeAt(0);
|
|
752
816
|
return c === 10 || c === 13 || c === 8232 || c === 8233;
|
|
753
817
|
}
|
|
818
|
+
var REGEX_PRECEDING_KEYWORDS = /* @__PURE__ */ new Set([
|
|
819
|
+
"return",
|
|
820
|
+
"typeof",
|
|
821
|
+
"instanceof",
|
|
822
|
+
"in",
|
|
823
|
+
"of",
|
|
824
|
+
"new",
|
|
825
|
+
"delete",
|
|
826
|
+
"void",
|
|
827
|
+
"do",
|
|
828
|
+
"else",
|
|
829
|
+
"yield",
|
|
830
|
+
"await",
|
|
831
|
+
"case",
|
|
832
|
+
"throw"
|
|
833
|
+
]);
|
|
834
|
+
function isRegexPositionAt(code, slashPos, prevChar) {
|
|
835
|
+
if (prevChar === void 0) return true;
|
|
836
|
+
if (prevChar === ")" || prevChar === "]" || prevChar === "}") return false;
|
|
837
|
+
if (!/[\w$]/.test(prevChar)) return true;
|
|
838
|
+
let k = slashPos - 1;
|
|
839
|
+
while (k >= 0 && /\s/.test(code[k])) k--;
|
|
840
|
+
const wordEnd = k + 1;
|
|
841
|
+
while (k >= 0 && /[\w$]/.test(code[k])) k--;
|
|
842
|
+
return REGEX_PRECEDING_KEYWORDS.has(code.slice(k + 1, wordEnd));
|
|
843
|
+
}
|
|
754
844
|
function makeCodeClassifier(code) {
|
|
755
845
|
const n = code.length;
|
|
756
846
|
let i = 0;
|
|
757
847
|
let skipStart = -1;
|
|
758
848
|
let skipEnd = -1;
|
|
849
|
+
let lastSig;
|
|
759
850
|
return (q) => {
|
|
760
851
|
if (q >= skipStart && q < skipEnd) return false;
|
|
761
852
|
while (i < n && i <= q) {
|
|
762
853
|
const c = code[i];
|
|
763
854
|
const d = i + 1 < n ? code[i + 1] : "";
|
|
764
855
|
let end = -1;
|
|
856
|
+
let transparent = false;
|
|
765
857
|
if (c === "/" && d === "/") {
|
|
766
858
|
let j = i + 2;
|
|
767
859
|
while (j < n && !isLineTerminator(code[j])) j++;
|
|
768
860
|
end = j;
|
|
861
|
+
transparent = true;
|
|
769
862
|
} else if (c === "/" && d === "*") {
|
|
770
863
|
let j = i + 2;
|
|
771
864
|
while (j < n && !(code[j] === "*" && code[j + 1] === "/")) j++;
|
|
772
865
|
end = Math.min(n, j + 2);
|
|
866
|
+
transparent = true;
|
|
773
867
|
} else if (c === '"' || c === "'" || c === "`") {
|
|
774
868
|
let j = i + 1;
|
|
775
869
|
while (j < n) {
|
|
@@ -784,6 +878,29 @@ function makeCodeClassifier(code) {
|
|
|
784
878
|
j++;
|
|
785
879
|
}
|
|
786
880
|
end = j;
|
|
881
|
+
} else if (c === "/" && d !== "/" && d !== "*" && isRegexPositionAt(code, i, lastSig)) {
|
|
882
|
+
let j = i + 1;
|
|
883
|
+
let inClass = false;
|
|
884
|
+
let closed = false;
|
|
885
|
+
while (j < n && !isLineTerminator(code[j])) {
|
|
886
|
+
const r = code[j];
|
|
887
|
+
if (r === "\\") {
|
|
888
|
+
j += 2;
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
if (r === "[") inClass = true;
|
|
892
|
+
else if (r === "]") inClass = false;
|
|
893
|
+
else if (r === "/" && !inClass) {
|
|
894
|
+
j++;
|
|
895
|
+
closed = true;
|
|
896
|
+
break;
|
|
897
|
+
}
|
|
898
|
+
j++;
|
|
899
|
+
}
|
|
900
|
+
if (closed) {
|
|
901
|
+
while (j < n && /[a-z]/.test(code[j])) j++;
|
|
902
|
+
end = j;
|
|
903
|
+
}
|
|
787
904
|
}
|
|
788
905
|
if (end >= 0) {
|
|
789
906
|
if (q < end) {
|
|
@@ -792,7 +909,9 @@ function makeCodeClassifier(code) {
|
|
|
792
909
|
return false;
|
|
793
910
|
}
|
|
794
911
|
i = end;
|
|
912
|
+
if (!transparent) lastSig = "x";
|
|
795
913
|
} else {
|
|
914
|
+
if (!/\s/.test(c)) lastSig = c;
|
|
796
915
|
i++;
|
|
797
916
|
}
|
|
798
917
|
}
|
|
@@ -851,13 +970,23 @@ function isExportOnlyFile(code, bindings) {
|
|
|
851
970
|
return true;
|
|
852
971
|
}
|
|
853
972
|
function createCallPattern(fnNames) {
|
|
854
|
-
return new RegExp(
|
|
855
|
-
|
|
856
|
-
|
|
973
|
+
return new RegExp(`\\b(?:${fnNames.map(escapeRegExp).join("|")})\\b`, "g");
|
|
974
|
+
}
|
|
975
|
+
function createCallStartIndices(code, fnNames) {
|
|
976
|
+
return codeMatchIndices(code, createCallPattern(fnNames)).filter(
|
|
977
|
+
(index) => findCallParenAfterGenerics(
|
|
978
|
+
code,
|
|
979
|
+
index + matchedNameLength(code, index)
|
|
980
|
+
) !== -1
|
|
857
981
|
);
|
|
858
982
|
}
|
|
983
|
+
function matchedNameLength(code, index) {
|
|
984
|
+
let i = index;
|
|
985
|
+
while (i < code.length && /[A-Za-z0-9_$]/.test(code[i])) i++;
|
|
986
|
+
return i - index;
|
|
987
|
+
}
|
|
859
988
|
function countCreateCallsForNames(code, fnNames) {
|
|
860
|
-
return
|
|
989
|
+
return createCallStartIndices(code, fnNames).length;
|
|
861
990
|
}
|
|
862
991
|
function offsetToLineColumn(code, index) {
|
|
863
992
|
let line = 1;
|
|
@@ -873,7 +1002,7 @@ function offsetToLineColumn(code, index) {
|
|
|
873
1002
|
}
|
|
874
1003
|
function findUnsupportedCreateCallSites(code, fnNames, supportedBindings) {
|
|
875
1004
|
const supported = new Set(supportedBindings.map((b) => b.callExprStart));
|
|
876
|
-
return
|
|
1005
|
+
return createCallStartIndices(code, fnNames).filter((index) => !supported.has(index)).map((index) => offsetToLineColumn(code, index));
|
|
877
1006
|
}
|
|
878
1007
|
function getImportedFnNames(code, importedName) {
|
|
879
1008
|
const importPattern = /import\s*\{([^}]*)\}\s*from\s*["']@rangojs\/router(?:\/[^"']*)?["']/g;
|
|
@@ -1067,11 +1196,13 @@ function generateClientLoaderStubs(bindings, code, filePath, isBuild) {
|
|
|
1067
1196
|
if (!isExportOnlyFile(code, bindings)) return null;
|
|
1068
1197
|
const lines = [];
|
|
1069
1198
|
for (const binding of bindings) {
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1199
|
+
const primaryName = binding.exportNames[0];
|
|
1200
|
+
const loaderId = makeStubId(filePath, primaryName, isBuild);
|
|
1201
|
+
lines.push(
|
|
1202
|
+
`export const ${primaryName} = { __brand: "loader", $$id: "${loaderId}" };`
|
|
1203
|
+
);
|
|
1204
|
+
for (const alias of binding.exportNames.slice(1)) {
|
|
1205
|
+
lines.push(`export const ${alias} = ${primaryName};`);
|
|
1075
1206
|
}
|
|
1076
1207
|
}
|
|
1077
1208
|
return { code: lines.join("\n") + "\n" };
|
|
@@ -1092,22 +1223,13 @@ ${binding.localName}.$$id = "${loaderId}";`;
|
|
|
1092
1223
|
}
|
|
1093
1224
|
|
|
1094
1225
|
// src/vite/plugins/expose-ids/handler-transform.ts
|
|
1095
|
-
function
|
|
1096
|
-
const content = code.slice(startPos, endPos).trim();
|
|
1097
|
-
return { hasArgs: content.length > 0 };
|
|
1098
|
-
}
|
|
1099
|
-
function transformHandles(bindings, s, code, filePath, isBuild) {
|
|
1226
|
+
function transformHandles(bindings, s, filePath, isBuild) {
|
|
1100
1227
|
let hasChanges = false;
|
|
1101
1228
|
for (const binding of bindings) {
|
|
1102
1229
|
const exportName = binding.exportNames[0];
|
|
1103
|
-
const args = analyzeCreateHandleArgs(
|
|
1104
|
-
code,
|
|
1105
|
-
binding.callOpenParenPos + 1,
|
|
1106
|
-
binding.callCloseParenPos
|
|
1107
|
-
);
|
|
1108
1230
|
const handleId = makeStubId(filePath, exportName, isBuild);
|
|
1109
1231
|
let paramInjection;
|
|
1110
|
-
if (
|
|
1232
|
+
if (binding.argCount === 0) {
|
|
1111
1233
|
paramInjection = `undefined, "${handleId}"`;
|
|
1112
1234
|
} else {
|
|
1113
1235
|
paramInjection = `, "${handleId}"`;
|
|
@@ -1182,36 +1304,68 @@ import MagicString2 from "magic-string";
|
|
|
1182
1304
|
import path3 from "node:path";
|
|
1183
1305
|
import { createHash } from "node:crypto";
|
|
1184
1306
|
var debug2 = createRangoDebugger(NS.transform);
|
|
1185
|
-
function
|
|
1307
|
+
function skipLeadingTrivia(code, start, end) {
|
|
1308
|
+
let i = start;
|
|
1309
|
+
while (i < end) {
|
|
1310
|
+
const skipped = skipStringOrComment(code, i);
|
|
1311
|
+
if (skipped > i) {
|
|
1312
|
+
i = skipped;
|
|
1313
|
+
continue;
|
|
1314
|
+
}
|
|
1315
|
+
if (/\s/.test(code[i])) {
|
|
1316
|
+
i++;
|
|
1317
|
+
continue;
|
|
1318
|
+
}
|
|
1319
|
+
break;
|
|
1320
|
+
}
|
|
1321
|
+
return i;
|
|
1322
|
+
}
|
|
1323
|
+
function transformRouter(code, filePath, routerFnNames, absolutePath, warn) {
|
|
1186
1324
|
const pat = new RegExp(
|
|
1187
|
-
`\\b(?:${routerFnNames.map(
|
|
1325
|
+
`\\b(?:${routerFnNames.map(escapeRegExp).join("|")})\\b`,
|
|
1188
1326
|
"g"
|
|
1189
1327
|
);
|
|
1190
1328
|
let match;
|
|
1191
1329
|
const s = new MagicString2(code);
|
|
1192
1330
|
let changed = false;
|
|
1331
|
+
const unsupportedSites = [];
|
|
1193
1332
|
const basename2 = path3.basename(filePath).replace(/\.(tsx?|jsx?)$/, "");
|
|
1194
1333
|
const routeNamesImport = `./${basename2}.named-routes.gen.js`;
|
|
1195
1334
|
const routeNamesVar = `__rsc_rn`;
|
|
1335
|
+
const codeOffsets = new Set(codeMatchIndices(code, pat));
|
|
1336
|
+
pat.lastIndex = 0;
|
|
1196
1337
|
while ((match = pat.exec(code)) !== null) {
|
|
1338
|
+
if (!codeOffsets.has(match.index)) continue;
|
|
1197
1339
|
const callStart = match.index;
|
|
1198
|
-
const
|
|
1340
|
+
const calleeEnd = match.index + match[0].length;
|
|
1341
|
+
const parenPos = findCallParenAfterGenerics(code, calleeEnd);
|
|
1342
|
+
if (parenPos === -1) continue;
|
|
1199
1343
|
const closeParen = findMatchingParen(code, parenPos + 1);
|
|
1200
1344
|
const callArgs = code.slice(parenPos + 1, closeParen);
|
|
1201
|
-
if (callArgs.includes(
|
|
1345
|
+
if (callArgs.includes(`$$routeNames: ${routeNamesVar}`)) continue;
|
|
1346
|
+
const sourceFilePath = absolutePath ?? filePath;
|
|
1202
1347
|
const lineNumber = code.slice(0, callStart).split("\n").length;
|
|
1203
1348
|
const hash = createHash("sha256").update(`${filePath}:${lineNumber}`).digest("hex").slice(0, 8);
|
|
1204
|
-
changed = true;
|
|
1205
|
-
const sourceFilePath = absolutePath ?? filePath;
|
|
1206
1349
|
const injected = ` $$id: "${hash}", $$sourceFile: "${sourceFilePath}", $$routeNames: ${routeNamesVar},`;
|
|
1207
|
-
const
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1350
|
+
const argsContentStart = skipLeadingTrivia(code, parenPos + 1, closeParen);
|
|
1351
|
+
const firstArgChar = code[argsContentStart];
|
|
1352
|
+
if (firstArgChar === "{") {
|
|
1353
|
+
changed = true;
|
|
1354
|
+
s.appendRight(argsContentStart + 1, injected);
|
|
1355
|
+
} else if (argsContentStart >= closeParen - 1) {
|
|
1356
|
+
changed = true;
|
|
1212
1357
|
s.appendRight(parenPos + 1, `{${injected} }`);
|
|
1358
|
+
} else {
|
|
1359
|
+
const lastNl = code.lastIndexOf("\n", callStart - 1);
|
|
1360
|
+
const column = callStart - (lastNl + 1) + 1;
|
|
1361
|
+
unsupportedSites.push({ line: lineNumber, column });
|
|
1213
1362
|
}
|
|
1214
1363
|
}
|
|
1364
|
+
if (unsupportedSites.length > 0 && warn) {
|
|
1365
|
+
warn(
|
|
1366
|
+
buildUnsupportedShapeWarning(filePath, "createRouter", unsupportedSites)
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1215
1369
|
if (!changed) return null;
|
|
1216
1370
|
s.prepend(
|
|
1217
1371
|
`import { NamedRoutes as ${routeNamesVar} } from "${routeNamesImport}";
|
|
@@ -1245,11 +1399,13 @@ function exposeRouterId() {
|
|
|
1245
1399
|
try {
|
|
1246
1400
|
const filePath = normalizePath(path3.relative(projectRoot, id));
|
|
1247
1401
|
const routerFnNames = getImportedFnNames(code, "createRouter");
|
|
1402
|
+
const warn = typeof this.warn === "function" ? (message) => this.warn(message) : void 0;
|
|
1248
1403
|
return transformRouter(
|
|
1249
1404
|
code,
|
|
1250
1405
|
filePath,
|
|
1251
1406
|
routerFnNames,
|
|
1252
|
-
normalizePath(id)
|
|
1407
|
+
normalizePath(id),
|
|
1408
|
+
warn
|
|
1253
1409
|
);
|
|
1254
1410
|
} finally {
|
|
1255
1411
|
counter?.record(id, performance.now() - start);
|
|
@@ -1345,6 +1501,7 @@ ${lazyImports.join(",\n")}
|
|
|
1345
1501
|
// --------------- Loader pre-scan (build mode) ---------------
|
|
1346
1502
|
async buildStart() {
|
|
1347
1503
|
if (!isBuild) return;
|
|
1504
|
+
if (this.environment && this.environment.name !== "rsc") return;
|
|
1348
1505
|
const fs2 = await import("node:fs/promises");
|
|
1349
1506
|
const SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", "build", "coverage"]);
|
|
1350
1507
|
async function scanDir(dir) {
|
|
@@ -1729,7 +1886,6 @@ ${lazyImports.join(",\n")}
|
|
|
1729
1886
|
changed = transformHandles(
|
|
1730
1887
|
getBindings(code, fnNames),
|
|
1731
1888
|
s,
|
|
1732
|
-
code,
|
|
1733
1889
|
filePath,
|
|
1734
1890
|
isBuild
|
|
1735
1891
|
) || changed;
|
|
@@ -1806,8 +1962,8 @@ function useCacheTransform() {
|
|
|
1806
1962
|
} = rscTransforms;
|
|
1807
1963
|
let ast;
|
|
1808
1964
|
try {
|
|
1809
|
-
const { parseAst:
|
|
1810
|
-
ast =
|
|
1965
|
+
const { parseAst: parseAst5 } = await import("vite");
|
|
1966
|
+
ast = parseAst5(code, { lang: "tsx" });
|
|
1811
1967
|
} catch {
|
|
1812
1968
|
return;
|
|
1813
1969
|
}
|
|
@@ -1841,7 +1997,7 @@ function useCacheTransform() {
|
|
|
1841
1997
|
};
|
|
1842
1998
|
}
|
|
1843
1999
|
function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLayoutOrTemplate, transformWrapExport) {
|
|
1844
|
-
const
|
|
2000
|
+
const unconfirmedExports = [];
|
|
1845
2001
|
const { exportNames, output } = transformWrapExport(code, ast, {
|
|
1846
2002
|
runtime: (value, name) => {
|
|
1847
2003
|
const funcId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
|
|
@@ -1850,16 +2006,17 @@ function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLa
|
|
|
1850
2006
|
rejectNonAsyncFunction: false,
|
|
1851
2007
|
filter: (name, meta) => {
|
|
1852
2008
|
if (name === "default" && isLayoutOrTemplate) return false;
|
|
1853
|
-
if (meta.isFunction
|
|
1854
|
-
|
|
2009
|
+
if (meta.isFunction !== true) {
|
|
2010
|
+
unconfirmedExports.push(name);
|
|
1855
2011
|
return false;
|
|
1856
2012
|
}
|
|
1857
2013
|
return true;
|
|
1858
2014
|
}
|
|
1859
2015
|
});
|
|
1860
|
-
if (
|
|
2016
|
+
if (unconfirmedExports.length > 0) {
|
|
2017
|
+
const plural = unconfirmedExports.length > 1;
|
|
1861
2018
|
throw new Error(
|
|
1862
|
-
`[rango:use-cache] File-level "use cache" in ${sourceId}
|
|
2019
|
+
`[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.`
|
|
1863
2020
|
);
|
|
1864
2021
|
}
|
|
1865
2022
|
if (exportNames.length === 0) {
|
|
@@ -1997,7 +2154,6 @@ function clientRefDedup() {
|
|
|
1997
2154
|
if (this.environment?.name !== "client") return;
|
|
1998
2155
|
if (!importer?.includes(CLIENT_IN_SERVER_PROXY_PREFIX)) return;
|
|
1999
2156
|
if (!source.includes("/node_modules/")) return;
|
|
2000
|
-
if (!importer) return;
|
|
2001
2157
|
const packageName = extractPackageName(source);
|
|
2002
2158
|
if (!packageName) return;
|
|
2003
2159
|
if (clientExclude.includes(packageName)) return;
|
|
@@ -2039,11 +2195,16 @@ async function initializeApp() {
|
|
|
2039
2195
|
createTemporaryReferenceSet,
|
|
2040
2196
|
};
|
|
2041
2197
|
|
|
2042
|
-
|
|
2198
|
+
// initBrowserApp resolves the initial payload and returns the browser app
|
|
2199
|
+
// context, including strictMode (default true) from createRouter. StrictMode
|
|
2200
|
+
// is the default; createRouter({ strictMode: false }) ships the opt-out in the
|
|
2201
|
+
// payload metadata. StrictMode emits no DOM, so toggling never changes markup.
|
|
2202
|
+
const { strictMode } = await initBrowserApp({ rscStream, deps });
|
|
2043
2203
|
|
|
2204
|
+
const app = createElement(Rango);
|
|
2044
2205
|
hydrateRoot(
|
|
2045
2206
|
document,
|
|
2046
|
-
createElement(StrictMode, null,
|
|
2207
|
+
strictMode === false ? app : createElement(StrictMode, null, app)
|
|
2047
2208
|
);
|
|
2048
2209
|
}
|
|
2049
2210
|
|
|
@@ -2051,9 +2212,14 @@ initializeApp().catch(console.error);
|
|
|
2051
2212
|
`.trim();
|
|
2052
2213
|
var VIRTUAL_ENTRY_SSR = `
|
|
2053
2214
|
import { createFromReadableStream } from "@rangojs/router/internal/deps/ssr";
|
|
2054
|
-
import { renderToReadableStream } from "react-dom/server.edge";
|
|
2215
|
+
import { renderToReadableStream, resume } from "react-dom/server.edge";
|
|
2216
|
+
import { prerender } from "react-dom/static.edge";
|
|
2055
2217
|
import { injectRSCPayload } from "@rangojs/router/internal/deps/html-stream-server";
|
|
2056
|
-
import {
|
|
2218
|
+
import {
|
|
2219
|
+
createSSRHandler,
|
|
2220
|
+
createShellCaptureHandler,
|
|
2221
|
+
createShellResumeHandler,
|
|
2222
|
+
} from "@rangojs/router/ssr";
|
|
2057
2223
|
|
|
2058
2224
|
export const renderHTML = createSSRHandler({
|
|
2059
2225
|
createFromReadableStream,
|
|
@@ -2062,8 +2228,35 @@ export const renderHTML = createSSRHandler({
|
|
|
2062
2228
|
loadBootstrapScriptContent: () =>
|
|
2063
2229
|
import.meta.viteRsc.loadBootstrapScriptContent("index"),
|
|
2064
2230
|
});
|
|
2231
|
+
|
|
2232
|
+
export const captureShellHTML = createShellCaptureHandler({
|
|
2233
|
+
createFromReadableStream,
|
|
2234
|
+
renderToReadableStream,
|
|
2235
|
+
injectRSCPayload,
|
|
2236
|
+
prerender,
|
|
2237
|
+
resume,
|
|
2238
|
+
loadBootstrapScriptContent: () =>
|
|
2239
|
+
import.meta.viteRsc.loadBootstrapScriptContent("index"),
|
|
2240
|
+
});
|
|
2241
|
+
|
|
2242
|
+
export const resumeShellHTML = createShellResumeHandler({
|
|
2243
|
+
createFromReadableStream,
|
|
2244
|
+
renderToReadableStream,
|
|
2245
|
+
injectRSCPayload,
|
|
2246
|
+
prerender,
|
|
2247
|
+
resume,
|
|
2248
|
+
loadBootstrapScriptContent: () =>
|
|
2249
|
+
import.meta.viteRsc.loadBootstrapScriptContent("index"),
|
|
2250
|
+
});
|
|
2065
2251
|
`.trim();
|
|
2252
|
+
var RSC_ENTRY_BOOTSTRAP_IMPORTS = [
|
|
2253
|
+
"virtual:rsc-router/routes-manifest",
|
|
2254
|
+
"virtual:rsc-router/loader-manifest"
|
|
2255
|
+
];
|
|
2066
2256
|
function getVirtualEntryRSC(routerPath) {
|
|
2257
|
+
const bootstrapImports = RSC_ENTRY_BOOTSTRAP_IMPORTS.map(
|
|
2258
|
+
(id) => `import "${id}";`
|
|
2259
|
+
).join("\n");
|
|
2067
2260
|
return `
|
|
2068
2261
|
import {
|
|
2069
2262
|
renderToReadableStream,
|
|
@@ -2077,15 +2270,9 @@ import { router } from "${routerPath}";
|
|
|
2077
2270
|
import { createRSCHandler } from "@rangojs/router/internal/rsc-handler";
|
|
2078
2271
|
import { VERSION } from "@rangojs/router:version";
|
|
2079
2272
|
|
|
2080
|
-
//
|
|
2081
|
-
//
|
|
2082
|
-
|
|
2083
|
-
import "virtual:rsc-router/loader-manifest";
|
|
2084
|
-
|
|
2085
|
-
// Import pre-generated route manifest so href() works immediately on cold start.
|
|
2086
|
-
// In build mode, this contains the full route map generated at build time.
|
|
2087
|
-
// In dev mode, this is a no-op (manifest is populated in-memory by the discovery plugin).
|
|
2088
|
-
import "virtual:rsc-router/routes-manifest";
|
|
2273
|
+
// Startup bootstrap imports (routes + loader manifests). See
|
|
2274
|
+
// RSC_ENTRY_BOOTSTRAP_IMPORTS \u2014 the same list the custom-entry injector uses.
|
|
2275
|
+
${bootstrapImports}
|
|
2089
2276
|
|
|
2090
2277
|
// Lazily create the handler on first request so that ESM live bindings
|
|
2091
2278
|
// have resolved by the time we read \`router\`. During HMR the module may
|
|
@@ -2096,6 +2283,11 @@ export default function handler(request, env) {
|
|
|
2096
2283
|
_handler = createRSCHandler({
|
|
2097
2284
|
router,
|
|
2098
2285
|
version: VERSION,
|
|
2286
|
+
// Forward the router's CSP nonce provider. createRSCHandler reads the
|
|
2287
|
+
// provider only from options.nonce; without this, createRouter({ nonce })
|
|
2288
|
+
// is silently dropped on the Node preset (the Cloudflare path wires it via
|
|
2289
|
+
// router.fetch). router.nonce is undefined when unconfigured, a safe no-op.
|
|
2290
|
+
nonce: router.nonce,
|
|
2099
2291
|
deps: {
|
|
2100
2292
|
renderToReadableStream,
|
|
2101
2293
|
decodeReply,
|
|
@@ -2112,6 +2304,77 @@ export default function handler(request, env) {
|
|
|
2112
2304
|
}
|
|
2113
2305
|
`.trim();
|
|
2114
2306
|
}
|
|
2307
|
+
function getVirtualEntryRSCHost(hostEntryPath) {
|
|
2308
|
+
return `
|
|
2309
|
+
import * as __hostEntry from "${hostEntryPath}";
|
|
2310
|
+
import { isNoRouteMatchError } from "@rangojs/router/host";
|
|
2311
|
+
|
|
2312
|
+
// Register every sub-app's fetchable loaders + route manifests at startup, same
|
|
2313
|
+
// as the single-router entry. Discovery's host fallback populates these for all
|
|
2314
|
+
// mounted sub-apps, so the aggregate manifests cover the whole host tree.
|
|
2315
|
+
import "virtual:rsc-router/loader-manifest";
|
|
2316
|
+
import "virtual:rsc-router/routes-manifest";
|
|
2317
|
+
|
|
2318
|
+
// The host entry module must export the HostRouter instance (createHostRouter()),
|
|
2319
|
+
// as a default export or a named \`hostRouter\`/\`router\` export. A Cloudflare-style
|
|
2320
|
+
// \`export default { fetch }\` object is not a HostRouter and is rejected (on first
|
|
2321
|
+
// request; see the lazy resolution below).
|
|
2322
|
+
// We require BOTH .match() and .host(): a regular createRouter() also exposes
|
|
2323
|
+
// .match(), so matching on .match() alone would accept an ordinary router and then
|
|
2324
|
+
// return its MatchResult (not a Response) at runtime. .host() is unique to a
|
|
2325
|
+
// HostRouter, so it disambiguates a mistaken \`hostRouter\` path.
|
|
2326
|
+
// Exports are read dynamically (m[name]) so Rollup does not emit IMPORT_IS_UNDEFINED
|
|
2327
|
+
// warnings for the named exports a default-only host module legitimately omits.
|
|
2328
|
+
const __resolveHostRouter = (m) => {
|
|
2329
|
+
for (const name of ["default", "hostRouter", "router"]) {
|
|
2330
|
+
const candidate = m[name];
|
|
2331
|
+
if (
|
|
2332
|
+
candidate &&
|
|
2333
|
+
typeof candidate.match === "function" &&
|
|
2334
|
+
typeof candidate.host === "function"
|
|
2335
|
+
)
|
|
2336
|
+
return candidate;
|
|
2337
|
+
}
|
|
2338
|
+
return undefined;
|
|
2339
|
+
};
|
|
2340
|
+
|
|
2341
|
+
// Resolve + validate the HostRouter lazily on first request, mirroring the
|
|
2342
|
+
// single-router entry's \`_handler\`. During HMR the host module can re-evaluate
|
|
2343
|
+
// before its createHostRouter() export has resolved; validating at module-
|
|
2344
|
+
// evaluation time would then throw a spurious "must export a HostRouter" error
|
|
2345
|
+
// overlay for a perfectly valid app. Resolving on first request lets the live
|
|
2346
|
+
// binding settle first.
|
|
2347
|
+
let _hostRouter;
|
|
2348
|
+
|
|
2349
|
+
// input = { env, ctx } from the launcher / node server. The host router threads
|
|
2350
|
+
// it unchanged to each matched sub-app's handler and cache factory.
|
|
2351
|
+
// On node/vercel rango owns this entry, so there is no user worker to translate
|
|
2352
|
+
// an unmatched host into a response: catch NoRouteMatchError and return 404
|
|
2353
|
+
// (parity with the documented Cloudflare catch). Other errors propagate.
|
|
2354
|
+
export default async function handler(request, input) {
|
|
2355
|
+
if (!_hostRouter) {
|
|
2356
|
+
_hostRouter = __resolveHostRouter(__hostEntry);
|
|
2357
|
+
if (!_hostRouter) {
|
|
2358
|
+
throw new Error(
|
|
2359
|
+
"[rango] The host entry (${hostEntryPath}) must export a HostRouter instance (createHostRouter()) for the node/vercel preset: a default export, or a named 'hostRouter'/'router' export. An ordinary createRouter() is not a host router (it has no .host()), and a Cloudflare-style 'export default { fetch }' object is not supported on this preset."
|
|
2360
|
+
);
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
try {
|
|
2364
|
+
return await _hostRouter.match(request, input);
|
|
2365
|
+
} catch (err) {
|
|
2366
|
+
// isNoRouteMatchError also matches by name: a workspace with a duplicated
|
|
2367
|
+
// @rangojs/router copy can throw a NoRouteMatchError whose prototype differs
|
|
2368
|
+
// from this module's import, so a bare instanceof would turn an
|
|
2369
|
+
// unmatched-host 404 into a 500.
|
|
2370
|
+
if (isNoRouteMatchError(err)) {
|
|
2371
|
+
return new Response("Not Found", { status: 404 });
|
|
2372
|
+
}
|
|
2373
|
+
throw err;
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
`.trim();
|
|
2377
|
+
}
|
|
2115
2378
|
var VIRTUAL_IDS = {
|
|
2116
2379
|
browser: "virtual:rsc-router/entry.browser.js",
|
|
2117
2380
|
ssr: "virtual:rsc-router/entry.ssr.js",
|
|
@@ -2130,7 +2393,7 @@ import { resolve } from "node:path";
|
|
|
2130
2393
|
// package.json
|
|
2131
2394
|
var package_default = {
|
|
2132
2395
|
name: "@rangojs/router",
|
|
2133
|
-
version: "0.0.0-experimental.
|
|
2396
|
+
version: "0.0.0-experimental.bdaf10aa",
|
|
2134
2397
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
2135
2398
|
keywords: [
|
|
2136
2399
|
"react",
|
|
@@ -2240,6 +2503,16 @@ var package_default = {
|
|
|
2240
2503
|
"react-server": "./src/cache/cache-runtime.ts",
|
|
2241
2504
|
default: "./src/cache/cache-runtime.ts"
|
|
2242
2505
|
},
|
|
2506
|
+
"./cloudflare": {
|
|
2507
|
+
types: "./src/cloudflare/index.ts",
|
|
2508
|
+
"react-server": "./src/cloudflare/index.ts",
|
|
2509
|
+
default: "./src/cloudflare/index.ts"
|
|
2510
|
+
},
|
|
2511
|
+
"./vercel": {
|
|
2512
|
+
types: "./src/vercel/index.ts",
|
|
2513
|
+
"react-server": "./src/vercel/index.ts",
|
|
2514
|
+
default: "./src/vercel/index.ts"
|
|
2515
|
+
},
|
|
2243
2516
|
"./theme": {
|
|
2244
2517
|
types: "./src/theme/index.ts",
|
|
2245
2518
|
default: "./src/theme/index.ts"
|
|
@@ -2288,7 +2561,7 @@ var package_default = {
|
|
|
2288
2561
|
tag: "experimental"
|
|
2289
2562
|
},
|
|
2290
2563
|
scripts: {
|
|
2291
|
-
build: "pnpm
|
|
2564
|
+
build: "pnpm exec 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 exec esbuild src/testing/vitest.ts --bundle --format=esm --outfile=dist/testing/vitest.js --platform=node --packages=external && pnpm exec 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",
|
|
2292
2565
|
prepublishOnly: "pnpm build",
|
|
2293
2566
|
typecheck: "tsc --noEmit && tsc -p tsconfig.strict-check.json --noEmit && tsc -p tsconfig.augment-check.json --noEmit",
|
|
2294
2567
|
test: "playwright test",
|
|
@@ -2300,14 +2573,18 @@ var package_default = {
|
|
|
2300
2573
|
},
|
|
2301
2574
|
dependencies: {
|
|
2302
2575
|
"@types/debug": "^4.1.12",
|
|
2303
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
2576
|
+
"@vitejs/plugin-rsc": "^0.5.27",
|
|
2304
2577
|
debug: "^4.4.1",
|
|
2305
2578
|
"magic-string": "^0.30.17",
|
|
2306
|
-
picomatch: "^4.0.
|
|
2579
|
+
picomatch: "^4.0.4",
|
|
2307
2580
|
"rsc-html-stream": "^0.0.7",
|
|
2581
|
+
srvx: "^0.11.15",
|
|
2308
2582
|
tinyexec: "^0.3.2"
|
|
2309
2583
|
},
|
|
2310
2584
|
devDependencies: {
|
|
2585
|
+
"@opentelemetry/api": "^1.9.0",
|
|
2586
|
+
"@opentelemetry/context-async-hooks": "^2.9.0",
|
|
2587
|
+
"@opentelemetry/sdk-trace-base": "^2.9.0",
|
|
2311
2588
|
"@playwright/test": "^1.49.1",
|
|
2312
2589
|
"@shared/e2e": "workspace:*",
|
|
2313
2590
|
"@testing-library/dom": "^10.4.1",
|
|
@@ -2315,40 +2592,51 @@ var package_default = {
|
|
|
2315
2592
|
"@types/node": "^24.10.1",
|
|
2316
2593
|
"@types/react": "catalog:",
|
|
2317
2594
|
"@types/react-dom": "catalog:",
|
|
2318
|
-
esbuild: "^0.
|
|
2595
|
+
esbuild: "^0.28.1",
|
|
2319
2596
|
"happy-dom": "^20.10.1",
|
|
2320
|
-
jiti: "^2.
|
|
2597
|
+
jiti: "^2.7.0",
|
|
2321
2598
|
react: "catalog:",
|
|
2322
2599
|
"react-dom": "catalog:",
|
|
2323
2600
|
typescript: "^5.3.0",
|
|
2324
|
-
vitest: "^4.
|
|
2601
|
+
vitest: "^4.1.9"
|
|
2325
2602
|
},
|
|
2326
2603
|
peerDependencies: {
|
|
2327
|
-
"@cloudflare/vite-plugin": "^1.
|
|
2604
|
+
"@cloudflare/vite-plugin": "^1.42.1",
|
|
2605
|
+
"@opentelemetry/api": "^1.9.0",
|
|
2328
2606
|
"@playwright/test": "^1.49.1",
|
|
2329
2607
|
"@testing-library/react": ">=16",
|
|
2330
|
-
"@
|
|
2608
|
+
"@vercel/functions": "^3.0.0",
|
|
2609
|
+
"@vitejs/plugin-rsc": "^0.5.27",
|
|
2331
2610
|
react: ">=19.2.6 <20",
|
|
2332
2611
|
"react-dom": ">=19.2.6 <20",
|
|
2333
|
-
vite: "^8.0.
|
|
2612
|
+
vite: "^8.0.16",
|
|
2334
2613
|
vitest: ">=3"
|
|
2335
2614
|
},
|
|
2336
2615
|
peerDependenciesMeta: {
|
|
2337
2616
|
"@cloudflare/vite-plugin": {
|
|
2338
2617
|
optional: true
|
|
2339
2618
|
},
|
|
2619
|
+
"@opentelemetry/api": {
|
|
2620
|
+
optional: true
|
|
2621
|
+
},
|
|
2340
2622
|
"@playwright/test": {
|
|
2341
2623
|
optional: true
|
|
2342
2624
|
},
|
|
2343
2625
|
"@testing-library/react": {
|
|
2344
2626
|
optional: true
|
|
2345
2627
|
},
|
|
2628
|
+
"@vercel/functions": {
|
|
2629
|
+
optional: true
|
|
2630
|
+
},
|
|
2346
2631
|
vite: {
|
|
2347
2632
|
optional: true
|
|
2348
2633
|
},
|
|
2349
2634
|
vitest: {
|
|
2350
2635
|
optional: true
|
|
2351
2636
|
}
|
|
2637
|
+
},
|
|
2638
|
+
engines: {
|
|
2639
|
+
node: "^20.19.0 || >=22.12.0"
|
|
2352
2640
|
}
|
|
2353
2641
|
};
|
|
2354
2642
|
|
|
@@ -2422,10 +2710,10 @@ function extractParamsFromPattern(pattern) {
|
|
|
2422
2710
|
function formatRouteEntry(key, pattern, _params, search) {
|
|
2423
2711
|
const hasSearch = search && Object.keys(search).length > 0;
|
|
2424
2712
|
if (!hasSearch) {
|
|
2425
|
-
return ` ${key}:
|
|
2713
|
+
return ` ${key}: ${JSON.stringify(pattern)},`;
|
|
2426
2714
|
}
|
|
2427
|
-
const searchBody = Object.entries(search).map(([k, v]) => `${k}:
|
|
2428
|
-
return ` ${key}: { path:
|
|
2715
|
+
const searchBody = Object.entries(search).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join(", ");
|
|
2716
|
+
return ` ${key}: { path: ${JSON.stringify(pattern)}, search: { ${searchBody} } },`;
|
|
2429
2717
|
}
|
|
2430
2718
|
|
|
2431
2719
|
// src/build/route-types/ast-route-extraction.ts
|
|
@@ -2451,8 +2739,8 @@ function extractObjectStringProperties(node) {
|
|
|
2451
2739
|
}
|
|
2452
2740
|
|
|
2453
2741
|
// src/build/route-types/ast-route-extraction.ts
|
|
2454
|
-
function extractRoutesFromSource(code) {
|
|
2455
|
-
const sourceFile = ts2.createSourceFile(
|
|
2742
|
+
function extractRoutesFromSource(code, sourceFileArg) {
|
|
2743
|
+
const sourceFile = sourceFileArg ?? ts2.createSourceFile(
|
|
2456
2744
|
"input.tsx",
|
|
2457
2745
|
code,
|
|
2458
2746
|
ts2.ScriptTarget.Latest,
|
|
@@ -2532,16 +2820,44 @@ export const NamedRoutes = {
|
|
|
2532
2820
|
${objectBody}
|
|
2533
2821
|
} as const;
|
|
2534
2822
|
|
|
2823
|
+
// Aliased so the augmentation below does not pay a homomorphic mapped-type
|
|
2824
|
+
// instantiation per route; \`as const\` already makes the members readonly.
|
|
2825
|
+
type NamedRoutesShape = typeof NamedRoutes;
|
|
2826
|
+
|
|
2535
2827
|
declare global {
|
|
2536
2828
|
namespace Rango {
|
|
2537
|
-
interface GeneratedRouteMap extends
|
|
2829
|
+
interface GeneratedRouteMap extends NamedRoutesShape {}
|
|
2538
2830
|
}
|
|
2539
2831
|
}
|
|
2540
2832
|
`;
|
|
2541
2833
|
}
|
|
2542
2834
|
|
|
2543
2835
|
// src/build/route-types/scan-filter.ts
|
|
2836
|
+
import { join, relative } from "node:path";
|
|
2544
2837
|
import picomatch from "picomatch";
|
|
2838
|
+
var DEFAULT_EXCLUDE_PATTERNS = [
|
|
2839
|
+
"**/__tests__/**",
|
|
2840
|
+
"**/__mocks__/**",
|
|
2841
|
+
"**/dist/**",
|
|
2842
|
+
"**/coverage/**",
|
|
2843
|
+
"**/*.test.{ts,tsx,js,jsx}",
|
|
2844
|
+
"**/*.spec.{ts,tsx,js,jsx}"
|
|
2845
|
+
];
|
|
2846
|
+
function createScanFilter(root, opts) {
|
|
2847
|
+
const { include, exclude } = opts;
|
|
2848
|
+
const hasInclude = include && include.length > 0;
|
|
2849
|
+
const hasCustomExclude = exclude !== void 0;
|
|
2850
|
+
if (!hasInclude && !hasCustomExclude) return void 0;
|
|
2851
|
+
const effectiveExclude = exclude ?? DEFAULT_EXCLUDE_PATTERNS;
|
|
2852
|
+
const includeMatcher = hasInclude ? picomatch(include) : null;
|
|
2853
|
+
const excludeMatcher = effectiveExclude.length > 0 ? picomatch(effectiveExclude) : null;
|
|
2854
|
+
return (absolutePath) => {
|
|
2855
|
+
const rel = relative(root, absolutePath);
|
|
2856
|
+
if (excludeMatcher && excludeMatcher(rel)) return false;
|
|
2857
|
+
if (includeMatcher) return includeMatcher(rel);
|
|
2858
|
+
return true;
|
|
2859
|
+
};
|
|
2860
|
+
}
|
|
2545
2861
|
|
|
2546
2862
|
// src/build/route-types/per-module-writer.ts
|
|
2547
2863
|
import ts4 from "typescript";
|
|
@@ -2550,6 +2866,33 @@ import ts4 from "typescript";
|
|
|
2550
2866
|
import { readFileSync, existsSync as existsSync2 } from "node:fs";
|
|
2551
2867
|
import { dirname, resolve as resolve2 } from "node:path";
|
|
2552
2868
|
import ts3 from "typescript";
|
|
2869
|
+
function createScanMemo() {
|
|
2870
|
+
return { files: /* @__PURE__ */ new Map(), blockSourceFiles: /* @__PURE__ */ new Map() };
|
|
2871
|
+
}
|
|
2872
|
+
function parseBlock(memo, block) {
|
|
2873
|
+
if (memo) {
|
|
2874
|
+
const cached = memo.blockSourceFiles.get(block);
|
|
2875
|
+
if (cached) return cached;
|
|
2876
|
+
}
|
|
2877
|
+
const sf = ts3.createSourceFile(
|
|
2878
|
+
"input.tsx",
|
|
2879
|
+
block,
|
|
2880
|
+
ts3.ScriptTarget.Latest,
|
|
2881
|
+
true,
|
|
2882
|
+
ts3.ScriptKind.TSX
|
|
2883
|
+
);
|
|
2884
|
+
if (memo) memo.blockSourceFiles.set(block, sf);
|
|
2885
|
+
return sf;
|
|
2886
|
+
}
|
|
2887
|
+
function readSourceMemoized(memo, realPath) {
|
|
2888
|
+
if (memo) {
|
|
2889
|
+
const cached = memo.files.get(realPath);
|
|
2890
|
+
if (cached !== void 0) return cached;
|
|
2891
|
+
}
|
|
2892
|
+
const source = readFileSync(realPath, "utf-8");
|
|
2893
|
+
if (memo) memo.files.set(realPath, source);
|
|
2894
|
+
return source;
|
|
2895
|
+
}
|
|
2553
2896
|
function extractNamePrefixFromInclude(node) {
|
|
2554
2897
|
if (node.arguments.length >= 3) {
|
|
2555
2898
|
const thirdArg = node.arguments[2];
|
|
@@ -2565,8 +2908,98 @@ function extractNamePrefixFromInclude(node) {
|
|
|
2565
2908
|
}
|
|
2566
2909
|
return null;
|
|
2567
2910
|
}
|
|
2568
|
-
function
|
|
2569
|
-
const
|
|
2911
|
+
function thenSelectsNonDefaultMember(expr) {
|
|
2912
|
+
const findThenCall = (e) => {
|
|
2913
|
+
if (ts3.isCallExpression(e) && ts3.isPropertyAccessExpression(e.expression) && e.expression.name.text === "then") {
|
|
2914
|
+
return e;
|
|
2915
|
+
}
|
|
2916
|
+
if (ts3.isCallExpression(e) && ts3.isPropertyAccessExpression(e.expression)) {
|
|
2917
|
+
return findThenCall(e.expression.expression);
|
|
2918
|
+
}
|
|
2919
|
+
if (ts3.isPropertyAccessExpression(e)) return findThenCall(e.expression);
|
|
2920
|
+
if (ts3.isParenthesizedExpression(e)) return findThenCall(e.expression);
|
|
2921
|
+
if (ts3.isAwaitExpression(e)) return findThenCall(e.expression);
|
|
2922
|
+
return null;
|
|
2923
|
+
};
|
|
2924
|
+
const thenCall = findThenCall(expr);
|
|
2925
|
+
if (!thenCall || thenCall.arguments.length === 0) return false;
|
|
2926
|
+
const cb = thenCall.arguments[0];
|
|
2927
|
+
if (!ts3.isArrowFunction(cb) && !ts3.isFunctionExpression(cb)) return false;
|
|
2928
|
+
let ret;
|
|
2929
|
+
if (ts3.isBlock(cb.body)) {
|
|
2930
|
+
for (const stmt of cb.body.statements) {
|
|
2931
|
+
if (ts3.isReturnStatement(stmt) && stmt.expression) {
|
|
2932
|
+
ret = stmt.expression;
|
|
2933
|
+
break;
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
} else {
|
|
2937
|
+
ret = cb.body;
|
|
2938
|
+
}
|
|
2939
|
+
if (!ret) return false;
|
|
2940
|
+
if (ts3.isPropertyAccessExpression(ret)) {
|
|
2941
|
+
return ret.name.text !== "default";
|
|
2942
|
+
}
|
|
2943
|
+
return false;
|
|
2944
|
+
}
|
|
2945
|
+
function extractDynamicImportSpecifier(node) {
|
|
2946
|
+
let body;
|
|
2947
|
+
if (ts3.isArrowFunction(node) || ts3.isFunctionExpression(node)) {
|
|
2948
|
+
body = node.body;
|
|
2949
|
+
}
|
|
2950
|
+
if (!body) return null;
|
|
2951
|
+
let expr;
|
|
2952
|
+
if (ts3.isBlock(body)) {
|
|
2953
|
+
for (const stmt of body.statements) {
|
|
2954
|
+
if (ts3.isReturnStatement(stmt) && stmt.expression) {
|
|
2955
|
+
expr = stmt.expression;
|
|
2956
|
+
break;
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
} else {
|
|
2960
|
+
expr = body;
|
|
2961
|
+
}
|
|
2962
|
+
if (!expr) return null;
|
|
2963
|
+
const findImportCall = (e) => {
|
|
2964
|
+
if (ts3.isCallExpression(e) && e.expression.kind === ts3.SyntaxKind.ImportKeyword) {
|
|
2965
|
+
return e;
|
|
2966
|
+
}
|
|
2967
|
+
if (ts3.isCallExpression(e) && ts3.isPropertyAccessExpression(e.expression)) {
|
|
2968
|
+
return findImportCall(e.expression.expression);
|
|
2969
|
+
}
|
|
2970
|
+
if (ts3.isPropertyAccessExpression(e)) return findImportCall(e.expression);
|
|
2971
|
+
if (ts3.isParenthesizedExpression(e)) return findImportCall(e.expression);
|
|
2972
|
+
if (ts3.isAwaitExpression(e)) return findImportCall(e.expression);
|
|
2973
|
+
return null;
|
|
2974
|
+
};
|
|
2975
|
+
const importCall = findImportCall(expr);
|
|
2976
|
+
if (!importCall || importCall.arguments.length === 0) return null;
|
|
2977
|
+
if (thenSelectsNonDefaultMember(expr)) return null;
|
|
2978
|
+
return getStringValue(importCall.arguments[0]);
|
|
2979
|
+
}
|
|
2980
|
+
function resolveDefaultExportTarget(code, sourceFile) {
|
|
2981
|
+
let result = null;
|
|
2982
|
+
function visit(node) {
|
|
2983
|
+
if (result) return;
|
|
2984
|
+
if (ts3.isExportAssignment(node) && !node.isExportEquals) {
|
|
2985
|
+
const expr = node.expression;
|
|
2986
|
+
if (ts3.isIdentifier(expr)) {
|
|
2987
|
+
result = { variableName: expr.text };
|
|
2988
|
+
} else if (ts3.isCallExpression(expr)) {
|
|
2989
|
+
const callee = expr.expression;
|
|
2990
|
+
if (ts3.isIdentifier(callee) && callee.text === "urls") {
|
|
2991
|
+
result = { inlineBlock: expr.getText(sourceFile) };
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
return;
|
|
2995
|
+
}
|
|
2996
|
+
ts3.forEachChild(node, visit);
|
|
2997
|
+
}
|
|
2998
|
+
visit(sourceFile);
|
|
2999
|
+
return result;
|
|
3000
|
+
}
|
|
3001
|
+
function extractIncludesWithDiagnostics(code, sourceFileArg) {
|
|
3002
|
+
const sourceFile = sourceFileArg ?? ts3.createSourceFile(
|
|
2570
3003
|
"input.tsx",
|
|
2571
3004
|
code,
|
|
2572
3005
|
ts3.ScriptTarget.Latest,
|
|
@@ -2590,12 +3023,19 @@ function extractIncludesWithDiagnostics(code) {
|
|
|
2590
3023
|
}
|
|
2591
3024
|
const secondArg = node.arguments[1];
|
|
2592
3025
|
const namePrefix = extractNamePrefixFromInclude(node);
|
|
3026
|
+
const dynamicImportSpec = extractDynamicImportSpecifier(secondArg);
|
|
2593
3027
|
if (ts3.isIdentifier(secondArg)) {
|
|
2594
3028
|
resolved.push({
|
|
2595
3029
|
pathPrefix,
|
|
2596
3030
|
variableName: secondArg.text,
|
|
2597
3031
|
namePrefix
|
|
2598
3032
|
});
|
|
3033
|
+
} else if (dynamicImportSpec !== null) {
|
|
3034
|
+
resolved.push({
|
|
3035
|
+
pathPrefix,
|
|
3036
|
+
moduleSpecifier: dynamicImportSpec,
|
|
3037
|
+
namePrefix
|
|
3038
|
+
});
|
|
2599
3039
|
} else if (ts3.isCallExpression(secondArg)) {
|
|
2600
3040
|
const callText = secondArg.expression.getText(sourceFile);
|
|
2601
3041
|
unresolvable.push({
|
|
@@ -2620,7 +3060,7 @@ function extractIncludesWithDiagnostics(code) {
|
|
|
2620
3060
|
return { resolved, unresolvable };
|
|
2621
3061
|
}
|
|
2622
3062
|
function resolveImportedVariable(code, localName) {
|
|
2623
|
-
const importRegex = /import\s
|
|
3063
|
+
const importRegex = /import\s*(?:[\w$]+\s*,\s*)?\{([^}]+)\}\s*from\s*["']([^"']+)["']/g;
|
|
2624
3064
|
let match;
|
|
2625
3065
|
while ((match = importRegex.exec(code)) !== null) {
|
|
2626
3066
|
const imports = match[1];
|
|
@@ -2657,8 +3097,8 @@ function resolveImportPath(importSpec, fromFile) {
|
|
|
2657
3097
|
}
|
|
2658
3098
|
return null;
|
|
2659
3099
|
}
|
|
2660
|
-
function extractUrlsBlockForVariable(code, varName) {
|
|
2661
|
-
const sourceFile = ts3.createSourceFile(
|
|
3100
|
+
function extractUrlsBlockForVariable(code, varName, sourceFileArg) {
|
|
3101
|
+
const sourceFile = sourceFileArg ?? ts3.createSourceFile(
|
|
2662
3102
|
"input.tsx",
|
|
2663
3103
|
code,
|
|
2664
3104
|
ts3.ScriptTarget.Latest,
|
|
@@ -2680,67 +3120,113 @@ function extractUrlsBlockForVariable(code, varName) {
|
|
|
2680
3120
|
visit(sourceFile);
|
|
2681
3121
|
return result;
|
|
2682
3122
|
}
|
|
2683
|
-
function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSchemasOut, diagnosticsOut) {
|
|
3123
|
+
function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSchemasOut, diagnosticsOut, memo) {
|
|
2684
3124
|
const routeMap = {};
|
|
2685
|
-
const
|
|
3125
|
+
const blockSourceFile = parseBlock(memo, block);
|
|
3126
|
+
const localRoutes = extractRoutesFromSource(block, blockSourceFile);
|
|
2686
3127
|
for (const { name, pattern, search } of localRoutes) {
|
|
2687
3128
|
routeMap[name] = pattern;
|
|
2688
3129
|
if (search && searchSchemasOut) {
|
|
2689
3130
|
searchSchemasOut[name] = search;
|
|
2690
3131
|
}
|
|
2691
3132
|
}
|
|
2692
|
-
const { resolved: includes, unresolvable } = extractIncludesWithDiagnostics(
|
|
3133
|
+
const { resolved: includes, unresolvable } = extractIncludesWithDiagnostics(
|
|
3134
|
+
block,
|
|
3135
|
+
blockSourceFile
|
|
3136
|
+
);
|
|
2693
3137
|
if (diagnosticsOut) {
|
|
2694
3138
|
for (const entry of unresolvable) {
|
|
2695
3139
|
diagnosticsOut.push({ ...entry, sourceFile: filePath });
|
|
2696
3140
|
}
|
|
2697
3141
|
}
|
|
2698
|
-
for (const
|
|
3142
|
+
for (const inc of includes) {
|
|
3143
|
+
const { pathPrefix, namePrefix } = inc;
|
|
2699
3144
|
let childResult;
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
const targetFile = resolveImportPath(imported.specifier, filePath);
|
|
3145
|
+
if (inc.moduleSpecifier) {
|
|
3146
|
+
const targetFile = resolveImportPath(inc.moduleSpecifier, filePath);
|
|
2703
3147
|
if (!targetFile) {
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
});
|
|
2712
|
-
}
|
|
3148
|
+
diagnosticsOut?.push({
|
|
3149
|
+
pathPrefix,
|
|
3150
|
+
namePrefix,
|
|
3151
|
+
reason: "file-not-found",
|
|
3152
|
+
sourceFile: filePath,
|
|
3153
|
+
detail: `import("${inc.moduleSpecifier}") resolved to no file`
|
|
3154
|
+
});
|
|
2713
3155
|
continue;
|
|
2714
3156
|
}
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
diagnosticsOut
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
3157
|
+
let targetSource;
|
|
3158
|
+
try {
|
|
3159
|
+
targetSource = readSourceMemoized(memo, resolve2(targetFile));
|
|
3160
|
+
} catch (err) {
|
|
3161
|
+
diagnosticsOut?.push({
|
|
3162
|
+
pathPrefix,
|
|
3163
|
+
namePrefix,
|
|
3164
|
+
reason: "file-not-found",
|
|
3165
|
+
sourceFile: filePath,
|
|
3166
|
+
detail: `import("${inc.moduleSpecifier}") resolved to "${targetFile}" but reading it failed: ${err?.message ?? String(err)}`
|
|
3167
|
+
});
|
|
3168
|
+
continue;
|
|
3169
|
+
}
|
|
3170
|
+
const def = resolveDefaultExportTarget(
|
|
3171
|
+
targetSource,
|
|
3172
|
+
parseBlock(memo, targetSource)
|
|
2725
3173
|
);
|
|
2726
|
-
if (!
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
});
|
|
2735
|
-
}
|
|
3174
|
+
if (!def) {
|
|
3175
|
+
diagnosticsOut?.push({
|
|
3176
|
+
pathPrefix,
|
|
3177
|
+
namePrefix,
|
|
3178
|
+
reason: "unresolvable-import",
|
|
3179
|
+
sourceFile: filePath,
|
|
3180
|
+
detail: `import("${inc.moduleSpecifier}") has no resolvable \`export default urls(...)\``
|
|
3181
|
+
});
|
|
2736
3182
|
continue;
|
|
2737
3183
|
}
|
|
2738
|
-
|
|
2739
|
-
|
|
3184
|
+
if (def.inlineBlock) {
|
|
3185
|
+
childResult = buildCombinedRouteMapWithSearch(
|
|
3186
|
+
targetFile,
|
|
3187
|
+
void 0,
|
|
3188
|
+
visited,
|
|
3189
|
+
diagnosticsOut,
|
|
3190
|
+
def.inlineBlock,
|
|
3191
|
+
memo
|
|
3192
|
+
);
|
|
3193
|
+
} else {
|
|
3194
|
+
const variableName = def.variableName;
|
|
3195
|
+
const resolved = resolveIncludedVariable({
|
|
3196
|
+
variableName,
|
|
3197
|
+
resolutionFile: targetFile,
|
|
3198
|
+
resolutionSource: targetSource,
|
|
3199
|
+
reportFile: filePath,
|
|
3200
|
+
memo,
|
|
3201
|
+
visited,
|
|
3202
|
+
diagnosticsOut,
|
|
3203
|
+
pathPrefix,
|
|
3204
|
+
namePrefix,
|
|
3205
|
+
fileNotFoundDetail: (specifier) => `import("${inc.moduleSpecifier}") default re-exports "${variableName}" from "${specifier}", which resolved to no file`,
|
|
3206
|
+
notFoundDetail: () => `import("${inc.moduleSpecifier}") default "${variableName}" not found in its imports or same-file scope`
|
|
3207
|
+
});
|
|
3208
|
+
if (!resolved) continue;
|
|
3209
|
+
childResult = resolved;
|
|
3210
|
+
}
|
|
3211
|
+
} else if (inc.variableName) {
|
|
3212
|
+
const variableName = inc.variableName;
|
|
3213
|
+
const resolved = resolveIncludedVariable({
|
|
2740
3214
|
variableName,
|
|
3215
|
+
resolutionFile: filePath,
|
|
3216
|
+
resolutionSource: fullSource,
|
|
3217
|
+
reportFile: filePath,
|
|
3218
|
+
memo,
|
|
2741
3219
|
visited,
|
|
2742
|
-
diagnosticsOut
|
|
2743
|
-
|
|
3220
|
+
diagnosticsOut,
|
|
3221
|
+
pathPrefix,
|
|
3222
|
+
namePrefix,
|
|
3223
|
+
fileNotFoundDetail: (specifier) => `import "${specifier}" resolved to no file`,
|
|
3224
|
+
notFoundDetail: () => `variable "${variableName}" not found in imports or same-file scope`
|
|
3225
|
+
});
|
|
3226
|
+
if (!resolved) continue;
|
|
3227
|
+
childResult = resolved;
|
|
3228
|
+
} else {
|
|
3229
|
+
continue;
|
|
2744
3230
|
}
|
|
2745
3231
|
if (namePrefix === null) {
|
|
2746
3232
|
continue;
|
|
@@ -2763,8 +3249,67 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
|
|
|
2763
3249
|
}
|
|
2764
3250
|
return routeMap;
|
|
2765
3251
|
}
|
|
2766
|
-
function
|
|
3252
|
+
function resolveIncludedVariable(opts) {
|
|
3253
|
+
const {
|
|
3254
|
+
variableName,
|
|
3255
|
+
resolutionFile,
|
|
3256
|
+
resolutionSource,
|
|
3257
|
+
reportFile,
|
|
3258
|
+
memo,
|
|
3259
|
+
visited,
|
|
3260
|
+
diagnosticsOut,
|
|
3261
|
+
pathPrefix,
|
|
3262
|
+
namePrefix
|
|
3263
|
+
} = opts;
|
|
3264
|
+
const imported = resolveImportedVariable(resolutionSource, variableName);
|
|
3265
|
+
if (imported) {
|
|
3266
|
+
const targetFile = resolveImportPath(imported.specifier, resolutionFile);
|
|
3267
|
+
if (!targetFile) {
|
|
3268
|
+
diagnosticsOut?.push({
|
|
3269
|
+
pathPrefix,
|
|
3270
|
+
namePrefix,
|
|
3271
|
+
reason: "file-not-found",
|
|
3272
|
+
sourceFile: reportFile,
|
|
3273
|
+
detail: opts.fileNotFoundDetail(imported.specifier)
|
|
3274
|
+
});
|
|
3275
|
+
return null;
|
|
3276
|
+
}
|
|
3277
|
+
return buildCombinedRouteMapWithSearch(
|
|
3278
|
+
targetFile,
|
|
3279
|
+
imported.exportedName,
|
|
3280
|
+
visited,
|
|
3281
|
+
diagnosticsOut,
|
|
3282
|
+
void 0,
|
|
3283
|
+
memo
|
|
3284
|
+
);
|
|
3285
|
+
}
|
|
3286
|
+
const sameFileBlock = extractUrlsBlockForVariable(
|
|
3287
|
+
resolutionSource,
|
|
3288
|
+
variableName,
|
|
3289
|
+
parseBlock(memo, resolutionSource)
|
|
3290
|
+
);
|
|
3291
|
+
if (!sameFileBlock) {
|
|
3292
|
+
diagnosticsOut?.push({
|
|
3293
|
+
pathPrefix,
|
|
3294
|
+
namePrefix,
|
|
3295
|
+
reason: "unresolvable-import",
|
|
3296
|
+
sourceFile: reportFile,
|
|
3297
|
+
detail: opts.notFoundDetail()
|
|
3298
|
+
});
|
|
3299
|
+
return null;
|
|
3300
|
+
}
|
|
3301
|
+
return buildCombinedRouteMapWithSearch(
|
|
3302
|
+
resolutionFile,
|
|
3303
|
+
variableName,
|
|
3304
|
+
visited,
|
|
3305
|
+
diagnosticsOut,
|
|
3306
|
+
void 0,
|
|
3307
|
+
memo
|
|
3308
|
+
);
|
|
3309
|
+
}
|
|
3310
|
+
function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut, inlineBlock, memo) {
|
|
2767
3311
|
visited = visited ?? /* @__PURE__ */ new Set();
|
|
3312
|
+
memo = memo ?? createScanMemo();
|
|
2768
3313
|
const realPath = resolve2(filePath);
|
|
2769
3314
|
const key = variableName ? `${realPath}:${variableName}` : realPath;
|
|
2770
3315
|
if (visited.has(key)) {
|
|
@@ -2774,7 +3319,7 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
|
|
|
2774
3319
|
visited.add(key);
|
|
2775
3320
|
let source;
|
|
2776
3321
|
try {
|
|
2777
|
-
source =
|
|
3322
|
+
source = readSourceMemoized(memo, realPath);
|
|
2778
3323
|
} catch {
|
|
2779
3324
|
return { routes: {}, searchSchemas: {} };
|
|
2780
3325
|
}
|
|
@@ -2782,7 +3327,11 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
|
|
|
2782
3327
|
if (inlineBlock) {
|
|
2783
3328
|
block = inlineBlock;
|
|
2784
3329
|
} else if (variableName) {
|
|
2785
|
-
const extracted = extractUrlsBlockForVariable(
|
|
3330
|
+
const extracted = extractUrlsBlockForVariable(
|
|
3331
|
+
source,
|
|
3332
|
+
variableName,
|
|
3333
|
+
parseBlock(memo, source)
|
|
3334
|
+
);
|
|
2786
3335
|
if (!extracted) return { routes: {}, searchSchemas: {} };
|
|
2787
3336
|
block = extracted;
|
|
2788
3337
|
} else {
|
|
@@ -2795,7 +3344,8 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
|
|
|
2795
3344
|
realPath,
|
|
2796
3345
|
visited,
|
|
2797
3346
|
searchSchemas,
|
|
2798
|
-
diagnosticsOut
|
|
3347
|
+
diagnosticsOut,
|
|
3348
|
+
memo
|
|
2799
3349
|
);
|
|
2800
3350
|
visited.delete(key);
|
|
2801
3351
|
return { routes, searchSchemas };
|
|
@@ -2810,7 +3360,7 @@ import {
|
|
|
2810
3360
|
readdirSync
|
|
2811
3361
|
} from "node:fs";
|
|
2812
3362
|
import {
|
|
2813
|
-
join,
|
|
3363
|
+
join as join2,
|
|
2814
3364
|
dirname as dirname2,
|
|
2815
3365
|
resolve as resolve3,
|
|
2816
3366
|
sep,
|
|
@@ -2833,7 +3383,10 @@ var ROUTER_CALL_PATTERN_G = /\bcreateRouter\s*[<(]/g;
|
|
|
2833
3383
|
function isRoutableSourceFile(name) {
|
|
2834
3384
|
return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
|
|
2835
3385
|
}
|
|
2836
|
-
function
|
|
3386
|
+
function isExcludedScanDir(name) {
|
|
3387
|
+
return name === "node_modules" || name === "dist" || name === "coverage" || name === "__tests__" || name === "__mocks__" || name.startsWith(".");
|
|
3388
|
+
}
|
|
3389
|
+
function findCallSiteFilesRecursive(dir, pattern, patternG, stopAtMatchDir, filter, results) {
|
|
2837
3390
|
let entries;
|
|
2838
3391
|
try {
|
|
2839
3392
|
entries = readdirSync(dir, { withFileTypes: true });
|
|
@@ -2844,32 +3397,36 @@ function findRouterFilesRecursive(dir, filter, results) {
|
|
|
2844
3397
|
return;
|
|
2845
3398
|
}
|
|
2846
3399
|
const childDirs = [];
|
|
2847
|
-
const
|
|
3400
|
+
const matchesInDir = [];
|
|
2848
3401
|
for (const entry of entries) {
|
|
2849
|
-
const fullPath =
|
|
3402
|
+
const fullPath = join2(dir, entry.name);
|
|
2850
3403
|
if (entry.isDirectory()) {
|
|
2851
|
-
if (entry.name
|
|
2852
|
-
continue;
|
|
2853
|
-
childDirs.push(fullPath);
|
|
3404
|
+
if (!isExcludedScanDir(entry.name)) childDirs.push(fullPath);
|
|
2854
3405
|
continue;
|
|
2855
3406
|
}
|
|
2856
3407
|
if (!isRoutableSourceFile(entry.name)) continue;
|
|
2857
3408
|
if (filter && !filter(fullPath)) continue;
|
|
2858
3409
|
try {
|
|
2859
3410
|
const source = readFileSync2(fullPath, "utf-8");
|
|
2860
|
-
if (
|
|
2861
|
-
|
|
3411
|
+
if (pattern.test(source) && firstCodeMatchIndex(source, patternG) >= 0) {
|
|
3412
|
+
matchesInDir.push(fullPath);
|
|
2862
3413
|
}
|
|
2863
3414
|
} catch {
|
|
2864
3415
|
continue;
|
|
2865
3416
|
}
|
|
2866
3417
|
}
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
3418
|
+
results.push(...matchesInDir);
|
|
3419
|
+
if (!stopAtMatchDir || matchesInDir.length === 0) {
|
|
3420
|
+
for (const childDir of childDirs) {
|
|
3421
|
+
findCallSiteFilesRecursive(
|
|
3422
|
+
childDir,
|
|
3423
|
+
pattern,
|
|
3424
|
+
patternG,
|
|
3425
|
+
stopAtMatchDir,
|
|
3426
|
+
filter,
|
|
3427
|
+
results
|
|
3428
|
+
);
|
|
3429
|
+
}
|
|
2873
3430
|
}
|
|
2874
3431
|
}
|
|
2875
3432
|
function findNestedRouterConflict(routerFiles) {
|
|
@@ -3006,7 +3563,7 @@ function applyBasenameToRoutes(result, basename2) {
|
|
|
3006
3563
|
}
|
|
3007
3564
|
function genFileTsPath(sourceFile) {
|
|
3008
3565
|
const base = pathBasename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
3009
|
-
return
|
|
3566
|
+
return join2(dirname2(sourceFile), `${base}.named-routes.gen.ts`);
|
|
3010
3567
|
}
|
|
3011
3568
|
function resolveSearchSchemas(publicRouteNames, runtimeSchemas, sourceFile) {
|
|
3012
3569
|
if (runtimeSchemas && Object.keys(runtimeSchemas).length > 0) {
|
|
@@ -3067,12 +3624,33 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
|
3067
3624
|
}
|
|
3068
3625
|
function findRouterFiles(root, filter) {
|
|
3069
3626
|
const result = [];
|
|
3070
|
-
|
|
3627
|
+
findCallSiteFilesRecursive(
|
|
3628
|
+
root,
|
|
3629
|
+
ROUTER_CALL_PATTERN,
|
|
3630
|
+
ROUTER_CALL_PATTERN_G,
|
|
3631
|
+
true,
|
|
3632
|
+
filter,
|
|
3633
|
+
result
|
|
3634
|
+
);
|
|
3635
|
+
return result;
|
|
3636
|
+
}
|
|
3637
|
+
var HOST_ROUTER_CALL_PATTERN = /\bcreateHostRouter\s*[<(]/;
|
|
3638
|
+
var HOST_ROUTER_CALL_PATTERN_G = /\bcreateHostRouter\s*[<(]/g;
|
|
3639
|
+
function findHostRouterFiles(root, filter) {
|
|
3640
|
+
const result = [];
|
|
3641
|
+
findCallSiteFilesRecursive(
|
|
3642
|
+
root,
|
|
3643
|
+
HOST_ROUTER_CALL_PATTERN,
|
|
3644
|
+
HOST_ROUTER_CALL_PATTERN_G,
|
|
3645
|
+
false,
|
|
3646
|
+
filter,
|
|
3647
|
+
result
|
|
3648
|
+
);
|
|
3071
3649
|
return result;
|
|
3072
3650
|
}
|
|
3073
3651
|
function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
3074
3652
|
try {
|
|
3075
|
-
const oldCombinedPath =
|
|
3653
|
+
const oldCombinedPath = join2(root, "src", "named-routes.gen.ts");
|
|
3076
3654
|
if (existsSync3(oldCombinedPath)) {
|
|
3077
3655
|
unlinkSync(oldCombinedPath);
|
|
3078
3656
|
console.log(
|
|
@@ -3133,7 +3711,28 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
|
3133
3711
|
}
|
|
3134
3712
|
|
|
3135
3713
|
// src/vite/plugins/version-plugin.ts
|
|
3714
|
+
import { parseAst as parseAst4 } from "vite";
|
|
3715
|
+
|
|
3716
|
+
// src/vite/utils/directive-prologue.ts
|
|
3136
3717
|
import { parseAst as parseAst3 } from "vite";
|
|
3718
|
+
function hasUseClientDirective(source) {
|
|
3719
|
+
let program;
|
|
3720
|
+
try {
|
|
3721
|
+
program = parseAst3(source, { lang: "tsx" });
|
|
3722
|
+
} catch {
|
|
3723
|
+
return false;
|
|
3724
|
+
}
|
|
3725
|
+
for (const node of program.body ?? []) {
|
|
3726
|
+
if (node?.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
|
|
3727
|
+
if (node.expression.value === "use client") return true;
|
|
3728
|
+
continue;
|
|
3729
|
+
}
|
|
3730
|
+
break;
|
|
3731
|
+
}
|
|
3732
|
+
return false;
|
|
3733
|
+
}
|
|
3734
|
+
|
|
3735
|
+
// src/vite/plugins/version-plugin.ts
|
|
3137
3736
|
function isCodeModule(id) {
|
|
3138
3737
|
return /\.(tsx?|jsx?)($|\?)/.test(id);
|
|
3139
3738
|
}
|
|
@@ -3141,23 +3740,13 @@ function normalizeModuleId(id) {
|
|
|
3141
3740
|
return id.split("?", 1)[0];
|
|
3142
3741
|
}
|
|
3143
3742
|
function getClientModuleSignature(source) {
|
|
3743
|
+
if (!hasUseClientDirective(source)) return void 0;
|
|
3144
3744
|
let program;
|
|
3145
3745
|
try {
|
|
3146
|
-
program =
|
|
3746
|
+
program = parseAst4(source, { lang: "tsx" });
|
|
3147
3747
|
} catch {
|
|
3148
3748
|
return void 0;
|
|
3149
3749
|
}
|
|
3150
|
-
let isUseClient = false;
|
|
3151
|
-
for (const node of program.body ?? []) {
|
|
3152
|
-
if (node?.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
|
|
3153
|
-
if (node.expression.value === "use client") {
|
|
3154
|
-
isUseClient = true;
|
|
3155
|
-
}
|
|
3156
|
-
continue;
|
|
3157
|
-
}
|
|
3158
|
-
break;
|
|
3159
|
-
}
|
|
3160
|
-
if (!isUseClient) return void 0;
|
|
3161
3750
|
const exports = /* @__PURE__ */ new Set();
|
|
3162
3751
|
let hasDefault = false;
|
|
3163
3752
|
let hasExportAll = false;
|
|
@@ -3282,7 +3871,6 @@ function createVersionPlugin() {
|
|
|
3282
3871
|
}
|
|
3283
3872
|
return null;
|
|
3284
3873
|
},
|
|
3285
|
-
// Track RSC module changes and update version
|
|
3286
3874
|
async hotUpdate(ctx) {
|
|
3287
3875
|
if (!isDev) return;
|
|
3288
3876
|
const isRscModule = this.environment?.name === "rsc";
|
|
@@ -3331,6 +3919,7 @@ function isViteDepCachePath(filePath, cacheDir) {
|
|
|
3331
3919
|
|
|
3332
3920
|
// src/vite/utils/shared-utils.ts
|
|
3333
3921
|
import * as Vite from "vite";
|
|
3922
|
+
import { isAbsolute, resolve as resolve4 } from "node:path";
|
|
3334
3923
|
|
|
3335
3924
|
// src/vite/plugins/performance-tracks.ts
|
|
3336
3925
|
import { readFile } from "node:fs/promises";
|
|
@@ -3359,9 +3948,6 @@ function performanceTracksOptimizeDepsPlugin() {
|
|
|
3359
3948
|
const RSDW_CLIENT_RE = /react-server-dom-webpack-client\.browser\.(development|production)\.js$/;
|
|
3360
3949
|
return {
|
|
3361
3950
|
name: "@rangojs/router:performance-tracks-optimize-deps",
|
|
3362
|
-
// Vite 8 optimizes deps with Rolldown (Rollup-style plugin pipeline), so the
|
|
3363
|
-
// pre-bundled RSDW client is patched via load() rather than esbuild's onLoad.
|
|
3364
|
-
// Returning code overrides Rolldown's default filesystem read for the module.
|
|
3365
3951
|
async load(id) {
|
|
3366
3952
|
const cleanId = id.split("?")[0] ?? id;
|
|
3367
3953
|
if (!RSDW_CLIENT_RE.test(cleanId)) return null;
|
|
@@ -3416,6 +4002,21 @@ var versionRolldownPlugin = {
|
|
|
3416
4002
|
var sharedRolldownOptions = {
|
|
3417
4003
|
plugins: [versionRolldownPlugin, performanceTracksOptimizeDepsPlugin()]
|
|
3418
4004
|
};
|
|
4005
|
+
function normalizeHostRouterEntry(rawInput, root, exists) {
|
|
4006
|
+
const raw = rawInput.replaceAll("\\", "/");
|
|
4007
|
+
const isRelative = raw.startsWith("./") || raw.startsWith("../");
|
|
4008
|
+
const isRooted = raw.startsWith("/") || isAbsolute(rawInput);
|
|
4009
|
+
if (isRooted) return raw;
|
|
4010
|
+
if (isRelative) {
|
|
4011
|
+
if (!exists(resolve4(root, raw))) {
|
|
4012
|
+
throw new Error(
|
|
4013
|
+
`[rango] hostRouter entry not found: "${rawInput}" (resolved under ${root}). Point it at your createHostRouter() module, e.g. rango({ hostRouter: "./src/worker.rsc.tsx" }).`
|
|
4014
|
+
);
|
|
4015
|
+
}
|
|
4016
|
+
return raw;
|
|
4017
|
+
}
|
|
4018
|
+
return exists(resolve4(root, raw)) ? "./" + raw : raw;
|
|
4019
|
+
}
|
|
3419
4020
|
function createVirtualEntriesPlugin(entries, routerPathRef) {
|
|
3420
4021
|
const virtualModules = {};
|
|
3421
4022
|
if (entries.client === VIRTUAL_IDS.browser) {
|
|
@@ -3449,7 +4050,7 @@ function createVirtualEntriesPlugin(entries, routerPathRef) {
|
|
|
3449
4050
|
if (virtualId === VIRTUAL_IDS.rsc && routerPathRef?.path) {
|
|
3450
4051
|
const raw = routerPathRef.path.startsWith(".") ? "/" + routerPathRef.path.slice(2) : routerPathRef.path;
|
|
3451
4052
|
const absoluteRouterPath = raw.replaceAll("\\", "/");
|
|
3452
|
-
return getVirtualEntryRSC(absoluteRouterPath);
|
|
4053
|
+
return routerPathRef.kind === "host" ? getVirtualEntryRSCHost(absoluteRouterPath) : getVirtualEntryRSC(absoluteRouterPath);
|
|
3453
4054
|
}
|
|
3454
4055
|
}
|
|
3455
4056
|
return null;
|
|
@@ -3504,7 +4105,7 @@ function getManualChunks(id) {
|
|
|
3504
4105
|
}
|
|
3505
4106
|
|
|
3506
4107
|
// src/vite/plugins/client-ref-hashing.ts
|
|
3507
|
-
import { relative } from "node:path";
|
|
4108
|
+
import { relative as relative2 } from "node:path";
|
|
3508
4109
|
import { createHash as createHash2 } from "node:crypto";
|
|
3509
4110
|
var debug7 = createRangoDebugger(NS.transform);
|
|
3510
4111
|
var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
|
|
@@ -3521,10 +4122,10 @@ function computeProductionHash(projectRoot, refKey) {
|
|
|
3521
4122
|
const absPath = decodeURIComponent(
|
|
3522
4123
|
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
|
|
3523
4124
|
);
|
|
3524
|
-
toHash =
|
|
4125
|
+
toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
|
|
3525
4126
|
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
3526
4127
|
const absPath = refKey.slice(FS_PREFIX.length - 1);
|
|
3527
|
-
toHash =
|
|
4128
|
+
toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
|
|
3528
4129
|
} else if (refKey.startsWith("/")) {
|
|
3529
4130
|
toHash = refKey.slice(1);
|
|
3530
4131
|
} else {
|
|
@@ -3551,7 +4152,6 @@ function hashClientRefs(projectRoot) {
|
|
|
3551
4152
|
const counter = createCounter(debug7, "hash-client-refs");
|
|
3552
4153
|
return {
|
|
3553
4154
|
name: "@rangojs/router:hash-client-refs",
|
|
3554
|
-
// Run after the RSC plugin's transform (default enforce is normal)
|
|
3555
4155
|
enforce: "post",
|
|
3556
4156
|
applyToEnvironment(env) {
|
|
3557
4157
|
return env.name === "rsc";
|
|
@@ -3602,31 +4202,246 @@ function directoryClientChunks(meta, ctx) {
|
|
|
3602
4202
|
if (isSharedRuntime(meta)) {
|
|
3603
4203
|
return void 0;
|
|
3604
4204
|
}
|
|
3605
|
-
if (ctx?.fallbackRefs.size && ctx.fallbackRefs.has(hashRefKey(meta.normalizedId))) {
|
|
3606
|
-
debugChunks?.("fallback %s -> app-fallback", meta.normalizedId);
|
|
3607
|
-
return "app-fallback";
|
|
4205
|
+
if (ctx?.fallbackRefs.size && ctx.fallbackRefs.has(hashRefKey(meta.normalizedId))) {
|
|
4206
|
+
debugChunks?.("fallback %s -> app-fallback", meta.normalizedId);
|
|
4207
|
+
return "app-fallback";
|
|
4208
|
+
}
|
|
4209
|
+
const segments = meta.normalizedId.split("/").filter(Boolean);
|
|
4210
|
+
const dirCount = segments.length - 1;
|
|
4211
|
+
if (dirCount >= 1) {
|
|
4212
|
+
for (let i = 0; i < dirCount - 1; i++) {
|
|
4213
|
+
if (ROUTE_ROOT_DIRS.has(segments[i].toLowerCase())) {
|
|
4214
|
+
const group = `app-${sanitizeGroup(segments[i + 1])}`;
|
|
4215
|
+
debugChunks?.("split %s -> %s", meta.normalizedId, group);
|
|
4216
|
+
return group;
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4220
|
+
debugChunks?.(
|
|
4221
|
+
"shared %s (no route-root marker; inherits default grouping)",
|
|
4222
|
+
meta.normalizedId
|
|
4223
|
+
);
|
|
4224
|
+
return void 0;
|
|
4225
|
+
}
|
|
4226
|
+
function resolveClientChunks(option, ctx) {
|
|
4227
|
+
if (!option) return void 0;
|
|
4228
|
+
if (option === true) return (meta) => directoryClientChunks(meta, ctx);
|
|
4229
|
+
return option;
|
|
4230
|
+
}
|
|
4231
|
+
|
|
4232
|
+
// src/vite/plugins/vercel-output.ts
|
|
4233
|
+
import { rm, mkdir, cp, writeFile } from "node:fs/promises";
|
|
4234
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
4235
|
+
import { resolve as resolve5, join as join3 } from "node:path";
|
|
4236
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
4237
|
+
import { pathToFileURL } from "node:url";
|
|
4238
|
+
var LAUNCHER_SOURCE = `import { toNodeHandler } from "srvx/node";
|
|
4239
|
+
import { waitUntil } from "@vercel/functions";
|
|
4240
|
+
import rscHandler from "./rsc/index.js";
|
|
4241
|
+
|
|
4242
|
+
// The Vercel Node launcher invokes a Node (req, res) handler, not a Web fetch
|
|
4243
|
+
// handler. srvx's toNodeHandler bridges the Rango Web fetch handler and pipes
|
|
4244
|
+
// the streamed Response to the Node response (set supportsResponseStreaming).
|
|
4245
|
+
const onVercel = Boolean(process.env.VERCEL);
|
|
4246
|
+
|
|
4247
|
+
const fetchHandler = (request) =>
|
|
4248
|
+
rscHandler(request, {
|
|
4249
|
+
env: process.env,
|
|
4250
|
+
// Forward Vercel's waitUntil so cache writes / revalidation run off the
|
|
4251
|
+
// response path. Omitted off-platform so those writes settle inline.
|
|
4252
|
+
ctx: onVercel ? { waitUntil } : undefined,
|
|
4253
|
+
});
|
|
4254
|
+
|
|
4255
|
+
export default toNodeHandler(fetchHandler);
|
|
4256
|
+
`;
|
|
4257
|
+
function assertVercelNodeRuntime(runtime) {
|
|
4258
|
+
if (runtime != null && !runtime.startsWith("nodejs")) {
|
|
4259
|
+
throw new Error(
|
|
4260
|
+
`[rango] preset "vercel": runtime "${runtime}" is not supported. This preset emits a Node serverless function; use a "nodejs*" runtime (default "nodejs22.x"). The Edge runtime is not supported.`
|
|
4261
|
+
);
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4264
|
+
function assertValidVercelFunctionName(functionName) {
|
|
4265
|
+
if (!/^[A-Za-z0-9._-]+$/.test(functionName)) {
|
|
4266
|
+
throw new Error(
|
|
4267
|
+
`[rango] preset "vercel": invalid functionName ${JSON.stringify(
|
|
4268
|
+
functionName
|
|
4269
|
+
)}. Use letters, digits, ".", "_" or "-" only (it becomes the .func directory and the routing dest).`
|
|
4270
|
+
);
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
function buildVercelVcConfig(vercel) {
|
|
4274
|
+
const vcConfig = {
|
|
4275
|
+
runtime: vercel.runtime ?? "nodejs22.x",
|
|
4276
|
+
handler: "index.mjs",
|
|
4277
|
+
launcherType: "Nodejs",
|
|
4278
|
+
shouldAddHelpers: false,
|
|
4279
|
+
supportsResponseStreaming: true,
|
|
4280
|
+
maxDuration: vercel.maxDuration ?? 30
|
|
4281
|
+
};
|
|
4282
|
+
if (vercel.memory != null) vcConfig.memory = vercel.memory;
|
|
4283
|
+
if (vercel.regions != null) vcConfig.regions = vercel.regions;
|
|
4284
|
+
return vcConfig;
|
|
4285
|
+
}
|
|
4286
|
+
function buildVercelOutputConfig(functionName, assetsDir) {
|
|
4287
|
+
const assetsPrefix = assetsDir.replace(/^\/+|\/+$/g, "");
|
|
4288
|
+
const assetHeaderRoute = assetsPrefix ? [
|
|
4289
|
+
{
|
|
4290
|
+
src: `/${escapeRegExp(assetsPrefix)}/(.*)`,
|
|
4291
|
+
headers: { "cache-control": "public, max-age=31536000, immutable" },
|
|
4292
|
+
continue: true
|
|
4293
|
+
}
|
|
4294
|
+
] : [];
|
|
4295
|
+
return {
|
|
4296
|
+
version: 3,
|
|
4297
|
+
routes: [
|
|
4298
|
+
...assetHeaderRoute,
|
|
4299
|
+
{ handle: "filesystem" },
|
|
4300
|
+
{ src: "/(.*)", dest: `/${functionName}` }
|
|
4301
|
+
]
|
|
4302
|
+
};
|
|
4303
|
+
}
|
|
4304
|
+
async function assemble(root, options, assetsDir, publicDir) {
|
|
4305
|
+
const vercel = options.vercel ?? {};
|
|
4306
|
+
assertVercelNodeRuntime(vercel.runtime);
|
|
4307
|
+
const assetsPrefix = assetsDir.replace(/^\/+|\/+$/g, "");
|
|
4308
|
+
if (publicDir && assetsPrefix && existsSync4(join3(publicDir, assetsPrefix))) {
|
|
4309
|
+
console.warn(
|
|
4310
|
+
`[rango] preset "vercel": ${join3(publicDir, assetsPrefix)} exists. Files under public/${assetsPrefix}/ share the /${assetsPrefix}/ URL prefix with hashed build assets and will be served with a one-year immutable cache-control header. Move un-hashed public files out of "${assetsPrefix}/".`
|
|
4311
|
+
);
|
|
4312
|
+
}
|
|
4313
|
+
const dist = join3(root, "dist");
|
|
4314
|
+
for (const dir of ["client", "rsc", "ssr"]) {
|
|
4315
|
+
if (!existsSync4(join3(dist, dir))) {
|
|
4316
|
+
throw new Error(
|
|
4317
|
+
`[rango] preset "vercel": missing dist/${dir}. Run the production build first.`
|
|
4318
|
+
);
|
|
4319
|
+
}
|
|
4320
|
+
}
|
|
4321
|
+
const functionName = vercel.functionName ?? "index";
|
|
4322
|
+
assertValidVercelFunctionName(functionName);
|
|
4323
|
+
const out = join3(root, ".vercel", "output");
|
|
4324
|
+
const funcDir = join3(out, "functions", `${functionName}.func`);
|
|
4325
|
+
await rm(out, { recursive: true, force: true });
|
|
4326
|
+
await mkdir(funcDir, { recursive: true });
|
|
4327
|
+
await cp(join3(dist, "client"), join3(out, "static"), { recursive: true });
|
|
4328
|
+
await cp(join3(dist, "rsc"), join3(funcDir, "rsc"), { recursive: true });
|
|
4329
|
+
await cp(join3(dist, "ssr"), join3(funcDir, "ssr"), { recursive: true });
|
|
4330
|
+
if (existsSync4(join3(dist, "static"))) {
|
|
4331
|
+
await cp(join3(dist, "static"), join3(funcDir, "static"), {
|
|
4332
|
+
recursive: true
|
|
4333
|
+
});
|
|
4334
|
+
}
|
|
4335
|
+
const rangoRequire = createRequire2(import.meta.url);
|
|
4336
|
+
let srvxNodePath;
|
|
4337
|
+
try {
|
|
4338
|
+
srvxNodePath = rangoRequire.resolve("srvx/node");
|
|
4339
|
+
} catch {
|
|
4340
|
+
throw new Error(
|
|
4341
|
+
'[rango] preset "vercel" requires "srvx" (a dependency of @rangojs/router). Reinstall dependencies.'
|
|
4342
|
+
);
|
|
4343
|
+
}
|
|
4344
|
+
const appRequire = createRequire2(join3(root, "package.json"));
|
|
4345
|
+
const resolveEsbuildPath = () => {
|
|
4346
|
+
try {
|
|
4347
|
+
const viteRequire = createRequire2(appRequire.resolve("vite"));
|
|
4348
|
+
return viteRequire.resolve("esbuild");
|
|
4349
|
+
} catch {
|
|
4350
|
+
}
|
|
4351
|
+
try {
|
|
4352
|
+
return appRequire.resolve("esbuild");
|
|
4353
|
+
} catch {
|
|
4354
|
+
}
|
|
4355
|
+
return rangoRequire.resolve("esbuild");
|
|
4356
|
+
};
|
|
4357
|
+
let esbuildModule;
|
|
4358
|
+
try {
|
|
4359
|
+
esbuildModule = await import(pathToFileURL(resolveEsbuildPath()).href);
|
|
4360
|
+
} catch {
|
|
4361
|
+
throw new Error(
|
|
4362
|
+
'[rango] preset "vercel" requires "esbuild" to bundle the function launcher. It ships with Vite; reinstall dependencies (or add esbuild to your app dependencies).'
|
|
4363
|
+
);
|
|
4364
|
+
}
|
|
4365
|
+
const esbuildBuild = esbuildModule.build ?? esbuildModule.default?.build;
|
|
4366
|
+
if (typeof esbuildBuild !== "function") {
|
|
4367
|
+
throw new Error('[rango] preset "vercel": could not load esbuild.build.');
|
|
3608
4368
|
}
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
4369
|
+
try {
|
|
4370
|
+
await esbuildBuild({
|
|
4371
|
+
stdin: {
|
|
4372
|
+
contents: LAUNCHER_SOURCE,
|
|
4373
|
+
resolveDir: root,
|
|
4374
|
+
sourcefile: "func-entry.mjs",
|
|
4375
|
+
loader: "js"
|
|
4376
|
+
},
|
|
4377
|
+
outfile: join3(funcDir, "index.mjs"),
|
|
4378
|
+
bundle: true,
|
|
4379
|
+
format: "esm",
|
|
4380
|
+
platform: "node",
|
|
4381
|
+
target: "node18",
|
|
4382
|
+
alias: { "srvx/node": srvxNodePath },
|
|
4383
|
+
plugins: [
|
|
4384
|
+
{
|
|
4385
|
+
name: "external-rsc-entry",
|
|
4386
|
+
setup(b) {
|
|
4387
|
+
b.onResolve({ filter: /^\.\/rsc\/index\.js$/ }, () => ({
|
|
4388
|
+
path: "./rsc/index.js",
|
|
4389
|
+
external: true
|
|
4390
|
+
}));
|
|
4391
|
+
}
|
|
4392
|
+
}
|
|
4393
|
+
]
|
|
4394
|
+
});
|
|
4395
|
+
} catch (error) {
|
|
4396
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4397
|
+
if (/@vercel\/functions/.test(message)) {
|
|
4398
|
+
throw new Error(
|
|
4399
|
+
'[rango] preset "vercel": could not resolve "@vercel/functions". Add it to your app dependencies (it also backs VercelCacheStore).\n' + message
|
|
4400
|
+
);
|
|
3618
4401
|
}
|
|
4402
|
+
throw error;
|
|
3619
4403
|
}
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
4404
|
+
await writeFile(
|
|
4405
|
+
join3(funcDir, "package.json"),
|
|
4406
|
+
JSON.stringify({ type: "module" }, null, 2) + "\n"
|
|
4407
|
+
);
|
|
4408
|
+
await writeFile(
|
|
4409
|
+
join3(funcDir, ".vc-config.json"),
|
|
4410
|
+
JSON.stringify(buildVercelVcConfig(vercel), null, 2) + "\n"
|
|
4411
|
+
);
|
|
4412
|
+
await writeFile(
|
|
4413
|
+
join3(out, "config.json"),
|
|
4414
|
+
JSON.stringify(buildVercelOutputConfig(functionName, assetsDir), null, 2) + "\n"
|
|
4415
|
+
);
|
|
4416
|
+
console.log(
|
|
4417
|
+
`[rango] assembled .vercel/output (function: ${functionName}.func)`
|
|
3623
4418
|
);
|
|
3624
|
-
return void 0;
|
|
3625
4419
|
}
|
|
3626
|
-
function
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
4420
|
+
function createVercelOutputPlugin(options) {
|
|
4421
|
+
let root = process.cwd();
|
|
4422
|
+
let isBuild = false;
|
|
4423
|
+
let assetsDir = "assets";
|
|
4424
|
+
let publicDir = "";
|
|
4425
|
+
return {
|
|
4426
|
+
name: "@rangojs/router:vercel-output",
|
|
4427
|
+
configResolved(config) {
|
|
4428
|
+
root = resolve5(config.root);
|
|
4429
|
+
isBuild = config.command === "build";
|
|
4430
|
+
assetsDir = config.environments?.client?.build?.assetsDir ?? config.build?.assetsDir ?? "assets";
|
|
4431
|
+
publicDir = config.publicDir || "";
|
|
4432
|
+
},
|
|
4433
|
+
// buildApp runs once after the whole multi-environment build (rsc, client,
|
|
4434
|
+
// ssr), so dist/ is complete here. closeBundle is unusable for this: it
|
|
4435
|
+
// fires per environment, and twice for ssr (the server-reference scan and
|
|
4436
|
+
// the real build), so it would run before dist/client exists.
|
|
4437
|
+
buildApp: {
|
|
4438
|
+
order: "post",
|
|
4439
|
+
async handler() {
|
|
4440
|
+
if (!isBuild) return;
|
|
4441
|
+
await assemble(root, options, assetsDir, publicDir);
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4444
|
+
};
|
|
3630
4445
|
}
|
|
3631
4446
|
|
|
3632
4447
|
// src/vite/utils/banner.ts
|
|
@@ -3656,7 +4471,7 @@ ${dim} ${reset}${bold}\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550$
|
|
|
3656
4471
|
}
|
|
3657
4472
|
|
|
3658
4473
|
// src/vite/plugins/version-injector.ts
|
|
3659
|
-
import { resolve as
|
|
4474
|
+
import { resolve as resolve6 } from "node:path";
|
|
3660
4475
|
import * as Vite2 from "vite";
|
|
3661
4476
|
function createVersionInjectorPlugin(rscEntryPath) {
|
|
3662
4477
|
let resolvedEntryPath = "";
|
|
@@ -3667,7 +4482,7 @@ function createVersionInjectorPlugin(rscEntryPath) {
|
|
|
3667
4482
|
let entryPath = rscEntryPath;
|
|
3668
4483
|
if (!entryPath) entryPath = resolveRscEntryFromConfig(config);
|
|
3669
4484
|
if (entryPath) {
|
|
3670
|
-
resolvedEntryPath =
|
|
4485
|
+
resolvedEntryPath = resolve6(config.root, entryPath);
|
|
3671
4486
|
}
|
|
3672
4487
|
},
|
|
3673
4488
|
transform(code, id) {
|
|
@@ -3677,9 +4492,9 @@ function createVersionInjectorPlugin(rscEntryPath) {
|
|
|
3677
4492
|
if (normalizedId !== normalizedEntry) {
|
|
3678
4493
|
return null;
|
|
3679
4494
|
}
|
|
3680
|
-
const prepend =
|
|
3681
|
-
`import "
|
|
3682
|
-
|
|
4495
|
+
const prepend = RSC_ENTRY_BOOTSTRAP_IMPORTS.map(
|
|
4496
|
+
(id2) => `import "${id2}";`
|
|
4497
|
+
);
|
|
3683
4498
|
let newCode = code;
|
|
3684
4499
|
const needsVersion = code.includes("createRSCHandler") && !code.includes("@rangojs/router:version") && /createRSCHandler\s*\(\s*\{/.test(code);
|
|
3685
4500
|
if (needsVersion) {
|
|
@@ -3715,13 +4530,17 @@ function createVersionInjectorPlugin(rscEntryPath) {
|
|
|
3715
4530
|
// src/vite/plugins/cjs-to-esm.ts
|
|
3716
4531
|
var debug8 = createRangoDebugger(NS.transform);
|
|
3717
4532
|
function createCjsToEsmPlugin() {
|
|
4533
|
+
let isProduction = false;
|
|
3718
4534
|
return {
|
|
3719
4535
|
name: "@rangojs/router:cjs-to-esm",
|
|
3720
4536
|
enforce: "pre",
|
|
4537
|
+
configResolved(config) {
|
|
4538
|
+
isProduction = config.isProduction;
|
|
4539
|
+
},
|
|
3721
4540
|
transform(code, id) {
|
|
3722
4541
|
const cleanId = id.split("?")[0].replaceAll("\\", "/");
|
|
3723
4542
|
if (cleanId.includes("vendor/react-server-dom/client.browser.js")) {
|
|
3724
|
-
const isProd =
|
|
4543
|
+
const isProd = isProduction;
|
|
3725
4544
|
const cjsFile = isProd ? "./cjs/react-server-dom-webpack-client.browser.production.js" : "./cjs/react-server-dom-webpack-client.browser.development.js";
|
|
3726
4545
|
debug8?.("cjs-to-esm entry redirect %s", id);
|
|
3727
4546
|
return {
|
|
@@ -3772,10 +4591,39 @@ function createCjsToEsmPlugin() {
|
|
|
3772
4591
|
|
|
3773
4592
|
// src/vite/router-discovery.ts
|
|
3774
4593
|
import { createServer as createViteServer } from "vite";
|
|
3775
|
-
import { resolve as
|
|
4594
|
+
import { resolve as resolve10 } from "node:path";
|
|
3776
4595
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
3777
|
-
import { createRequire as
|
|
3778
|
-
import { pathToFileURL } from "node:url";
|
|
4596
|
+
import { createRequire as createRequire3, register } from "node:module";
|
|
4597
|
+
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
4598
|
+
|
|
4599
|
+
// src/vite/inject-client-debug.ts
|
|
4600
|
+
function isRouterInternalDebugId(id) {
|
|
4601
|
+
if (!id.includes("internal-debug")) return false;
|
|
4602
|
+
const norm = id.replace(/\\/g, "/");
|
|
4603
|
+
return /\/internal-debug\.[cm]?[jt]sx?(\?|$)/.test(norm) && (norm.includes("/@rangojs/router/") || norm.includes("/packages/rangojs-router/"));
|
|
4604
|
+
}
|
|
4605
|
+
function injectClientDebugFlag(id) {
|
|
4606
|
+
if (!isRouterInternalDebugId(id)) return null;
|
|
4607
|
+
return {
|
|
4608
|
+
code: `export const INTERNAL_RANGO_DEBUG = ${!!process.env.INTERNAL_RANGO_DEBUG};
|
|
4609
|
+
`,
|
|
4610
|
+
map: null
|
|
4611
|
+
};
|
|
4612
|
+
}
|
|
4613
|
+
function internalDebugNoCacheMiddleware() {
|
|
4614
|
+
return function rangoInternalDebugNoCache(req, res, next) {
|
|
4615
|
+
if (req.url && isRouterInternalDebugId(req.url)) {
|
|
4616
|
+
const setHeader = res.setHeader.bind(res);
|
|
4617
|
+
res.setHeader = (name, value) => {
|
|
4618
|
+
return setHeader(
|
|
4619
|
+
name,
|
|
4620
|
+
name.toLowerCase() === "cache-control" ? "no-cache" : value
|
|
4621
|
+
);
|
|
4622
|
+
};
|
|
4623
|
+
}
|
|
4624
|
+
next();
|
|
4625
|
+
};
|
|
4626
|
+
}
|
|
3779
4627
|
|
|
3780
4628
|
// src/vite/plugins/virtual-stub-plugin.ts
|
|
3781
4629
|
function createVirtualStubPlugin() {
|
|
@@ -4060,7 +4908,93 @@ function checkSelfGenWrite(state, filePath, consume) {
|
|
|
4060
4908
|
}
|
|
4061
4909
|
}
|
|
4062
4910
|
|
|
4063
|
-
// src/
|
|
4911
|
+
// src/router/logging.ts
|
|
4912
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4913
|
+
|
|
4914
|
+
// src/internal-debug.ts
|
|
4915
|
+
var INTERNAL_RANGO_DEBUG = typeof process !== "undefined" && Boolean(process.env?.INTERNAL_RANGO_DEBUG);
|
|
4916
|
+
|
|
4917
|
+
// src/router/logging.ts
|
|
4918
|
+
var routerLogContext = new AsyncLocalStorage();
|
|
4919
|
+
|
|
4920
|
+
// src/router/url-params.ts
|
|
4921
|
+
var PATH_SAFE_ESCAPES = {
|
|
4922
|
+
"%3A": ":",
|
|
4923
|
+
"%40": "@",
|
|
4924
|
+
"%24": "$",
|
|
4925
|
+
"%26": "&",
|
|
4926
|
+
"%2B": "+",
|
|
4927
|
+
"%2C": ",",
|
|
4928
|
+
"%3B": ";",
|
|
4929
|
+
"%3D": "="
|
|
4930
|
+
};
|
|
4931
|
+
function encodePathSegment(value) {
|
|
4932
|
+
return encodeURIComponent(value).replace(
|
|
4933
|
+
/%(?:3A|40|24|26|2B|2C|3B|3D)/gi,
|
|
4934
|
+
(match) => PATH_SAFE_ESCAPES[match.toUpperCase()] ?? match
|
|
4935
|
+
);
|
|
4936
|
+
}
|
|
4937
|
+
function encodePathRemainder(value, encode = encodePathSegment) {
|
|
4938
|
+
return value.split("/").map(encode).join("/");
|
|
4939
|
+
}
|
|
4940
|
+
|
|
4941
|
+
// src/router/parse-pattern.ts
|
|
4942
|
+
function parsePattern(pattern) {
|
|
4943
|
+
const segments = [];
|
|
4944
|
+
const segmentRegex = /\/(:([a-zA-Z_][a-zA-Z0-9_]*)(\(([^)]+)\))?(\?)?([+*])?([^/]*)|(\*)|([^/]+))/g;
|
|
4945
|
+
let match;
|
|
4946
|
+
while ((match = segmentRegex.exec(pattern)) !== null) {
|
|
4947
|
+
const [
|
|
4948
|
+
,
|
|
4949
|
+
,
|
|
4950
|
+
paramName,
|
|
4951
|
+
,
|
|
4952
|
+
constraint,
|
|
4953
|
+
optional,
|
|
4954
|
+
repeat,
|
|
4955
|
+
suffix,
|
|
4956
|
+
wildcard,
|
|
4957
|
+
staticText
|
|
4958
|
+
] = match;
|
|
4959
|
+
if (wildcard) {
|
|
4960
|
+
segments.push({ type: "wildcard", value: "*", optional: false });
|
|
4961
|
+
} else if (paramName) {
|
|
4962
|
+
if (repeat && !suffix && optional !== "?" && !constraint) {
|
|
4963
|
+
segments.push({
|
|
4964
|
+
type: "wildcard",
|
|
4965
|
+
value: paramName,
|
|
4966
|
+
optional: false,
|
|
4967
|
+
oneOrMore: repeat === "+"
|
|
4968
|
+
});
|
|
4969
|
+
} else {
|
|
4970
|
+
segments.push({
|
|
4971
|
+
type: "param",
|
|
4972
|
+
value: paramName,
|
|
4973
|
+
optional: optional === "?",
|
|
4974
|
+
constraint: constraint ? constraint.split("|") : void 0,
|
|
4975
|
+
// Fold a non-modifier `+`/`*` back into the literal suffix.
|
|
4976
|
+
suffix: (repeat ?? "") + (suffix ?? "") || void 0
|
|
4977
|
+
});
|
|
4978
|
+
}
|
|
4979
|
+
} else if (staticText) {
|
|
4980
|
+
segments.push({ type: "static", value: staticText, optional: false });
|
|
4981
|
+
}
|
|
4982
|
+
}
|
|
4983
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
4984
|
+
const s = segments[i];
|
|
4985
|
+
if (s.type === "wildcard" && s.value !== "*") {
|
|
4986
|
+
segments[i] = {
|
|
4987
|
+
type: "param",
|
|
4988
|
+
value: s.value,
|
|
4989
|
+
optional: false,
|
|
4990
|
+
suffix: s.oneOrMore ? "+" : "*"
|
|
4991
|
+
};
|
|
4992
|
+
}
|
|
4993
|
+
}
|
|
4994
|
+
return segments;
|
|
4995
|
+
}
|
|
4996
|
+
|
|
4997
|
+
// src/build/prefix-tree-utils.ts
|
|
4064
4998
|
function flattenLeafEntries(prefixTree, routeManifest, result) {
|
|
4065
4999
|
function visit(node, ancestorStaticPrefixes) {
|
|
4066
5000
|
const children = node.children || {};
|
|
@@ -4101,6 +5035,226 @@ function buildRouteToStaticPrefix(prefixTree, result) {
|
|
|
4101
5035
|
visit(node);
|
|
4102
5036
|
}
|
|
4103
5037
|
}
|
|
5038
|
+
|
|
5039
|
+
// src/build/route-trie.ts
|
|
5040
|
+
function buildRouteTrie(routeManifest, routeAncestry, routeToStaticPrefix, routeTrailingSlash, prerenderRouteNames, passthroughRouteNames, responseTypeRoutes) {
|
|
5041
|
+
const root = {};
|
|
5042
|
+
for (const [routeName, pattern] of Object.entries(routeManifest)) {
|
|
5043
|
+
const ancestry = routeAncestry[routeName] || [];
|
|
5044
|
+
const staticPrefix = routeToStaticPrefix[routeName] || "";
|
|
5045
|
+
const trailingSlash = routeTrailingSlash?.[routeName];
|
|
5046
|
+
const responseType = responseTypeRoutes?.[routeName];
|
|
5047
|
+
const hasTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
|
|
5048
|
+
const normalizedPattern = hasTrailingSlash ? pattern.slice(0, -1) : pattern;
|
|
5049
|
+
const segments = parsePattern(normalizedPattern);
|
|
5050
|
+
insertRoute(root, segments, 0, {
|
|
5051
|
+
n: routeName,
|
|
5052
|
+
sp: staticPrefix,
|
|
5053
|
+
a: ancestry,
|
|
5054
|
+
...trailingSlash ? { ts: trailingSlash } : {},
|
|
5055
|
+
...prerenderRouteNames?.has(routeName) ? { pr: true } : {},
|
|
5056
|
+
...passthroughRouteNames?.has(routeName) ? { pt: true } : {},
|
|
5057
|
+
...responseType ? { rt: responseType } : {}
|
|
5058
|
+
});
|
|
5059
|
+
}
|
|
5060
|
+
sortSuffixParams(root);
|
|
5061
|
+
return root;
|
|
5062
|
+
}
|
|
5063
|
+
function sortSuffixParams(node) {
|
|
5064
|
+
if (node.xp) {
|
|
5065
|
+
const sorted = {};
|
|
5066
|
+
for (const suffix of Object.keys(node.xp).sort(
|
|
5067
|
+
(a, b) => b.length - a.length
|
|
5068
|
+
)) {
|
|
5069
|
+
sorted[suffix] = node.xp[suffix];
|
|
5070
|
+
}
|
|
5071
|
+
node.xp = sorted;
|
|
5072
|
+
for (const child of Object.values(node.xp)) {
|
|
5073
|
+
sortSuffixParams(child.c);
|
|
5074
|
+
}
|
|
5075
|
+
}
|
|
5076
|
+
if (node.s) {
|
|
5077
|
+
for (const child of Object.values(node.s)) {
|
|
5078
|
+
sortSuffixParams(child);
|
|
5079
|
+
}
|
|
5080
|
+
}
|
|
5081
|
+
if (node.p) {
|
|
5082
|
+
sortSuffixParams(node.p.c);
|
|
5083
|
+
}
|
|
5084
|
+
}
|
|
5085
|
+
function buildPerRouterTrie(manifest) {
|
|
5086
|
+
const ancestry = manifest._routeAncestry;
|
|
5087
|
+
if (!ancestry || Object.keys(ancestry).length === 0) {
|
|
5088
|
+
return null;
|
|
5089
|
+
}
|
|
5090
|
+
const routeToStaticPrefix = {};
|
|
5091
|
+
for (const name of Object.keys(manifest.routeManifest)) {
|
|
5092
|
+
routeToStaticPrefix[name] = "";
|
|
5093
|
+
}
|
|
5094
|
+
if (manifest.prefixTree) {
|
|
5095
|
+
buildRouteToStaticPrefix(manifest.prefixTree, routeToStaticPrefix);
|
|
5096
|
+
}
|
|
5097
|
+
return buildRouteTrie(
|
|
5098
|
+
manifest.routeManifest,
|
|
5099
|
+
ancestry,
|
|
5100
|
+
routeToStaticPrefix,
|
|
5101
|
+
manifest.routeTrailingSlash,
|
|
5102
|
+
manifest.prerenderRoutes ? new Set(manifest.prerenderRoutes) : void 0,
|
|
5103
|
+
manifest.passthroughRoutes ? new Set(manifest.passthroughRoutes) : void 0,
|
|
5104
|
+
manifest.responseTypeRoutes
|
|
5105
|
+
);
|
|
5106
|
+
}
|
|
5107
|
+
function insertRoute(node, segments, index, leaf) {
|
|
5108
|
+
const constraints = {};
|
|
5109
|
+
for (const seg of segments) {
|
|
5110
|
+
if (seg.type === "param") {
|
|
5111
|
+
if (seg.constraint) {
|
|
5112
|
+
constraints[seg.value] = seg.constraint;
|
|
5113
|
+
}
|
|
5114
|
+
}
|
|
5115
|
+
}
|
|
5116
|
+
const leafBase = {
|
|
5117
|
+
...leaf,
|
|
5118
|
+
...Object.keys(constraints).length > 0 ? { cv: constraints } : {}
|
|
5119
|
+
};
|
|
5120
|
+
insertSegments(node, segments, index, leafBase, []);
|
|
5121
|
+
}
|
|
5122
|
+
function toVariant(leaf, responseType) {
|
|
5123
|
+
return leaf.pa ? { routeKey: leaf.n, responseType, pa: leaf.pa } : { routeKey: leaf.n, responseType };
|
|
5124
|
+
}
|
|
5125
|
+
function mergeLeaves(existing, leaf) {
|
|
5126
|
+
if (!existing) return leaf;
|
|
5127
|
+
if (existing.rt && leaf.rt) {
|
|
5128
|
+
const merged = leaf;
|
|
5129
|
+
merged.nv = existing.nv || [];
|
|
5130
|
+
merged.nv.push(toVariant(existing, existing.rt));
|
|
5131
|
+
return merged;
|
|
5132
|
+
}
|
|
5133
|
+
if (leaf.rt && !existing.rt) {
|
|
5134
|
+
if (!existing.nv) {
|
|
5135
|
+
existing.nv = [];
|
|
5136
|
+
existing.rf = true;
|
|
5137
|
+
}
|
|
5138
|
+
existing.nv.push(toVariant(leaf, leaf.rt));
|
|
5139
|
+
return existing;
|
|
5140
|
+
}
|
|
5141
|
+
if (!leaf.rt && existing.rt) {
|
|
5142
|
+
if (!leaf.nv) leaf.nv = [];
|
|
5143
|
+
if (existing.nv) leaf.nv.push(...existing.nv);
|
|
5144
|
+
leaf.nv.push(toVariant(existing, existing.rt));
|
|
5145
|
+
return leaf;
|
|
5146
|
+
}
|
|
5147
|
+
return leaf;
|
|
5148
|
+
}
|
|
5149
|
+
function mergeLeaf(node, leaf) {
|
|
5150
|
+
node.r = mergeLeaves(node.r, leaf);
|
|
5151
|
+
}
|
|
5152
|
+
function buildLeaf(leafBase, paramNames) {
|
|
5153
|
+
return paramNames.length > 0 ? { ...leafBase, pa: [...paramNames] } : { ...leafBase };
|
|
5154
|
+
}
|
|
5155
|
+
function insertSegments(node, segments, index, leafBase, paramNames) {
|
|
5156
|
+
if (index >= segments.length) {
|
|
5157
|
+
mergeLeaf(node, buildLeaf(leafBase, paramNames));
|
|
5158
|
+
return;
|
|
5159
|
+
}
|
|
5160
|
+
const segment = segments[index];
|
|
5161
|
+
if (segment.type === "static") {
|
|
5162
|
+
if (!node.s) node.s = {};
|
|
5163
|
+
if (!node.s[segment.value]) node.s[segment.value] = {};
|
|
5164
|
+
insertSegments(
|
|
5165
|
+
node.s[segment.value],
|
|
5166
|
+
segments,
|
|
5167
|
+
index + 1,
|
|
5168
|
+
leafBase,
|
|
5169
|
+
paramNames
|
|
5170
|
+
);
|
|
5171
|
+
} else if (segment.type === "param") {
|
|
5172
|
+
if (segment.optional) {
|
|
5173
|
+
insertSegments(node, segments, index + 1, leafBase, paramNames);
|
|
5174
|
+
}
|
|
5175
|
+
if (segment.suffix) {
|
|
5176
|
+
if (!node.xp) node.xp = {};
|
|
5177
|
+
if (!node.xp[segment.suffix]) {
|
|
5178
|
+
node.xp[segment.suffix] = { n: segment.value, c: {} };
|
|
5179
|
+
}
|
|
5180
|
+
insertSegments(node.xp[segment.suffix].c, segments, index + 1, leafBase, [
|
|
5181
|
+
...paramNames,
|
|
5182
|
+
segment.value
|
|
5183
|
+
]);
|
|
5184
|
+
} else {
|
|
5185
|
+
if (!node.p) {
|
|
5186
|
+
node.p = { n: segment.value, c: {} };
|
|
5187
|
+
}
|
|
5188
|
+
insertSegments(node.p.c, segments, index + 1, leafBase, [
|
|
5189
|
+
...paramNames,
|
|
5190
|
+
segment.value
|
|
5191
|
+
]);
|
|
5192
|
+
}
|
|
5193
|
+
} else if (segment.type === "wildcard") {
|
|
5194
|
+
const wildLeaf = {
|
|
5195
|
+
...buildLeaf(leafBase, paramNames),
|
|
5196
|
+
pn: segment.value,
|
|
5197
|
+
...segment.oneOrMore ? { w1: true } : {}
|
|
5198
|
+
};
|
|
5199
|
+
const existing = node.w;
|
|
5200
|
+
const canMerge = existing === void 0 || Boolean(existing.rt) || Boolean(wildLeaf.rt) || existing.pn === wildLeaf.pn && Boolean(existing.w1) === Boolean(wildLeaf.w1);
|
|
5201
|
+
if (canMerge) {
|
|
5202
|
+
const merged = mergeLeaves(
|
|
5203
|
+
existing ? { ...existing } : void 0,
|
|
5204
|
+
wildLeaf
|
|
5205
|
+
);
|
|
5206
|
+
node.w = merged;
|
|
5207
|
+
}
|
|
5208
|
+
}
|
|
5209
|
+
}
|
|
5210
|
+
|
|
5211
|
+
// src/build/collect-fallback-refs.ts
|
|
5212
|
+
var CLIENT_REF = /* @__PURE__ */ Symbol.for("react.client.reference");
|
|
5213
|
+
var MAX_DEPTH = 40;
|
|
5214
|
+
var SYNTHETIC_PROPS = {
|
|
5215
|
+
error: new Error("rango: build-time fallback-chunk discovery"),
|
|
5216
|
+
reset: () => {
|
|
5217
|
+
},
|
|
5218
|
+
pathname: "/",
|
|
5219
|
+
info: { componentStack: "" }
|
|
5220
|
+
};
|
|
5221
|
+
function isReactNodeLike(v) {
|
|
5222
|
+
return Array.isArray(v) || typeof v === "object" && v !== null && "$$typeof" in v;
|
|
5223
|
+
}
|
|
5224
|
+
function walkElementTree(node, report, depth) {
|
|
5225
|
+
if (node == null || depth > MAX_DEPTH) return;
|
|
5226
|
+
if (Array.isArray(node)) {
|
|
5227
|
+
for (const child of node) walkElementTree(child, report, depth + 1);
|
|
5228
|
+
return;
|
|
5229
|
+
}
|
|
5230
|
+
if (typeof node !== "object") return;
|
|
5231
|
+
const el = node;
|
|
5232
|
+
const type = el.type;
|
|
5233
|
+
if (type?.$$typeof === CLIENT_REF && typeof type.$$id === "string") {
|
|
5234
|
+
report(type.$$id.split("#")[0]);
|
|
5235
|
+
}
|
|
5236
|
+
const props = el.props;
|
|
5237
|
+
if (props && typeof props === "object") {
|
|
5238
|
+
walkElementTree(props.children, report, depth + 1);
|
|
5239
|
+
for (const key in props) {
|
|
5240
|
+
if (key === "children") continue;
|
|
5241
|
+
const value = props[key];
|
|
5242
|
+
if (isReactNodeLike(value)) walkElementTree(value, report, depth + 1);
|
|
5243
|
+
}
|
|
5244
|
+
}
|
|
5245
|
+
}
|
|
5246
|
+
function collectFallbackClientRefs(boundary, report) {
|
|
5247
|
+
try {
|
|
5248
|
+
let node = boundary;
|
|
5249
|
+
if (typeof node === "function") {
|
|
5250
|
+
node = node(SYNTHETIC_PROPS);
|
|
5251
|
+
}
|
|
5252
|
+
walkElementTree(node, report, 0);
|
|
5253
|
+
} catch {
|
|
5254
|
+
}
|
|
5255
|
+
}
|
|
5256
|
+
|
|
5257
|
+
// src/vite/utils/manifest-utils.ts
|
|
4104
5258
|
function jsonParseExpression(value) {
|
|
4105
5259
|
const json = JSON.stringify(value);
|
|
4106
5260
|
const escaped = json.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
@@ -4108,6 +5262,9 @@ function jsonParseExpression(value) {
|
|
|
4108
5262
|
}
|
|
4109
5263
|
|
|
4110
5264
|
// src/context-var.ts
|
|
5265
|
+
function hasContextVars(variables) {
|
|
5266
|
+
return Object.keys(variables).length > 0 || Object.getOwnPropertySymbols(variables).length > 0;
|
|
5267
|
+
}
|
|
4111
5268
|
var NON_CACHEABLE_KEYS = /* @__PURE__ */ Symbol.for(
|
|
4112
5269
|
"rango:non-cacheable-keys"
|
|
4113
5270
|
);
|
|
@@ -4141,24 +5298,31 @@ function contextSet(variables, keyOrVar, value, options) {
|
|
|
4141
5298
|
import { createHash as createHash4 } from "node:crypto";
|
|
4142
5299
|
import {
|
|
4143
5300
|
copyFileSync,
|
|
4144
|
-
existsSync as
|
|
5301
|
+
existsSync as existsSync5,
|
|
4145
5302
|
mkdirSync,
|
|
4146
5303
|
rmSync,
|
|
4147
5304
|
statSync,
|
|
4148
5305
|
writeFileSync as writeFileSync2
|
|
4149
5306
|
} from "node:fs";
|
|
4150
|
-
import { resolve as
|
|
4151
|
-
function escapeRegExp2(str) {
|
|
4152
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4153
|
-
}
|
|
5307
|
+
import { resolve as resolve7 } from "node:path";
|
|
4154
5308
|
function encodePathParam(value) {
|
|
4155
|
-
return String(value)
|
|
5309
|
+
return encodePathRemainder(String(value), encodeURIComponent);
|
|
4156
5310
|
}
|
|
4157
5311
|
function substituteRouteParams(pattern, params, encode = encodeURIComponent) {
|
|
4158
5312
|
let result = pattern;
|
|
4159
5313
|
let hadOmittedOptional = false;
|
|
4160
5314
|
for (const [key, value] of Object.entries(params)) {
|
|
4161
|
-
const escaped =
|
|
5315
|
+
const escaped = escapeRegExp(key);
|
|
5316
|
+
const catchAllRe = new RegExp(`:${escaped}[+*]`);
|
|
5317
|
+
if (catchAllRe.test(result)) {
|
|
5318
|
+
if (value === "") {
|
|
5319
|
+
result = result.replace(catchAllRe, "");
|
|
5320
|
+
hadOmittedOptional = true;
|
|
5321
|
+
} else {
|
|
5322
|
+
result = result.replace(catchAllRe, encodePathRemainder(value, encode));
|
|
5323
|
+
}
|
|
5324
|
+
continue;
|
|
5325
|
+
}
|
|
4162
5326
|
if (value === "") {
|
|
4163
5327
|
result = result.replace(
|
|
4164
5328
|
new RegExp(`:${escaped}(\\([^)]*\\))?(?!\\?)`),
|
|
@@ -4191,13 +5355,24 @@ async function runWithConcurrency(items, concurrency, fn) {
|
|
|
4191
5355
|
return;
|
|
4192
5356
|
}
|
|
4193
5357
|
let nextIndex = 0;
|
|
5358
|
+
let firstError;
|
|
5359
|
+
let failed = false;
|
|
4194
5360
|
async function worker() {
|
|
4195
|
-
while (nextIndex < items.length) {
|
|
5361
|
+
while (nextIndex < items.length && !failed) {
|
|
4196
5362
|
const idx = nextIndex++;
|
|
4197
|
-
|
|
5363
|
+
try {
|
|
5364
|
+
await fn(items[idx]);
|
|
5365
|
+
} catch (err) {
|
|
5366
|
+
if (!failed) {
|
|
5367
|
+
failed = true;
|
|
5368
|
+
firstError = err;
|
|
5369
|
+
}
|
|
5370
|
+
return;
|
|
5371
|
+
}
|
|
4198
5372
|
}
|
|
4199
5373
|
}
|
|
4200
5374
|
await Promise.all(Array.from({ length: limit }, () => worker()));
|
|
5375
|
+
if (failed) throw firstError;
|
|
4201
5376
|
}
|
|
4202
5377
|
function groupByConcurrency(entries) {
|
|
4203
5378
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -4244,8 +5419,25 @@ function notifyOnError(registry, error, phase, routeKey, pathname, skipped) {
|
|
|
4244
5419
|
break;
|
|
4245
5420
|
}
|
|
4246
5421
|
}
|
|
5422
|
+
function resolvePrerenderError(registry, error, onError, label, elapsed, phase, routeKey, pathname) {
|
|
5423
|
+
const isSkip = error?.name === "Skip";
|
|
5424
|
+
if (isSkip || onError === "warn") {
|
|
5425
|
+
if (isSkip) {
|
|
5426
|
+
console.log(`[rango] SKIP ${label} (${elapsed}ms) - ${error.message}`);
|
|
5427
|
+
} else {
|
|
5428
|
+
console.warn(
|
|
5429
|
+
`[rango] WARN ${label} (${elapsed}ms) - render error, not pre-rendered (prerender.onError: "warn"): ${error.message}`
|
|
5430
|
+
);
|
|
5431
|
+
}
|
|
5432
|
+
notifyOnError(registry, error, phase, routeKey, pathname, true);
|
|
5433
|
+
return;
|
|
5434
|
+
}
|
|
5435
|
+
console.error(`[rango] FAIL ${label} (${elapsed}ms) - ${error.message}`);
|
|
5436
|
+
notifyOnError(registry, error, phase, routeKey, pathname);
|
|
5437
|
+
throw error;
|
|
5438
|
+
}
|
|
4247
5439
|
function getStagedAssetDir(projectRoot) {
|
|
4248
|
-
return
|
|
5440
|
+
return resolve7(projectRoot, "node_modules/.rangojs-router-build/rsc-assets");
|
|
4249
5441
|
}
|
|
4250
5442
|
function resetStagedBuildAssets(projectRoot) {
|
|
4251
5443
|
rmSync(getStagedAssetDir(projectRoot), { recursive: true, force: true });
|
|
@@ -4255,8 +5447,8 @@ function stageBuildAssetModule(projectRoot, prefix, exportValue) {
|
|
|
4255
5447
|
mkdirSync(stagedDir, { recursive: true });
|
|
4256
5448
|
const contentHash = createHash4("sha256").update(exportValue).digest("hex").slice(0, 8);
|
|
4257
5449
|
const fileName = `${prefix}-${contentHash}.js`;
|
|
4258
|
-
const filePath =
|
|
4259
|
-
if (!
|
|
5450
|
+
const filePath = resolve7(stagedDir, fileName);
|
|
5451
|
+
if (!existsSync5(filePath)) {
|
|
4260
5452
|
writeFileSync2(filePath, `export default ${exportValue};
|
|
4261
5453
|
`);
|
|
4262
5454
|
}
|
|
@@ -4264,12 +5456,12 @@ function stageBuildAssetModule(projectRoot, prefix, exportValue) {
|
|
|
4264
5456
|
}
|
|
4265
5457
|
function copyStagedBuildAssets(projectRoot, fileNames) {
|
|
4266
5458
|
const stagedDir = getStagedAssetDir(projectRoot);
|
|
4267
|
-
const distAssetsDir =
|
|
5459
|
+
const distAssetsDir = resolve7(projectRoot, "dist/rsc/assets");
|
|
4268
5460
|
mkdirSync(distAssetsDir, { recursive: true });
|
|
4269
5461
|
let totalBytes = 0;
|
|
4270
5462
|
for (const fileName of new Set(fileNames)) {
|
|
4271
|
-
const stagedPath =
|
|
4272
|
-
const distPath =
|
|
5463
|
+
const stagedPath = resolve7(stagedDir, fileName);
|
|
5464
|
+
const distPath = resolve7(distAssetsDir, fileName);
|
|
4273
5465
|
copyFileSync(stagedPath, distPath);
|
|
4274
5466
|
totalBytes += statSync(stagedPath).size;
|
|
4275
5467
|
}
|
|
@@ -4360,7 +5552,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4360
5552
|
(performance.now() - getParamsStart).toFixed(1)
|
|
4361
5553
|
);
|
|
4362
5554
|
const concurrency = def.options?.concurrency ?? 1;
|
|
4363
|
-
const hasBuildVars =
|
|
5555
|
+
const hasBuildVars = hasContextVars(buildVars);
|
|
4364
5556
|
for (const params of paramsList) {
|
|
4365
5557
|
let url = substituteRouteParams(
|
|
4366
5558
|
pattern,
|
|
@@ -4445,6 +5637,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4445
5637
|
const manifestEntries = {};
|
|
4446
5638
|
let doneCount = 0;
|
|
4447
5639
|
let skipCount = 0;
|
|
5640
|
+
const prerenderOnError = state.opts?.prerenderOnError ?? "fail";
|
|
4448
5641
|
const startTotal = performance.now();
|
|
4449
5642
|
const groups = groupByConcurrency(entries);
|
|
4450
5643
|
for (const group of groups) {
|
|
@@ -4487,10 +5680,9 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4487
5680
|
const interceptKey = `${result.routeName}/${paramHash}/i`;
|
|
4488
5681
|
const interceptValue = JSON.stringify({
|
|
4489
5682
|
segments: [...result.segments, ...result.interceptSegments],
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
}
|
|
5683
|
+
// interceptHandles is the pre-encoded MERGED (main + intercept)
|
|
5684
|
+
// handle string (the producer merged before encoding).
|
|
5685
|
+
handles: result.interceptHandles ?? ""
|
|
4494
5686
|
});
|
|
4495
5687
|
manifestEntries[interceptKey] = stageBuildAssetModule(
|
|
4496
5688
|
state.projectRoot,
|
|
@@ -4505,34 +5697,19 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
4505
5697
|
doneCount++;
|
|
4506
5698
|
break;
|
|
4507
5699
|
} catch (err) {
|
|
4508
|
-
if (err.name === "Skip") {
|
|
4509
|
-
const elapsed2 = (performance.now() - startUrl).toFixed(0);
|
|
4510
|
-
console.log(
|
|
4511
|
-
`[rango] SKIP ${entry.urlPath.padEnd(40)} (${elapsed2}ms) - ${err.message}`
|
|
4512
|
-
);
|
|
4513
|
-
skipCount++;
|
|
4514
|
-
notifyOnError(
|
|
4515
|
-
registry,
|
|
4516
|
-
err,
|
|
4517
|
-
"prerender",
|
|
4518
|
-
entry.routeName,
|
|
4519
|
-
entry.urlPath,
|
|
4520
|
-
true
|
|
4521
|
-
);
|
|
4522
|
-
break;
|
|
4523
|
-
}
|
|
4524
5700
|
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
4525
|
-
|
|
4526
|
-
`[rango] FAIL ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`
|
|
4527
|
-
);
|
|
4528
|
-
notifyOnError(
|
|
5701
|
+
resolvePrerenderError(
|
|
4529
5702
|
registry,
|
|
4530
5703
|
err,
|
|
5704
|
+
prerenderOnError,
|
|
5705
|
+
entry.urlPath.padEnd(40),
|
|
5706
|
+
elapsed,
|
|
4531
5707
|
"prerender",
|
|
4532
5708
|
entry.routeName,
|
|
4533
5709
|
entry.urlPath
|
|
4534
5710
|
);
|
|
4535
|
-
|
|
5711
|
+
skipCount++;
|
|
5712
|
+
break;
|
|
4536
5713
|
}
|
|
4537
5714
|
}
|
|
4538
5715
|
}
|
|
@@ -4567,6 +5744,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4567
5744
|
let staticDone = 0;
|
|
4568
5745
|
let staticSkip = 0;
|
|
4569
5746
|
let totalStaticCount = 0;
|
|
5747
|
+
const prerenderOnError = state.opts?.prerenderOnError ?? "fail";
|
|
4570
5748
|
for (const [, exportNames] of state.resolvedStaticModules) {
|
|
4571
5749
|
totalStaticCount += exportNames.length;
|
|
4572
5750
|
}
|
|
@@ -4600,7 +5778,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4600
5778
|
!state.isBuildMode
|
|
4601
5779
|
);
|
|
4602
5780
|
if (result) {
|
|
4603
|
-
const hasHandles =
|
|
5781
|
+
const hasHandles = result.handles !== "";
|
|
4604
5782
|
const exportValue = hasHandles ? JSON.stringify(result) : JSON.stringify(result.encoded);
|
|
4605
5783
|
manifestEntries[def.$$id] = stageBuildAssetModule(
|
|
4606
5784
|
state.projectRoot,
|
|
@@ -4614,22 +5792,18 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
4614
5792
|
break;
|
|
4615
5793
|
}
|
|
4616
5794
|
} catch (err) {
|
|
4617
|
-
if (err.name === "Skip") {
|
|
4618
|
-
const elapsed2 = (performance.now() - startHandler).toFixed(0);
|
|
4619
|
-
console.log(
|
|
4620
|
-
`[rango] SKIP ${name.padEnd(40)} (${elapsed2}ms) - ${err.message}`
|
|
4621
|
-
);
|
|
4622
|
-
staticSkip++;
|
|
4623
|
-
notifyOnError(registry, err, "static", void 0, void 0, true);
|
|
4624
|
-
handled = true;
|
|
4625
|
-
break;
|
|
4626
|
-
}
|
|
4627
5795
|
const elapsed = (performance.now() - startHandler).toFixed(0);
|
|
4628
|
-
|
|
4629
|
-
|
|
5796
|
+
resolvePrerenderError(
|
|
5797
|
+
registry,
|
|
5798
|
+
err,
|
|
5799
|
+
prerenderOnError,
|
|
5800
|
+
name.padEnd(40),
|
|
5801
|
+
elapsed,
|
|
5802
|
+
"static"
|
|
4630
5803
|
);
|
|
4631
|
-
|
|
4632
|
-
|
|
5804
|
+
staticSkip++;
|
|
5805
|
+
handled = true;
|
|
5806
|
+
break;
|
|
4633
5807
|
}
|
|
4634
5808
|
}
|
|
4635
5809
|
if (!handled) {
|
|
@@ -4728,6 +5902,28 @@ var DiscoveryError = class _DiscoveryError extends Error {
|
|
|
4728
5902
|
Object.setPrototypeOf(this, _DiscoveryError.prototype);
|
|
4729
5903
|
}
|
|
4730
5904
|
};
|
|
5905
|
+
function describeDiscoveryFailure(err, opts = {}) {
|
|
5906
|
+
if (err instanceof DiscoveryError && err.caught.length === 0) {
|
|
5907
|
+
const entry = err.entryPath ?? "the router entry";
|
|
5908
|
+
if (opts.reoptimizeObserved) {
|
|
5909
|
+
return {
|
|
5910
|
+
level: "warn",
|
|
5911
|
+
message: `[rango] No routers found while Vite was re-optimizing dependencies on dev boot. This is transient: routes are served per-request and discovery re-runs automatically, so it clears on the next boot. If routes still 404, confirm ${entry} calls createRouter().`
|
|
5912
|
+
};
|
|
5913
|
+
}
|
|
5914
|
+
return {
|
|
5915
|
+
level: "error",
|
|
5916
|
+
message: `${err.message}
|
|
5917
|
+
Ensure ${entry} calls createRouter() at module top level and that the configured router entry path is correct.`
|
|
5918
|
+
};
|
|
5919
|
+
}
|
|
5920
|
+
const e = err;
|
|
5921
|
+
const detail = e?.stack ?? e?.message ?? String(err);
|
|
5922
|
+
return {
|
|
5923
|
+
level: "error",
|
|
5924
|
+
message: `[rango] Router discovery failed: ${detail}`
|
|
5925
|
+
};
|
|
5926
|
+
}
|
|
4731
5927
|
|
|
4732
5928
|
// src/vite/discovery/discover-routers.ts
|
|
4733
5929
|
var debug10 = createRangoDebugger(NS.discovery);
|
|
@@ -4803,8 +5999,8 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4803
5999
|
computeProductionHash(state.projectRoot, refKey)
|
|
4804
6000
|
) : void 0;
|
|
4805
6001
|
const collectFromBoundaryNode = (node) => {
|
|
4806
|
-
if (collectClientFallbackRef
|
|
4807
|
-
|
|
6002
|
+
if (collectClientFallbackRef) {
|
|
6003
|
+
collectFallbackClientRefs(node, collectClientFallbackRef);
|
|
4808
6004
|
}
|
|
4809
6005
|
};
|
|
4810
6006
|
const manifestGenStart = debug10 ? performance.now() : 0;
|
|
@@ -4812,7 +6008,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4812
6008
|
if (!router.urlpatterns || !generateManifestFull) {
|
|
4813
6009
|
continue;
|
|
4814
6010
|
}
|
|
4815
|
-
const manifest = generateManifestFull(
|
|
6011
|
+
const manifest = await generateManifestFull(
|
|
4816
6012
|
router.urlpatterns,
|
|
4817
6013
|
routerMountIndex,
|
|
4818
6014
|
{
|
|
@@ -4863,18 +6059,14 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4863
6059
|
if (manifest.routeTrailingSlash) {
|
|
4864
6060
|
Object.assign(mergedRouteTrailingSlash, manifest.routeTrailingSlash);
|
|
4865
6061
|
}
|
|
4866
|
-
flattenLeafEntries(
|
|
4867
|
-
manifest.prefixTree,
|
|
4868
|
-
manifest.routeManifest,
|
|
4869
|
-
newMergedPrecomputedEntries
|
|
4870
|
-
);
|
|
4871
|
-
newPerRouterManifestDataMap.set(id, manifest.routeManifest);
|
|
4872
6062
|
const routerPrecomputed = [];
|
|
4873
6063
|
flattenLeafEntries(
|
|
4874
6064
|
manifest.prefixTree,
|
|
4875
6065
|
manifest.routeManifest,
|
|
4876
6066
|
routerPrecomputed
|
|
4877
6067
|
);
|
|
6068
|
+
newMergedPrecomputedEntries.push(...routerPrecomputed);
|
|
6069
|
+
newPerRouterManifestDataMap.set(id, manifest.routeManifest);
|
|
4878
6070
|
newPerRouterPrecomputedMap.set(id, routerPrecomputed);
|
|
4879
6071
|
console.log(
|
|
4880
6072
|
`[rango] Router "${id}" -> ${routeCount} routes (${staticRoutes} static, ${dynamicRoutes} dynamic)`
|
|
@@ -4898,8 +6090,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4898
6090
|
let newMergedRouteTrie = null;
|
|
4899
6091
|
const trieStart = debug10 ? performance.now() : 0;
|
|
4900
6092
|
if (Object.keys(newMergedRouteManifest).length > 0) {
|
|
4901
|
-
|
|
4902
|
-
if (buildRouteTrie && mergedRouteAncestry) {
|
|
6093
|
+
if (mergedRouteAncestry) {
|
|
4903
6094
|
const routeToStaticPrefix = {};
|
|
4904
6095
|
for (const { manifest } of allManifests) {
|
|
4905
6096
|
for (const name of Object.keys(manifest.routeManifest)) {
|
|
@@ -4937,25 +6128,10 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4937
6128
|
mergedResponseTypeRoutes
|
|
4938
6129
|
);
|
|
4939
6130
|
for (const { id, manifest } of allManifests) {
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
for (const name of Object.keys(manifest.routeManifest)) {
|
|
4944
|
-
perRouterStaticPrefix[name] = "";
|
|
6131
|
+
const perRouterTrie = buildPerRouterTrie(manifest);
|
|
6132
|
+
if (perRouterTrie) {
|
|
6133
|
+
newPerRouterTrieMap.set(id, perRouterTrie);
|
|
4945
6134
|
}
|
|
4946
|
-
buildRouteToStaticPrefix(manifest.prefixTree, perRouterStaticPrefix);
|
|
4947
|
-
const perRouterPrerenderNames = manifest.prerenderRoutes ? new Set(manifest.prerenderRoutes) : void 0;
|
|
4948
|
-
const perRouterPassthroughNames = manifest.passthroughRoutes ? new Set(manifest.passthroughRoutes) : void 0;
|
|
4949
|
-
const perRouterTrie = buildRouteTrie(
|
|
4950
|
-
manifest.routeManifest,
|
|
4951
|
-
manifest._routeAncestry,
|
|
4952
|
-
perRouterStaticPrefix,
|
|
4953
|
-
manifest.routeTrailingSlash,
|
|
4954
|
-
perRouterPrerenderNames,
|
|
4955
|
-
perRouterPassthroughNames,
|
|
4956
|
-
manifest.responseTypeRoutes
|
|
4957
|
-
);
|
|
4958
|
-
newPerRouterTrieMap.set(id, perRouterTrie);
|
|
4959
6135
|
}
|
|
4960
6136
|
}
|
|
4961
6137
|
}
|
|
@@ -4975,9 +6151,46 @@ async function discoverRouters(state, rscEnv) {
|
|
|
4975
6151
|
return serverMod;
|
|
4976
6152
|
}
|
|
4977
6153
|
|
|
6154
|
+
// src/vite/discovery/dev-prerender-cache.ts
|
|
6155
|
+
function payloadBodiesFromResult(result) {
|
|
6156
|
+
const main = JSON.stringify({
|
|
6157
|
+
segments: result.segments,
|
|
6158
|
+
handles: result.handles
|
|
6159
|
+
});
|
|
6160
|
+
const intercept = result.interceptSegments?.length ? JSON.stringify({
|
|
6161
|
+
segments: [...result.segments, ...result.interceptSegments],
|
|
6162
|
+
handles: result.interceptHandles ?? ""
|
|
6163
|
+
}) : main;
|
|
6164
|
+
return { main, intercept };
|
|
6165
|
+
}
|
|
6166
|
+
function devPrerenderCacheKey(pathname, opts) {
|
|
6167
|
+
return `${pathname}|i=${opts.intercept ? 1 : 0}|p=${opts.passthrough ? 1 : 0}|r=${opts.routeName ?? ""}`;
|
|
6168
|
+
}
|
|
6169
|
+
var MAX_ENTRIES_PER_ROUTER = 500;
|
|
6170
|
+
function createDevPrerenderCache(maxEntriesPerRouter = MAX_ENTRIES_PER_ROUTER) {
|
|
6171
|
+
const buckets = /* @__PURE__ */ new WeakMap();
|
|
6172
|
+
return {
|
|
6173
|
+
get(router, key) {
|
|
6174
|
+
return buckets.get(router)?.get(key);
|
|
6175
|
+
},
|
|
6176
|
+
set(router, key, body) {
|
|
6177
|
+
let bucket = buckets.get(router);
|
|
6178
|
+
if (!bucket) {
|
|
6179
|
+
bucket = /* @__PURE__ */ new Map();
|
|
6180
|
+
buckets.set(router, bucket);
|
|
6181
|
+
}
|
|
6182
|
+
if (!bucket.has(key) && bucket.size >= maxEntriesPerRouter) {
|
|
6183
|
+
const oldest = bucket.keys().next().value;
|
|
6184
|
+
if (oldest !== void 0) bucket.delete(oldest);
|
|
6185
|
+
}
|
|
6186
|
+
bucket.set(key, body);
|
|
6187
|
+
}
|
|
6188
|
+
};
|
|
6189
|
+
}
|
|
6190
|
+
|
|
4978
6191
|
// src/vite/discovery/route-types-writer.ts
|
|
4979
|
-
import { dirname as dirname3, join as
|
|
4980
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as
|
|
6192
|
+
import { dirname as dirname3, join as join4, resolve as resolve8 } from "node:path";
|
|
6193
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync6, unlinkSync as unlinkSync2 } from "node:fs";
|
|
4981
6194
|
function filterUserNamedRoutes(manifest) {
|
|
4982
6195
|
const filtered = {};
|
|
4983
6196
|
for (const [name, pattern] of Object.entries(manifest)) {
|
|
@@ -4988,7 +6201,7 @@ function filterUserNamedRoutes(manifest) {
|
|
|
4988
6201
|
return filtered;
|
|
4989
6202
|
}
|
|
4990
6203
|
function writeGenFileIfChanged(state, outPath, source, opts) {
|
|
4991
|
-
const existing =
|
|
6204
|
+
const existing = existsSync6(outPath) ? readFileSync4(outPath, "utf-8") : null;
|
|
4992
6205
|
if (existing === source) return;
|
|
4993
6206
|
markSelfGenWrite(state, outPath, source);
|
|
4994
6207
|
writeFileSync3(outPath, source);
|
|
@@ -5006,10 +6219,10 @@ function writeRouteTypesFiles(state) {
|
|
|
5006
6219
|
if (state.perRouterManifests.length === 0) return;
|
|
5007
6220
|
try {
|
|
5008
6221
|
const entryDir = dirname3(
|
|
5009
|
-
|
|
6222
|
+
resolve8(state.projectRoot, state.resolvedEntryPath)
|
|
5010
6223
|
);
|
|
5011
|
-
const oldCombinedPath =
|
|
5012
|
-
if (
|
|
6224
|
+
const oldCombinedPath = join4(entryDir, "named-routes.gen.ts");
|
|
6225
|
+
if (existsSync6(oldCombinedPath)) {
|
|
5013
6226
|
unlinkSync2(oldCombinedPath);
|
|
5014
6227
|
console.log(
|
|
5015
6228
|
`[rango] Removed stale combined route types: ${oldCombinedPath}`
|
|
@@ -5090,7 +6303,7 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
5090
6303
|
}
|
|
5091
6304
|
|
|
5092
6305
|
// src/vite/discovery/virtual-module-codegen.ts
|
|
5093
|
-
import { dirname as dirname4, basename, join as
|
|
6306
|
+
import { dirname as dirname4, basename, join as join5 } from "node:path";
|
|
5094
6307
|
function generateRoutesManifestModule(state) {
|
|
5095
6308
|
const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
|
|
5096
6309
|
if (hasManifest) {
|
|
@@ -5105,7 +6318,7 @@ function generateRoutesManifestModule(state) {
|
|
|
5105
6318
|
/\.(tsx?|jsx?)$/,
|
|
5106
6319
|
""
|
|
5107
6320
|
);
|
|
5108
|
-
const genPath =
|
|
6321
|
+
const genPath = join5(
|
|
5109
6322
|
routerDir,
|
|
5110
6323
|
`${routerBasename}.named-routes.gen.js`
|
|
5111
6324
|
).replaceAll("\\", "/");
|
|
@@ -5190,7 +6403,7 @@ function generatePerRouterModule(state, routerId) {
|
|
|
5190
6403
|
/\.(tsx?|jsx?)$/,
|
|
5191
6404
|
""
|
|
5192
6405
|
);
|
|
5193
|
-
const genPath =
|
|
6406
|
+
const genPath = join5(
|
|
5194
6407
|
routerDir,
|
|
5195
6408
|
`${routerBasename}.named-routes.gen.js`
|
|
5196
6409
|
).replaceAll("\\", "/");
|
|
@@ -5213,17 +6426,17 @@ function generatePerRouterModule(state, routerId) {
|
|
|
5213
6426
|
`export const precomputedEntries = ${jsonParseExpression(entries)};`
|
|
5214
6427
|
);
|
|
5215
6428
|
}
|
|
5216
|
-
return lines.join("\n") || "
|
|
6429
|
+
return lines.join("\n") || "";
|
|
5217
6430
|
}
|
|
5218
6431
|
|
|
5219
6432
|
// src/vite/discovery/bundle-postprocess.ts
|
|
5220
|
-
import { resolve as
|
|
5221
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as
|
|
6433
|
+
import { resolve as resolve9 } from "node:path";
|
|
6434
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync7 } from "node:fs";
|
|
5222
6435
|
function postprocessBundle(state) {
|
|
5223
6436
|
const hasPrerenderData = state.prerenderManifestEntries && Object.keys(state.prerenderManifestEntries).length > 0;
|
|
5224
6437
|
const hasStaticData = state.staticManifestEntries && Object.keys(state.staticManifestEntries).length > 0;
|
|
5225
6438
|
if (!hasPrerenderData && !hasStaticData) return;
|
|
5226
|
-
const rscEntryPath =
|
|
6439
|
+
const rscEntryPath = resolve9(
|
|
5227
6440
|
state.projectRoot,
|
|
5228
6441
|
"dist/rsc",
|
|
5229
6442
|
state.rscEntryFileName ?? "index.js"
|
|
@@ -5244,7 +6457,7 @@ function postprocessBundle(state) {
|
|
|
5244
6457
|
];
|
|
5245
6458
|
for (const target of evictionTargets) {
|
|
5246
6459
|
for (const info of target.infos) {
|
|
5247
|
-
const chunkPath =
|
|
6460
|
+
const chunkPath = resolve9(state.projectRoot, "dist/rsc", info.fileName);
|
|
5248
6461
|
try {
|
|
5249
6462
|
const code = readFileSync5(chunkPath, "utf-8");
|
|
5250
6463
|
const result = evictHandlerCode(
|
|
@@ -5269,7 +6482,7 @@ function postprocessBundle(state) {
|
|
|
5269
6482
|
}
|
|
5270
6483
|
state.handlerChunkInfoMap.clear();
|
|
5271
6484
|
state.staticHandlerChunkInfoMap.clear();
|
|
5272
|
-
if (hasPrerenderData &&
|
|
6485
|
+
if (hasPrerenderData && existsSync7(rscEntryPath)) {
|
|
5273
6486
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
5274
6487
|
if (!rscCode.includes("__prerender-manifest.js")) {
|
|
5275
6488
|
try {
|
|
@@ -5284,12 +6497,12 @@ function postprocessBundle(state) {
|
|
|
5284
6497
|
manifestMap[key] = `./assets/${assetFileName}`;
|
|
5285
6498
|
}
|
|
5286
6499
|
const manifestCode = [
|
|
5287
|
-
`const m
|
|
6500
|
+
`const m=${jsonParseExpression(manifestMap)};`,
|
|
5288
6501
|
`export function loadPrerenderAsset(s){return import(s)}`,
|
|
5289
6502
|
`export default m;`,
|
|
5290
6503
|
""
|
|
5291
6504
|
].join("\n");
|
|
5292
|
-
const manifestPath =
|
|
6505
|
+
const manifestPath = resolve9(
|
|
5293
6506
|
state.projectRoot,
|
|
5294
6507
|
"dist/rsc/__prerender-manifest.js"
|
|
5295
6508
|
);
|
|
@@ -5309,7 +6522,7 @@ function postprocessBundle(state) {
|
|
|
5309
6522
|
}
|
|
5310
6523
|
}
|
|
5311
6524
|
}
|
|
5312
|
-
if (hasStaticData &&
|
|
6525
|
+
if (hasStaticData && existsSync7(rscEntryPath)) {
|
|
5313
6526
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
5314
6527
|
if (!rscCode.includes("__static-manifest.js")) {
|
|
5315
6528
|
try {
|
|
@@ -5327,7 +6540,7 @@ function postprocessBundle(state) {
|
|
|
5327
6540
|
}
|
|
5328
6541
|
const manifestCode = `const m={${manifestEntries.join(",")}};globalThis.__STATIC_MANIFEST=m;export default m;
|
|
5329
6542
|
`;
|
|
5330
|
-
const manifestPath =
|
|
6543
|
+
const manifestPath = resolve9(
|
|
5331
6544
|
state.projectRoot,
|
|
5332
6545
|
"dist/rsc/__static-manifest.js"
|
|
5333
6546
|
);
|
|
@@ -5359,8 +6572,8 @@ function createDiscoveryGate(s, debug11) {
|
|
|
5359
6572
|
let pendingEvents = false;
|
|
5360
6573
|
const beginGate = () => {
|
|
5361
6574
|
if (gatePending) return;
|
|
5362
|
-
s.discoveryDone = new Promise((
|
|
5363
|
-
gateResolver =
|
|
6575
|
+
s.discoveryDone = new Promise((resolve12) => {
|
|
6576
|
+
gateResolver = resolve12;
|
|
5364
6577
|
});
|
|
5365
6578
|
gatePending = true;
|
|
5366
6579
|
};
|
|
@@ -5452,15 +6665,15 @@ function selectForwardableResolvePlugins(plugins) {
|
|
|
5452
6665
|
}
|
|
5453
6666
|
function pickForwardedRunnerConfig(config) {
|
|
5454
6667
|
const r = config.resolve ?? {};
|
|
5455
|
-
const
|
|
5456
|
-
if (r.alias !== void 0)
|
|
5457
|
-
if (r.dedupe !== void 0)
|
|
5458
|
-
if (r.conditions !== void 0)
|
|
5459
|
-
if (r.mainFields !== void 0)
|
|
5460
|
-
if (r.extensions !== void 0)
|
|
6668
|
+
const resolve12 = {};
|
|
6669
|
+
if (r.alias !== void 0) resolve12.alias = r.alias;
|
|
6670
|
+
if (r.dedupe !== void 0) resolve12.dedupe = r.dedupe;
|
|
6671
|
+
if (r.conditions !== void 0) resolve12.conditions = r.conditions;
|
|
6672
|
+
if (r.mainFields !== void 0) resolve12.mainFields = r.mainFields;
|
|
6673
|
+
if (r.extensions !== void 0) resolve12.extensions = r.extensions;
|
|
5461
6674
|
if (r.preserveSymlinks !== void 0)
|
|
5462
|
-
|
|
5463
|
-
if (r.tsconfigPaths !== void 0)
|
|
6675
|
+
resolve12.preserveSymlinks = r.preserveSymlinks;
|
|
6676
|
+
if (r.tsconfigPaths !== void 0) resolve12.tsconfigPaths = r.tsconfigPaths;
|
|
5464
6677
|
const userOxc = config.oxc;
|
|
5465
6678
|
const userJsx = userOxc && typeof userOxc === "object" && typeof userOxc.jsx === "object" && userOxc.jsx !== null ? userOxc.jsx : {};
|
|
5466
6679
|
const oxc = userOxc && typeof userOxc === "object" ? {
|
|
@@ -5468,7 +6681,7 @@ function pickForwardedRunnerConfig(config) {
|
|
|
5468
6681
|
jsx: { ...userJsx, runtime: "automatic", importSource: "react" }
|
|
5469
6682
|
} : { jsx: { runtime: "automatic", importSource: "react" } };
|
|
5470
6683
|
return {
|
|
5471
|
-
resolve:
|
|
6684
|
+
resolve: resolve12,
|
|
5472
6685
|
define: config.define,
|
|
5473
6686
|
oxc
|
|
5474
6687
|
};
|
|
@@ -5546,11 +6759,11 @@ async function resolveBuildEnv(option, factoryCtx) {
|
|
|
5546
6759
|
);
|
|
5547
6760
|
}
|
|
5548
6761
|
try {
|
|
5549
|
-
const userRequire =
|
|
5550
|
-
|
|
6762
|
+
const userRequire = createRequire3(
|
|
6763
|
+
resolve10(factoryCtx.root, "package.json")
|
|
5551
6764
|
);
|
|
5552
6765
|
const wranglerPath = userRequire.resolve("wrangler");
|
|
5553
|
-
const { getPlatformProxy } = await import(
|
|
6766
|
+
const { getPlatformProxy } = await import(pathToFileURL2(wranglerPath).href);
|
|
5554
6767
|
const proxy = await getPlatformProxy();
|
|
5555
6768
|
return {
|
|
5556
6769
|
env: proxy.env,
|
|
@@ -5602,16 +6815,17 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
5602
6815
|
let viteMode = "production";
|
|
5603
6816
|
return {
|
|
5604
6817
|
name: "@rangojs/router:discovery",
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
return
|
|
6818
|
+
// Make INTERNAL_RANGO_DEBUG reach the CLIENT debug logs by just setting the
|
|
6819
|
+
// env var. See injectClientDebugFlag: bakes the resolved flag into the
|
|
6820
|
+
// internal-debug module so FE debug no longer depends on Vite delivering the
|
|
6821
|
+
// `__RANGO_DEBUG__` define to the client (which it does only as an injected
|
|
6822
|
+
// global whose presence varies across consumer setups). Runs in dev and build.
|
|
6823
|
+
transform(_code, id) {
|
|
6824
|
+
return injectClientDebugFlag(id);
|
|
5612
6825
|
},
|
|
5613
6826
|
configResolved(config) {
|
|
5614
6827
|
s.projectRoot = config.root;
|
|
6828
|
+
s.scanFilter = opts?.discovery ? createScanFilter(s.projectRoot, opts.discovery) : void 0;
|
|
5615
6829
|
s.isBuildMode = config.command === "build";
|
|
5616
6830
|
viteCommand = config.command;
|
|
5617
6831
|
viteMode = config.mode;
|
|
@@ -5645,9 +6859,10 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
5645
6859
|
if (s.isBuildMode) return;
|
|
5646
6860
|
if (globalThis.__rscRouterDiscoveryActive) return;
|
|
5647
6861
|
s.devServer = server;
|
|
6862
|
+
server.middlewares.use(internalDebugNoCacheMiddleware());
|
|
5648
6863
|
let resolveDiscovery;
|
|
5649
|
-
const discoveryPromise = new Promise((
|
|
5650
|
-
resolveDiscovery =
|
|
6864
|
+
const discoveryPromise = new Promise((resolve12) => {
|
|
6865
|
+
resolveDiscovery = resolve12;
|
|
5651
6866
|
});
|
|
5652
6867
|
const gate = createDiscoveryGate(s, debugDiscovery);
|
|
5653
6868
|
const beginDiscoveryGate = gate.beginGate;
|
|
@@ -5754,6 +6969,10 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
5754
6969
|
);
|
|
5755
6970
|
console.warn(`[rango] Failed to create temp runner: ${err.message}`);
|
|
5756
6971
|
}
|
|
6972
|
+
await prerenderTempServer?.close().catch(() => {
|
|
6973
|
+
});
|
|
6974
|
+
prerenderTempServer = null;
|
|
6975
|
+
prerenderNodeRegistry = null;
|
|
5757
6976
|
return null;
|
|
5758
6977
|
}
|
|
5759
6978
|
async function clearTempRegistries(tempRscEnv) {
|
|
@@ -5805,6 +7024,15 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
5805
7024
|
await importEntryAndRegistry(tempRscEnv);
|
|
5806
7025
|
return tempRscEnv;
|
|
5807
7026
|
}
|
|
7027
|
+
const emitDiscoveryFailure = (err, hashBefore, hashAfter) => {
|
|
7028
|
+
const reoptimizeObserved = hashBefore !== void 0 && hashAfter !== void 0 && hashBefore !== hashAfter;
|
|
7029
|
+
const report = describeDiscoveryFailure(err, { reoptimizeObserved });
|
|
7030
|
+
if (report.level === "warn") {
|
|
7031
|
+
console.warn(report.message);
|
|
7032
|
+
} else {
|
|
7033
|
+
console.error(report.message);
|
|
7034
|
+
}
|
|
7035
|
+
};
|
|
5808
7036
|
const discover = async () => {
|
|
5809
7037
|
const discoverStart = performance.now();
|
|
5810
7038
|
const rscEnv = server.environments?.rsc;
|
|
@@ -5814,18 +7042,21 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
5814
7042
|
globalThis.__rscRouterDiscoveryActive ?? false
|
|
5815
7043
|
);
|
|
5816
7044
|
s.devServerOrigin = getDevServerOrigin();
|
|
7045
|
+
let tempRscEnv;
|
|
7046
|
+
let optimizerHashBefore2;
|
|
5817
7047
|
try {
|
|
5818
7048
|
await timed(
|
|
5819
7049
|
debugDiscovery,
|
|
5820
7050
|
"acquireBuildEnv",
|
|
5821
7051
|
() => acquireBuildEnv(s, viteCommand, viteMode)
|
|
5822
7052
|
);
|
|
5823
|
-
|
|
7053
|
+
tempRscEnv = await timed(
|
|
5824
7054
|
debugDiscovery,
|
|
5825
7055
|
"getOrCreateTempServer",
|
|
5826
7056
|
() => getOrCreateTempServer()
|
|
5827
7057
|
);
|
|
5828
7058
|
if (tempRscEnv) {
|
|
7059
|
+
optimizerHashBefore2 = tempRscEnv.depsOptimizer?.metadata?.browserHash;
|
|
5829
7060
|
await timed(
|
|
5830
7061
|
debugDiscovery,
|
|
5831
7062
|
"discoverRouters (cloudflare)",
|
|
@@ -5838,9 +7069,10 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
5838
7069
|
);
|
|
5839
7070
|
}
|
|
5840
7071
|
} catch (err) {
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
7072
|
+
emitDiscoveryFailure(
|
|
7073
|
+
err,
|
|
7074
|
+
optimizerHashBefore2,
|
|
7075
|
+
tempRscEnv?.depsOptimizer?.metadata?.browserHash
|
|
5844
7076
|
);
|
|
5845
7077
|
}
|
|
5846
7078
|
debugDiscovery?.(
|
|
@@ -5850,6 +7082,7 @@ ${err.stack}`
|
|
|
5850
7082
|
resolveDiscovery();
|
|
5851
7083
|
return;
|
|
5852
7084
|
}
|
|
7085
|
+
const optimizerHashBefore = rscEnv.depsOptimizer?.metadata?.browserHash;
|
|
5853
7086
|
try {
|
|
5854
7087
|
debugDiscovery?.("dev: node path start");
|
|
5855
7088
|
await timed(
|
|
@@ -5859,17 +7092,12 @@ ${err.stack}`
|
|
|
5859
7092
|
);
|
|
5860
7093
|
const serverMod = await timed(
|
|
5861
7094
|
debugDiscovery,
|
|
5862
|
-
"
|
|
5863
|
-
() => rscEnv
|
|
7095
|
+
"discoverRouters",
|
|
7096
|
+
() => discoverRouters(s, rscEnv)
|
|
5864
7097
|
);
|
|
5865
7098
|
if (serverMod?.setManifestReadyPromise) {
|
|
5866
7099
|
serverMod.setManifestReadyPromise(discoveryPromise);
|
|
5867
7100
|
}
|
|
5868
|
-
await timed(
|
|
5869
|
-
debugDiscovery,
|
|
5870
|
-
"discoverRouters",
|
|
5871
|
-
() => discoverRouters(s, rscEnv)
|
|
5872
|
-
);
|
|
5873
7101
|
s.devServerOrigin = getDevServerOrigin();
|
|
5874
7102
|
timedSync(
|
|
5875
7103
|
debugDiscovery,
|
|
@@ -5882,9 +7110,10 @@ ${err.stack}`
|
|
|
5882
7110
|
() => propagateDiscoveryState(rscEnv)
|
|
5883
7111
|
);
|
|
5884
7112
|
} catch (err) {
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
7113
|
+
emitDiscoveryFailure(
|
|
7114
|
+
err,
|
|
7115
|
+
optimizerHashBefore,
|
|
7116
|
+
rscEnv.depsOptimizer?.metadata?.browserHash
|
|
5888
7117
|
);
|
|
5889
7118
|
} finally {
|
|
5890
7119
|
debugDiscovery?.(
|
|
@@ -5900,6 +7129,7 @@ ${err.stack}`
|
|
|
5900
7129
|
0
|
|
5901
7130
|
);
|
|
5902
7131
|
let mainRegistry = null;
|
|
7132
|
+
const devPrerenderCache = createDevPrerenderCache();
|
|
5903
7133
|
const propagateDiscoveryState = async (rscEnv) => {
|
|
5904
7134
|
const serverMod = await rscEnv.runner.import("@rangojs/router/server");
|
|
5905
7135
|
if (!serverMod) return;
|
|
@@ -5969,8 +7199,19 @@ ${err.stack}`
|
|
|
5969
7199
|
registry = mainRegistry;
|
|
5970
7200
|
}
|
|
5971
7201
|
if (!registry) {
|
|
5972
|
-
|
|
5973
|
-
|
|
7202
|
+
const tempRscEnv = await getOrCreateTempServer();
|
|
7203
|
+
if (tempRscEnv) {
|
|
7204
|
+
try {
|
|
7205
|
+
await importEntryAndRegistry(tempRscEnv);
|
|
7206
|
+
} catch (err) {
|
|
7207
|
+
console.warn(
|
|
7208
|
+
`[rango] Dev prerender module refresh failed: ${err.message}`
|
|
7209
|
+
);
|
|
7210
|
+
res.statusCode = 500;
|
|
7211
|
+
res.end(`Prerender handler error: ${err.message}`);
|
|
7212
|
+
logResult(500, "temp module refresh failed");
|
|
7213
|
+
return;
|
|
7214
|
+
}
|
|
5974
7215
|
}
|
|
5975
7216
|
registry = prerenderNodeRegistry;
|
|
5976
7217
|
}
|
|
@@ -5983,8 +7224,29 @@ ${err.stack}`
|
|
|
5983
7224
|
const wantIntercept = url.searchParams.get("intercept") === "1";
|
|
5984
7225
|
const wantRouteName = url.searchParams.get("routeName");
|
|
5985
7226
|
const wantPassthrough = url.searchParams.get("passthrough") === "1";
|
|
7227
|
+
const variantDims = {
|
|
7228
|
+
passthrough: wantPassthrough,
|
|
7229
|
+
routeName: wantRouteName
|
|
7230
|
+
};
|
|
7231
|
+
const keyMain = devPrerenderCacheKey(pathname, {
|
|
7232
|
+
intercept: false,
|
|
7233
|
+
...variantDims
|
|
7234
|
+
});
|
|
7235
|
+
const keyIntercept = devPrerenderCacheKey(pathname, {
|
|
7236
|
+
intercept: true,
|
|
7237
|
+
...variantDims
|
|
7238
|
+
});
|
|
7239
|
+
const requestedKey = wantIntercept ? keyIntercept : keyMain;
|
|
5986
7240
|
for (const [, routerInstance] of registry) {
|
|
5987
7241
|
if (!routerInstance.matchForPrerender) continue;
|
|
7242
|
+
const cached = devPrerenderCache.get(routerInstance, requestedKey);
|
|
7243
|
+
if (cached !== void 0) {
|
|
7244
|
+
res.setHeader("content-type", "application/json");
|
|
7245
|
+
res.setHeader("x-rango-prerender-cache", "HIT");
|
|
7246
|
+
res.end(cached);
|
|
7247
|
+
logResult(200, "cache hit");
|
|
7248
|
+
return;
|
|
7249
|
+
}
|
|
5988
7250
|
try {
|
|
5989
7251
|
const result = await routerInstance.matchForPrerender(
|
|
5990
7252
|
pathname,
|
|
@@ -5998,26 +7260,24 @@ ${err.stack}`
|
|
|
5998
7260
|
if (!result) continue;
|
|
5999
7261
|
if (result.passthrough) continue;
|
|
6000
7262
|
if (wantRouteName && result.routeName !== wantRouteName) continue;
|
|
7263
|
+
const bodies = payloadBodiesFromResult(result);
|
|
7264
|
+
devPrerenderCache.set(routerInstance, keyMain, bodies.main);
|
|
7265
|
+
devPrerenderCache.set(
|
|
7266
|
+
routerInstance,
|
|
7267
|
+
keyIntercept,
|
|
7268
|
+
bodies.intercept
|
|
7269
|
+
);
|
|
6001
7270
|
res.setHeader("content-type", "application/json");
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
payload = {
|
|
6005
|
-
segments: [...result.segments, ...result.interceptSegments],
|
|
6006
|
-
handles: {
|
|
6007
|
-
...result.handles,
|
|
6008
|
-
...result.interceptHandles || {}
|
|
6009
|
-
}
|
|
6010
|
-
};
|
|
6011
|
-
} else {
|
|
6012
|
-
payload = { segments: result.segments, handles: result.handles };
|
|
6013
|
-
}
|
|
6014
|
-
res.end(JSON.stringify(payload));
|
|
7271
|
+
res.setHeader("x-rango-prerender-cache", "MISS");
|
|
7272
|
+
res.end(wantIntercept ? bodies.intercept : bodies.main);
|
|
6015
7273
|
logResult(200, `match ${result.routeName}`);
|
|
6016
7274
|
return;
|
|
6017
7275
|
} catch (err) {
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
7276
|
+
if (err?.name !== "Skip") {
|
|
7277
|
+
console.warn(
|
|
7278
|
+
`[rango] Dev prerender error for ${pathname} (serving live instead): ${err.message}`
|
|
7279
|
+
);
|
|
7280
|
+
}
|
|
6021
7281
|
}
|
|
6022
7282
|
}
|
|
6023
7283
|
res.statusCode = 404;
|
|
@@ -6224,7 +7484,7 @@ ${err.stack}`
|
|
|
6224
7484
|
if (hasCreateRouter) {
|
|
6225
7485
|
const nestedRouterConflict = findNestedRouterConflict([
|
|
6226
7486
|
...s.cachedRouterFiles ?? [],
|
|
6227
|
-
|
|
7487
|
+
resolve10(filePath)
|
|
6228
7488
|
]);
|
|
6229
7489
|
if (nestedRouterConflict) {
|
|
6230
7490
|
server.config.logger.error(
|
|
@@ -6536,7 +7796,11 @@ async function rango(options) {
|
|
|
6536
7796
|
];
|
|
6537
7797
|
const pkg = getPublishedPackageName();
|
|
6538
7798
|
const nested = (spec) => `${pkg} > ${spec}`;
|
|
6539
|
-
const routerRef = {
|
|
7799
|
+
const routerRef = {
|
|
7800
|
+
path: void 0,
|
|
7801
|
+
kind: "router"
|
|
7802
|
+
};
|
|
7803
|
+
const explicitHostRouter = preset !== "cloudflare" ? resolvedOptions.hostRouter : void 0;
|
|
6540
7804
|
const prerenderEnabled = true;
|
|
6541
7805
|
if (preset === "cloudflare") {
|
|
6542
7806
|
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
@@ -6549,8 +7813,6 @@ async function rango(options) {
|
|
|
6549
7813
|
enforce: "pre",
|
|
6550
7814
|
config() {
|
|
6551
7815
|
return {
|
|
6552
|
-
// Exclude rsc-router modules from optimization to prevent module duplication
|
|
6553
|
-
// This ensures the same Context instance is used by both browser entry and RSC proxy modules
|
|
6554
7816
|
optimizeDeps: {
|
|
6555
7817
|
exclude: excludeDeps,
|
|
6556
7818
|
rolldownOptions: sharedRolldownOptions
|
|
@@ -6573,21 +7835,12 @@ async function rango(options) {
|
|
|
6573
7835
|
client: {
|
|
6574
7836
|
build: {
|
|
6575
7837
|
rollupOptions: {
|
|
6576
|
-
// FILE_NAME_CONFLICT (and any other client-build warning) is
|
|
6577
|
-
// emitted by the CLIENT environment build, which consults THIS
|
|
6578
|
-
// env's onwarn -- Vite 8's environment builds do NOT propagate
|
|
6579
|
-
// the top-level build.rollupOptions.onwarn into the client env.
|
|
6580
|
-
// Wire it here so the suppression runs where the conflicts
|
|
6581
|
-
// originate (the top-level handler is invoked 0x for these; the
|
|
6582
|
-
// client-env handler is invoked for all of them).
|
|
6583
7838
|
onwarn,
|
|
6584
7839
|
output: {
|
|
6585
7840
|
manualChunks: getManualChunks
|
|
6586
7841
|
}
|
|
6587
7842
|
}
|
|
6588
7843
|
},
|
|
6589
|
-
// Pre-bundle rsc-html-stream to prevent discovery during first request
|
|
6590
|
-
// Exclude rsc-router modules to ensure same Context instance
|
|
6591
7844
|
optimizeDeps: {
|
|
6592
7845
|
include: [nested("rsc-html-stream/client")],
|
|
6593
7846
|
exclude: excludeDeps,
|
|
@@ -6595,12 +7848,9 @@ async function rango(options) {
|
|
|
6595
7848
|
}
|
|
6596
7849
|
},
|
|
6597
7850
|
ssr: {
|
|
6598
|
-
// Build SSR inside RSC directory so wrangler can deploy self-contained dist/rsc
|
|
6599
7851
|
build: {
|
|
6600
7852
|
outDir: "./dist/rsc/ssr"
|
|
6601
7853
|
},
|
|
6602
|
-
// Pre-bundle SSR entry and React for proper module linking with childEnvironments
|
|
6603
|
-
// All deps must be listed to avoid late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
6604
7854
|
optimizeDeps: {
|
|
6605
7855
|
entries: [finalEntries.ssr],
|
|
6606
7856
|
include: [
|
|
@@ -6620,10 +7870,7 @@ async function rango(options) {
|
|
|
6620
7870
|
}
|
|
6621
7871
|
},
|
|
6622
7872
|
rsc: {
|
|
6623
|
-
// RSC environment needs exclude list and esbuild options
|
|
6624
|
-
// Exclude rsc-router modules to prevent createContext in RSC environment
|
|
6625
7873
|
optimizeDeps: {
|
|
6626
|
-
// Pre-bundle all RSC deps to prevent late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
6627
7874
|
include: [
|
|
6628
7875
|
"react",
|
|
6629
7876
|
"react/jsx-runtime",
|
|
@@ -6661,17 +7908,49 @@ async function rango(options) {
|
|
|
6661
7908
|
name: "@rangojs/router:auto-discover",
|
|
6662
7909
|
config(userConfig) {
|
|
6663
7910
|
if (routerRef.path) return;
|
|
6664
|
-
const root = userConfig.root ?
|
|
7911
|
+
const root = userConfig.root ? resolve11(process.cwd(), userConfig.root) : process.cwd();
|
|
7912
|
+
const toRootRelative = (abs) => (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
|
|
7913
|
+
const bulletList = (files) => files.map((f) => " - " + toRootRelative(f)).join("\n");
|
|
7914
|
+
if (explicitHostRouter) {
|
|
7915
|
+
routerRef.path = normalizeHostRouterEntry(
|
|
7916
|
+
explicitHostRouter,
|
|
7917
|
+
root,
|
|
7918
|
+
existsSync8
|
|
7919
|
+
);
|
|
7920
|
+
routerRef.kind = "host";
|
|
7921
|
+
return;
|
|
7922
|
+
}
|
|
7923
|
+
const hostCandidates = findHostRouterFiles(root);
|
|
7924
|
+
if (hostCandidates.length === 1) {
|
|
7925
|
+
const hostPath = toRootRelative(hostCandidates[0]);
|
|
7926
|
+
console.info(
|
|
7927
|
+
`[rango] Serving host router entry ${hostPath} (auto-detected). Set the \`hostRouter\` option to override.`
|
|
7928
|
+
);
|
|
7929
|
+
routerRef.path = hostPath;
|
|
7930
|
+
routerRef.kind = "host";
|
|
7931
|
+
return;
|
|
7932
|
+
}
|
|
7933
|
+
if (hostCandidates.length > 1) {
|
|
7934
|
+
throw new Error(
|
|
7935
|
+
`[rango] Multiple host routers found:
|
|
7936
|
+
${bulletList(hostCandidates)}
|
|
7937
|
+
|
|
7938
|
+
Set the \`hostRouter\` option to the entry to serve, e.g. rango({ preset: "${preset}", hostRouter: "./src/worker.rsc.tsx" }).`
|
|
7939
|
+
);
|
|
7940
|
+
}
|
|
6665
7941
|
const candidates = findRouterFiles(root);
|
|
6666
7942
|
if (candidates.length === 1) {
|
|
6667
|
-
|
|
6668
|
-
routerRef.
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
${
|
|
7943
|
+
routerRef.path = toRootRelative(candidates[0]);
|
|
7944
|
+
routerRef.kind = "router";
|
|
7945
|
+
return;
|
|
7946
|
+
}
|
|
7947
|
+
if (candidates.length > 1) {
|
|
7948
|
+
throw new Error(
|
|
7949
|
+
`[rango] Multiple routers found:
|
|
7950
|
+
${bulletList(candidates)}
|
|
7951
|
+
|
|
7952
|
+
If this is a multi-app host router, export a createHostRouter() instance and set the \`hostRouter\` option (e.g. rango({ preset: "${preset}", hostRouter: "./src/worker.rsc.tsx" })), or use preset: "cloudflare" where you own the worker entry.`
|
|
7953
|
+
);
|
|
6675
7954
|
}
|
|
6676
7955
|
}
|
|
6677
7956
|
});
|
|
@@ -6685,8 +7964,11 @@ ${list}`);
|
|
|
6685
7964
|
plugins.push({
|
|
6686
7965
|
name: "@rangojs/router:rsc-integration",
|
|
6687
7966
|
enforce: "pre",
|
|
6688
|
-
config() {
|
|
7967
|
+
config(_userConfig, configEnv) {
|
|
7968
|
+
const vercelDefine = preset === "vercel" && configEnv.command === "build" ? { "process.env.NODE_ENV": JSON.stringify("production") } : void 0;
|
|
7969
|
+
const vercelServerEnv = preset === "vercel" && configEnv.command === "build" ? { resolve: { noExternal: true } } : void 0;
|
|
6689
7970
|
return {
|
|
7971
|
+
...vercelDefine ? { define: vercelDefine } : {},
|
|
6690
7972
|
optimizeDeps: {
|
|
6691
7973
|
exclude: excludeDeps,
|
|
6692
7974
|
rolldownOptions: sharedRolldownOptions
|
|
@@ -6709,13 +7991,6 @@ ${list}`);
|
|
|
6709
7991
|
client: {
|
|
6710
7992
|
build: {
|
|
6711
7993
|
rollupOptions: {
|
|
6712
|
-
// FILE_NAME_CONFLICT (and any other client-build warning) is
|
|
6713
|
-
// emitted by the CLIENT environment build, which consults THIS
|
|
6714
|
-
// env's onwarn -- Vite 8's environment builds do NOT propagate
|
|
6715
|
-
// the top-level build.rollupOptions.onwarn into the client env.
|
|
6716
|
-
// Wire it here so the suppression runs where the conflicts
|
|
6717
|
-
// originate (the top-level handler is invoked 0x for these; the
|
|
6718
|
-
// client-env handler is invoked for all of them).
|
|
6719
7994
|
onwarn,
|
|
6720
7995
|
output: {
|
|
6721
7996
|
manualChunks: getManualChunks
|
|
@@ -6736,6 +8011,7 @@ ${list}`);
|
|
|
6736
8011
|
}
|
|
6737
8012
|
},
|
|
6738
8013
|
ssr: {
|
|
8014
|
+
...vercelServerEnv ?? {},
|
|
6739
8015
|
optimizeDeps: {
|
|
6740
8016
|
entries: [VIRTUAL_IDS.ssr],
|
|
6741
8017
|
include: [
|
|
@@ -6754,6 +8030,7 @@ ${list}`);
|
|
|
6754
8030
|
}
|
|
6755
8031
|
},
|
|
6756
8032
|
rsc: {
|
|
8033
|
+
...vercelServerEnv ?? {},
|
|
6757
8034
|
optimizeDeps: {
|
|
6758
8035
|
entries: [VIRTUAL_IDS.rsc],
|
|
6759
8036
|
include: [
|
|
@@ -6764,6 +8041,12 @@ ${list}`);
|
|
|
6764
8041
|
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
6765
8042
|
)
|
|
6766
8043
|
],
|
|
8044
|
+
// Vite 8 does not propagate the top-level optimizeDeps.exclude
|
|
8045
|
+
// (set in config()) to non-client envs, so the rsc env must set
|
|
8046
|
+
// it explicitly — mirroring the node ssr env and the cloudflare
|
|
8047
|
+
// rsc env. Without it a strict-pnpm npm-installed app can try to
|
|
8048
|
+
// pre-bundle the router's own subpath entries and fail.
|
|
8049
|
+
exclude: excludeDeps,
|
|
6767
8050
|
rolldownOptions: sharedRolldownOptions
|
|
6768
8051
|
}
|
|
6769
8052
|
}
|
|
@@ -6773,7 +8056,11 @@ ${list}`);
|
|
|
6773
8056
|
configResolved(config) {
|
|
6774
8057
|
if (showBanner) {
|
|
6775
8058
|
const mode = config.command === "serve" ? process.argv.includes("preview") ? "preview" : "dev" : "build";
|
|
6776
|
-
printBanner(
|
|
8059
|
+
printBanner(
|
|
8060
|
+
mode,
|
|
8061
|
+
preset === "vercel" ? "vercel" : "node",
|
|
8062
|
+
rangoVersion
|
|
8063
|
+
);
|
|
6777
8064
|
}
|
|
6778
8065
|
const rscMinimalCount = config.plugins.filter(
|
|
6779
8066
|
(p) => p.name === "rsc:minimal"
|
|
@@ -6806,8 +8093,7 @@ ${list}`);
|
|
|
6806
8093
|
return;
|
|
6807
8094
|
try {
|
|
6808
8095
|
const source = readFileSync7(file, "utf-8");
|
|
6809
|
-
|
|
6810
|
-
if (trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'")) {
|
|
8096
|
+
if (hasUseClientDirective(source)) {
|
|
6811
8097
|
return [];
|
|
6812
8098
|
}
|
|
6813
8099
|
} catch {
|
|
@@ -6831,9 +8117,16 @@ ${list}`);
|
|
|
6831
8117
|
enableBuildPrerender: prerenderEnabled,
|
|
6832
8118
|
buildEnv: options?.buildEnv,
|
|
6833
8119
|
preset,
|
|
8120
|
+
prerenderOnError: options?.prerender?.onError,
|
|
8121
|
+
discovery: options?.discovery,
|
|
6834
8122
|
clientChunkCtx
|
|
6835
8123
|
})
|
|
6836
8124
|
);
|
|
8125
|
+
if (preset === "vercel") {
|
|
8126
|
+
plugins.push(
|
|
8127
|
+
createVercelOutputPlugin(resolvedOptions)
|
|
8128
|
+
);
|
|
8129
|
+
}
|
|
6837
8130
|
debugConfig?.(
|
|
6838
8131
|
"rango(%s) setup done: %d plugin(s) (%sms)",
|
|
6839
8132
|
preset,
|
|
@@ -6846,7 +8139,7 @@ ${list}`);
|
|
|
6846
8139
|
// src/vite/plugins/refresh-cmd.ts
|
|
6847
8140
|
function poke() {
|
|
6848
8141
|
return {
|
|
6849
|
-
name: "
|
|
8142
|
+
name: "@rangojs/router:poke",
|
|
6850
8143
|
apply: "serve",
|
|
6851
8144
|
configureServer(server) {
|
|
6852
8145
|
const stdin = process.stdin;
|
|
@@ -6924,6 +8217,7 @@ function poke() {
|
|
|
6924
8217
|
};
|
|
6925
8218
|
}
|
|
6926
8219
|
export {
|
|
8220
|
+
directoryClientChunks,
|
|
6927
8221
|
poke,
|
|
6928
8222
|
rango
|
|
6929
8223
|
};
|