@rangojs/router 0.0.0-experimental.79 → 0.0.0-experimental.7c7e4327
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 +301 -797
- package/dist/bin/rango.js +603 -145
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +3750 -1160
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +96 -24
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +85 -6
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +228 -33
- package/skills/caching/SKILL.md +336 -19
- 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 +110 -4
- 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 +87 -56
- package/skills/fonts/SKILL.md +1 -1
- package/skills/handler-use/SKILL.md +12 -10
- package/skills/hooks/SKILL.md +73 -691
- 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 +129 -27
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +75 -19
- package/skills/layout/SKILL.md +40 -19
- package/skills/links/SKILL.md +247 -17
- package/skills/loader/SKILL.md +248 -10
- package/skills/middleware/SKILL.md +25 -13
- package/skills/migrate-nextjs/SKILL.md +205 -20
- package/skills/migrate-react-router/SKILL.md +59 -670
- 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 +29 -2
- package/skills/observability/SKILL.md +202 -0
- package/skills/parallel/SKILL.md +40 -10
- package/skills/ppr/SKILL.md +616 -0
- package/skills/prerender/SKILL.md +72 -60
- package/skills/rango/SKILL.md +318 -26
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +138 -49
- package/skills/route/SKILL.md +117 -9
- package/skills/router-setup/SKILL.md +44 -9
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +776 -0
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +28 -4
- package/skills/testing/SKILL.md +130 -0
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -0
- package/skills/testing/handles.md +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 -626
- 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 +74 -15
- package/skills/vercel/SKILL.md +128 -0
- package/skills/view-transitions/SKILL.md +337 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +252 -158
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/logging.ts +28 -0
- package/src/browser/merge-segment-loaders.ts +6 -4
- package/src/browser/navigation-bridge.ts +94 -25
- package/src/browser/navigation-client.ts +144 -79
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +161 -73
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +183 -144
- package/src/browser/prefetch/cache.ts +242 -77
- package/src/browser/prefetch/fetch.ts +325 -69
- package/src/browser/prefetch/queue.ts +61 -12
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +58 -20
- package/src/browser/react/NavigationProvider.tsx +202 -120
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +66 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +178 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +17 -14
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +32 -7
- package/src/browser/react/use-params.ts +20 -10
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +25 -3
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +11 -21
- package/src/browser/response-adapter.ts +99 -8
- package/src/browser/rsc-router.tsx +145 -28
- package/src/browser/scroll-restoration.ts +37 -22
- package/src/browser/segment-reconciler.ts +31 -21
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +236 -65
- package/src/browser/types.ts +102 -9
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +203 -154
- package/src/build/generate-route-types.ts +3 -1
- package/src/build/index.ts +11 -3
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +152 -21
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +16 -5
- package/src/build/route-types/include-resolution.ts +456 -62
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +22 -6
- package/src/build/route-types/router-processing.ts +128 -51
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +13 -21
- 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 +421 -58
- package/src/cache/cache-scope.ts +187 -96
- 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 +2202 -372
- 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 +180 -99
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1127 -0
- package/src/client.rsc.tsx +41 -21
- package/src/client.tsx +33 -61
- 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 +18 -6
- package/src/decode-loader-results.ts +52 -0
- package/src/defer.ts +185 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +30 -4
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +67 -37
- 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 +9 -2
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +97 -12
- package/src/index.ts +98 -14
- package/src/internal-debug.ts +11 -10
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +78 -10
- 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 +62 -0
- package/src/reverse.ts +65 -39
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +19 -77
- package/src/route-definition/dsl-helpers.ts +304 -309
- package/src/route-definition/helper-factories.ts +28 -140
- package/src/route-definition/helpers-types.ts +87 -59
- package/src/route-definition/index.ts +1 -2
- package/src/route-definition/redirect.ts +44 -11
- package/src/route-definition/resolve-handler-use.ts +12 -1
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-map-builder.ts +41 -20
- package/src/route-types.ts +19 -46
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +73 -25
- package/src/router/error-handling.ts +45 -18
- package/src/router/find-match.ts +129 -30
- package/src/router/handler-context.ts +27 -42
- package/src/router/instrument.ts +355 -0
- package/src/router/intercept-resolution.ts +39 -20
- package/src/router/lazy-includes.ts +82 -59
- package/src/router/loader-resolution.ts +167 -72
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +74 -40
- package/src/router/match-api.ts +80 -55
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +211 -165
- package/src/router/match-middleware/background-revalidation.ts +40 -24
- package/src/router/match-middleware/cache-lookup.ts +159 -285
- package/src/router/match-middleware/cache-store.ts +64 -52
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +69 -79
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +7 -134
- package/src/router/middleware.ts +298 -172
- 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 +181 -150
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +112 -67
- package/src/router/preview-match.ts +6 -2
- package/src/router/request-classification.ts +50 -69
- package/src/router/revalidation.ts +123 -73
- package/src/router/route-snapshot.ts +14 -3
- package/src/router/router-context.ts +6 -29
- package/src/router/router-interfaces.ts +115 -36
- package/src/router/router-options.ts +166 -5
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +131 -86
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +139 -39
- package/src/router/segment-resolution/loader-mask.ts +67 -0
- package/src/router/segment-resolution/loader-snapshot.ts +251 -0
- package/src/router/segment-resolution/revalidation.ts +272 -320
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +56 -0
- package/src/router/segment-resolution.ts +5 -1
- package/src/router/segment-wrappers.ts +6 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +75 -0
- package/src/router/telemetry-otel.ts +160 -200
- package/src/router/telemetry.ts +105 -20
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +215 -0
- package/src/router/trie-matching.ts +171 -59
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +57 -0
- package/src/router.ts +157 -71
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +291 -217
- package/src/rsc/helpers.ts +168 -46
- package/src/rsc/index.ts +2 -5
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +114 -38
- package/src/rsc/manifest-init.ts +29 -42
- package/src/rsc/nonce.ts +10 -1
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +124 -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 +99 -189
- package/src/rsc/rsc-rendering.ts +421 -76
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +282 -116
- package/src/rsc/shell-capture.ts +1158 -0
- package/src/rsc/shell-serve.ts +150 -0
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +53 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +35 -30
- package/src/segment-loader-promise.ts +49 -4
- package/src/segment-system.tsx +350 -149
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +208 -51
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +152 -5
- package/src/server/handle-store.ts +21 -38
- package/src/server/loader-registry.ts +33 -42
- package/src/server/request-context.ts +395 -176
- package/src/ssr/index.tsx +458 -178
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +46 -0
- package/src/testing/dispatch.ts +813 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +257 -0
- package/src/testing/generated-routes.ts +199 -0
- package/src/testing/index.ts +105 -0
- package/src/testing/internal/context.ts +371 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +357 -0
- package/src/testing/render-route.tsx +584 -0
- package/src/testing/run-loader.ts +385 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/run-transition-when.ts +164 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +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 +54 -41
- package/src/types/handler-context.ts +110 -62
- package/src/types/index.ts +3 -10
- package/src/types/loader-types.ts +11 -9
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +20 -52
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +135 -14
- package/src/urls/include-helper.ts +19 -64
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +2 -11
- package/src/urls/path-helper-types.ts +63 -17
- package/src/urls/path-helper.ts +22 -106
- package/src/urls/pattern-types.ts +72 -19
- package/src/urls/response-types.ts +22 -29
- package/src/urls/type-extraction.ts +98 -154
- package/src/urls/urls-function.ts +1 -19
- package/src/use-loader.tsx +292 -107
- package/src/vercel/index.ts +11 -0
- package/src/vercel/tracing.ts +88 -0
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +8 -7
- package/src/vite/discovery/dev-prerender-cache.ts +117 -0
- package/src/vite/discovery/discover-routers.ts +127 -86
- package/src/vite/discovery/discovery-errors.ts +255 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +96 -68
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +45 -1
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +4 -0
- package/src/vite/inject-client-debug.ts +88 -0
- package/src/vite/plugin-types.ts +210 -10
- package/src/vite/plugins/cjs-to-esm.ts +16 -19
- package/src/vite/plugins/client-ref-dedup.ts +16 -11
- package/src/vite/plugins/client-ref-hashing.ts +28 -15
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
- package/src/vite/plugins/expose-action-id.ts +48 -95
- package/src/vite/plugins/expose-id-utils.ts +88 -55
- package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +11 -90
- package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
- package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
- package/src/vite/plugins/expose-internal-ids.ts +505 -486
- package/src/vite/plugins/performance-tracks.ts +26 -25
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +73 -83
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +40 -29
- package/src/vite/plugins/version-plugin.ts +37 -40
- package/src/vite/plugins/virtual-entries.ts +138 -27
- package/src/vite/rango.ts +236 -138
- package/src/vite/router-discovery.ts +927 -136
- package/src/vite/utils/ast-handler-extract.ts +26 -35
- package/src/vite/utils/banner.ts +1 -1
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +20 -52
- package/src/vite/utils/prerender-utils.ts +71 -43
- package/src/vite/utils/shared-utils.ts +142 -43
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/network-error-thrower.tsx +0 -23
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -1,62 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* Non-leaf nodes are skipped because they have nested lazy includes that
|
|
6
|
-
* require the handler to run for discovery.
|
|
7
|
-
*/
|
|
8
|
-
export function flattenLeafEntries(
|
|
9
|
-
prefixTree: Record<string, any>,
|
|
10
|
-
routeManifest: Record<string, string>,
|
|
11
|
-
result: Array<{ staticPrefix: string; routes: Record<string, string> }>,
|
|
12
|
-
): void {
|
|
13
|
-
function visit(node: any): void {
|
|
14
|
-
const children = node.children || {};
|
|
15
|
-
if (
|
|
16
|
-
Object.keys(children).length === 0 &&
|
|
17
|
-
node.routes &&
|
|
18
|
-
node.routes.length > 0
|
|
19
|
-
) {
|
|
20
|
-
// Leaf node: collect its routes from the manifest
|
|
21
|
-
const routes: Record<string, string> = {};
|
|
22
|
-
for (const name of node.routes) {
|
|
23
|
-
if (name in routeManifest) {
|
|
24
|
-
routes[name] = routeManifest[name];
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
result.push({ staticPrefix: node.staticPrefix, routes });
|
|
28
|
-
} else {
|
|
29
|
-
// Non-leaf: recurse into children
|
|
30
|
-
for (const child of Object.values(children)) {
|
|
31
|
-
visit(child);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
for (const node of Object.values(prefixTree)) {
|
|
36
|
-
visit(node);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Walk prefix tree to map each route name to its scope's staticPrefix.
|
|
42
|
-
*/
|
|
43
|
-
export function buildRouteToStaticPrefix(
|
|
44
|
-
prefixTree: Record<string, any>,
|
|
45
|
-
result: Record<string, string>,
|
|
46
|
-
): void {
|
|
47
|
-
function visit(node: any): void {
|
|
48
|
-
const sp = node.staticPrefix || "";
|
|
49
|
-
for (const name of node.routes || []) {
|
|
50
|
-
result[name] = sp;
|
|
51
|
-
}
|
|
52
|
-
for (const child of Object.values(node.children || {})) {
|
|
53
|
-
visit(child);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
for (const node of Object.values(prefixTree)) {
|
|
57
|
-
visit(node);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
1
|
+
export {
|
|
2
|
+
flattenLeafEntries,
|
|
3
|
+
buildRouteToStaticPrefix,
|
|
4
|
+
} from "../../build/prefix-tree-utils.js";
|
|
60
5
|
|
|
61
6
|
/**
|
|
62
7
|
* Wrap a value as `JSON.parse('...')` instead of a JS object literal.
|
|
@@ -1,57 +1,29 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Package Resolution Utilities
|
|
3
|
-
*
|
|
4
|
-
* Handles detection of workspace vs npm install context and generates
|
|
5
|
-
* appropriate aliases and exclude lists for Vite configuration.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
1
|
import { existsSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
9
3
|
import { resolve } from "node:path";
|
|
10
|
-
import packageJson from "../../../package.json"
|
|
4
|
+
import packageJson from "../../../package.json";
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
11
7
|
|
|
12
8
|
/**
|
|
13
9
|
* The canonical name used in virtual entries (without scope)
|
|
14
10
|
*/
|
|
15
11
|
const VIRTUAL_PACKAGE_NAME = "@rangojs/router";
|
|
16
12
|
|
|
17
|
-
/**
|
|
18
|
-
* Get the published package name (e.g., "@rangojs/router")
|
|
19
|
-
*/
|
|
20
13
|
export function getPublishedPackageName(): string {
|
|
21
14
|
return packageJson.name;
|
|
22
15
|
}
|
|
23
16
|
|
|
24
|
-
/**
|
|
25
|
-
* Check if the package is installed from npm (scoped) vs workspace (unscoped)
|
|
26
|
-
*
|
|
27
|
-
* In workspace development:
|
|
28
|
-
* - Package is installed as "@rangojs/router" via pnpm workspace alias
|
|
29
|
-
* - The scoped name (@rangojs/router) doesn't exist in node_modules
|
|
30
|
-
*
|
|
31
|
-
* When installed from npm:
|
|
32
|
-
* - Package is installed as "@rangojs/router"
|
|
33
|
-
* - We need aliases to map "@rangojs/router/*" to "@rangojs/router/*"
|
|
34
|
-
*/
|
|
35
17
|
export function isInstalledFromNpm(): boolean {
|
|
36
18
|
const packageName = getPublishedPackageName();
|
|
37
19
|
// Check if the scoped package exists in node_modules
|
|
38
20
|
return existsSync(resolve(process.cwd(), "node_modules", packageName));
|
|
39
21
|
}
|
|
40
22
|
|
|
41
|
-
/**
|
|
42
|
-
* Check if we're in a monorepo/workspace development context
|
|
43
|
-
*/
|
|
44
23
|
export function isWorkspaceDevelopment(): boolean {
|
|
45
24
|
return !isInstalledFromNpm();
|
|
46
25
|
}
|
|
47
26
|
|
|
48
|
-
/**
|
|
49
|
-
* Subpaths derived from package.json exports that use TypeScript source.
|
|
50
|
-
* These must be excluded from Vite's dependency optimization (they ship
|
|
51
|
-
* as .ts/.tsx, not compiled JS) and aliased when installed from npm.
|
|
52
|
-
*
|
|
53
|
-
* Derived automatically from the exports field to prevent drift.
|
|
54
|
-
*/
|
|
55
27
|
const SOURCE_EXPORT_SUBPATHS = Object.keys(packageJson.exports)
|
|
56
28
|
.filter((key) => {
|
|
57
29
|
const entry = (
|
|
@@ -67,12 +39,6 @@ const SOURCE_EXPORT_SUBPATHS = Object.keys(packageJson.exports)
|
|
|
67
39
|
})
|
|
68
40
|
.map((key) => key.replace(/^\./, ""));
|
|
69
41
|
|
|
70
|
-
/**
|
|
71
|
-
* Generate the list of modules to exclude from Vite's dependency optimization.
|
|
72
|
-
*
|
|
73
|
-
* We include both the published name and the virtual name because
|
|
74
|
-
* Vite's optimizer runs before alias resolution.
|
|
75
|
-
*/
|
|
76
42
|
export function getExcludeDeps(): string[] {
|
|
77
43
|
const packageName = getPublishedPackageName();
|
|
78
44
|
const excludes: string[] = [];
|
|
@@ -89,24 +55,10 @@ export function getExcludeDeps(): string[] {
|
|
|
89
55
|
return excludes;
|
|
90
56
|
}
|
|
91
57
|
|
|
92
|
-
/**
|
|
93
|
-
* Subpaths that need aliasing — same as SOURCE_EXPORT_SUBPATHS.
|
|
94
|
-
* When installed from npm, virtual entries may use a different package name
|
|
95
|
-
* than the published one; aliases bridge them.
|
|
96
|
-
*/
|
|
97
58
|
const ALIAS_SUBPATHS = SOURCE_EXPORT_SUBPATHS;
|
|
98
59
|
|
|
99
|
-
/**
|
|
100
|
-
* Generate aliases to map virtual package paths to the actual published package.
|
|
101
|
-
*
|
|
102
|
-
* Only needed when installed from npm, where the package is under @rangojs/router
|
|
103
|
-
* but virtual entries import from rsc-router/*.
|
|
104
|
-
*
|
|
105
|
-
* Returns empty object in workspace development where rsc-router resolves directly.
|
|
106
|
-
*/
|
|
107
60
|
export function getPackageAliases(): Record<string, string> {
|
|
108
61
|
if (isWorkspaceDevelopment()) {
|
|
109
|
-
// No aliases needed - rsc-router resolves directly
|
|
110
62
|
return {};
|
|
111
63
|
}
|
|
112
64
|
|
|
@@ -119,3 +71,19 @@ export function getPackageAliases(): Record<string, string> {
|
|
|
119
71
|
|
|
120
72
|
return aliases;
|
|
121
73
|
}
|
|
74
|
+
|
|
75
|
+
export function getVendorAliases(): Record<string, string> {
|
|
76
|
+
const specs = [
|
|
77
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
|
|
78
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
|
|
79
|
+
];
|
|
80
|
+
const aliases: Record<string, string> = {};
|
|
81
|
+
for (const spec of specs) {
|
|
82
|
+
try {
|
|
83
|
+
aliases[spec] = require.resolve(spec);
|
|
84
|
+
} catch {
|
|
85
|
+
// Non-fatal; Vite will warn if it cannot resolve the spec
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return aliases;
|
|
89
|
+
}
|
|
@@ -9,30 +9,13 @@ import {
|
|
|
9
9
|
} from "node:fs";
|
|
10
10
|
import { resolve } from "node:path";
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* into new RegExp() patterns.
|
|
15
|
-
*/
|
|
16
|
-
export function escapeRegExp(str: string): string {
|
|
17
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
18
|
-
}
|
|
12
|
+
import { escapeRegExp } from "../../regex-escape.js";
|
|
13
|
+
import { encodePathRemainder } from "../../router/url-params.js";
|
|
19
14
|
|
|
20
|
-
/**
|
|
21
|
-
* Encode route param values for path interpolation while preserving path
|
|
22
|
-
* separators for wildcard params (splat-style values can include `/`).
|
|
23
|
-
*/
|
|
24
15
|
export function encodePathParam(value: unknown): string {
|
|
25
|
-
return String(value)
|
|
26
|
-
.split("/")
|
|
27
|
-
.map((segment) => encodeURIComponent(segment))
|
|
28
|
-
.join("/");
|
|
16
|
+
return encodePathRemainder(String(value), encodeURIComponent);
|
|
29
17
|
}
|
|
30
18
|
|
|
31
|
-
/**
|
|
32
|
-
* Substitute route params into a pattern, stripping constraint and optional
|
|
33
|
-
* syntax (:param(a|b)? -> value). Also handles wildcard params (*key).
|
|
34
|
-
* Optional params not present in `params` are removed from the output.
|
|
35
|
-
*/
|
|
36
19
|
export function substituteRouteParams(
|
|
37
20
|
pattern: string,
|
|
38
21
|
params: Record<string, string>,
|
|
@@ -41,16 +24,24 @@ export function substituteRouteParams(
|
|
|
41
24
|
let result = pattern;
|
|
42
25
|
let hadOmittedOptional = false;
|
|
43
26
|
|
|
44
|
-
// First pass: substitute provided params.
|
|
45
|
-
// Empty string on an optional placeholder is treated as omitted (the trie
|
|
46
|
-
// matcher fills unmatched optionals with "" — letting the second pass
|
|
47
|
-
// strip them keeps slash cleanup consistent). Empty string on required
|
|
48
|
-
// `:key` or wildcard `*key` still substitutes, matching prior behaviour.
|
|
49
27
|
for (const [key, value] of Object.entries(params)) {
|
|
50
28
|
const escaped = escapeRegExp(key);
|
|
29
|
+
// Named catch-all `:key+` / `:key*` (issue #634). Like the runtime reverse,
|
|
30
|
+
// the value is multi-segment: encode each segment and keep the `/` separators
|
|
31
|
+
// (a whole-value encode would turn `a/b` into `a%2Fb`), and consume the
|
|
32
|
+
// trailing modifier so it does not leak into the URL. `*` (zero-or-more)
|
|
33
|
+
// absent collapses via the trailing cleanup below.
|
|
34
|
+
const catchAllRe = new RegExp(`:${escaped}[+*]`);
|
|
35
|
+
if (catchAllRe.test(result)) {
|
|
36
|
+
if (value === "") {
|
|
37
|
+
result = result.replace(catchAllRe, "");
|
|
38
|
+
hadOmittedOptional = true;
|
|
39
|
+
} else {
|
|
40
|
+
result = result.replace(catchAllRe, encodePathRemainder(value, encode));
|
|
41
|
+
}
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
51
44
|
if (value === "") {
|
|
52
|
-
// Only replace required placeholders (negative lookahead for `?`);
|
|
53
|
-
// leave `:key?` for the second pass.
|
|
54
45
|
result = result.replace(
|
|
55
46
|
new RegExp(`:${escaped}(\\([^)]*\\))?(?!\\?)`),
|
|
56
47
|
"",
|
|
@@ -65,13 +56,11 @@ export function substituteRouteParams(
|
|
|
65
56
|
}
|
|
66
57
|
}
|
|
67
58
|
|
|
68
|
-
// Second pass: strip remaining optional param placeholders not in params
|
|
69
59
|
result = result.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\([^)]*\))?\?/g, () => {
|
|
70
60
|
hadOmittedOptional = true;
|
|
71
61
|
return "";
|
|
72
62
|
});
|
|
73
63
|
|
|
74
|
-
// Clean up slashes from omitted optional segments
|
|
75
64
|
if (hadOmittedOptional) {
|
|
76
65
|
const hadTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
|
|
77
66
|
result = result.replace(/\/\/+/g, "/").replace(/\/+$/, "") || "/";
|
|
@@ -81,10 +70,6 @@ export function substituteRouteParams(
|
|
|
81
70
|
return result;
|
|
82
71
|
}
|
|
83
72
|
|
|
84
|
-
/**
|
|
85
|
-
* Run an async function over items with bounded concurrency.
|
|
86
|
-
* Errors propagate immediately and abort remaining work.
|
|
87
|
-
*/
|
|
88
73
|
export async function runWithConcurrency<T>(
|
|
89
74
|
items: T[],
|
|
90
75
|
concurrency: number,
|
|
@@ -96,19 +81,30 @@ export async function runWithConcurrency<T>(
|
|
|
96
81
|
return;
|
|
97
82
|
}
|
|
98
83
|
let nextIndex = 0;
|
|
84
|
+
// On first failure (the default prerender.onError: "fail" re-throws), stop
|
|
85
|
+
// scheduling new work so the remaining workers don't keep running full RSC
|
|
86
|
+
// renders before the build aborts. The first error is surfaced after all
|
|
87
|
+
// in-flight workers settle, preserving the throw-to-fail-build behavior.
|
|
88
|
+
let firstError: unknown;
|
|
89
|
+
let failed = false;
|
|
99
90
|
async function worker() {
|
|
100
|
-
while (nextIndex < items.length) {
|
|
91
|
+
while (nextIndex < items.length && !failed) {
|
|
101
92
|
const idx = nextIndex++;
|
|
102
|
-
|
|
93
|
+
try {
|
|
94
|
+
await fn(items[idx]);
|
|
95
|
+
} catch (err) {
|
|
96
|
+
if (!failed) {
|
|
97
|
+
failed = true;
|
|
98
|
+
firstError = err;
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
103
102
|
}
|
|
104
103
|
}
|
|
105
104
|
await Promise.all(Array.from({ length: limit }, () => worker()));
|
|
105
|
+
if (failed) throw firstError;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
/**
|
|
109
|
-
* Group prerender entries by their concurrency setting so each group
|
|
110
|
-
* can be rendered with the appropriate parallelism.
|
|
111
|
-
*/
|
|
112
108
|
export function groupByConcurrency<T extends { concurrency: number }>(
|
|
113
109
|
entries: T[],
|
|
114
110
|
): { concurrency: number; entries: T[] }[] {
|
|
@@ -128,10 +124,6 @@ export function groupByConcurrency<T extends { concurrency: number }>(
|
|
|
128
124
|
}));
|
|
129
125
|
}
|
|
130
126
|
|
|
131
|
-
/**
|
|
132
|
-
* Notify all routers' onError callbacks about a build-time error.
|
|
133
|
-
* Uses a synthetic request since there is no real request during build.
|
|
134
|
-
*/
|
|
135
127
|
export function notifyOnError(
|
|
136
128
|
registry: Map<string, any>,
|
|
137
129
|
error: unknown,
|
|
@@ -171,6 +163,42 @@ export function notifyOnError(
|
|
|
171
163
|
}
|
|
172
164
|
}
|
|
173
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Resolve a thrown build-time render error into the prerender build's policy and
|
|
168
|
+
* log a per-entry line. A `Skip` (or any render error under `prerender.onError:
|
|
169
|
+
* "warn"`) logs and returns so the caller skips the entry; a render error under
|
|
170
|
+
* the default "fail" logs FAIL, notifies `onError`, and re-throws to fail the
|
|
171
|
+
* build. Shared by `expandPrerenderRoutes` (prerender) and `renderStaticHandlers`
|
|
172
|
+
* (static) so the Skip/warn/fail policy lives in one place. `label` is the padded
|
|
173
|
+
* URL / handler name for the log line; `elapsed` is the per-entry duration string.
|
|
174
|
+
*/
|
|
175
|
+
export function resolvePrerenderError(
|
|
176
|
+
registry: Map<string, any>,
|
|
177
|
+
error: any,
|
|
178
|
+
onError: "fail" | "warn",
|
|
179
|
+
label: string,
|
|
180
|
+
elapsed: string,
|
|
181
|
+
phase: "prerender" | "static",
|
|
182
|
+
routeKey?: string,
|
|
183
|
+
pathname?: string,
|
|
184
|
+
): void {
|
|
185
|
+
const isSkip = error?.name === "Skip";
|
|
186
|
+
if (isSkip || onError === "warn") {
|
|
187
|
+
if (isSkip) {
|
|
188
|
+
console.log(`[rango] SKIP ${label} (${elapsed}ms) - ${error.message}`);
|
|
189
|
+
} else {
|
|
190
|
+
console.warn(
|
|
191
|
+
`[rango] WARN ${label} (${elapsed}ms) - render error, not pre-rendered (prerender.onError: "warn"): ${error.message}`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
notifyOnError(registry, error, phase, routeKey, pathname, true);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
console.error(`[rango] FAIL ${label} (${elapsed}ms) - ${error.message}`);
|
|
198
|
+
notifyOnError(registry, error, phase, routeKey, pathname);
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
|
|
174
202
|
function getStagedAssetDir(projectRoot: string): string {
|
|
175
203
|
return resolve(projectRoot, "node_modules/.rangojs-router-build/rsc-assets");
|
|
176
204
|
}
|
|
@@ -1,53 +1,114 @@
|
|
|
1
|
-
import type { Plugin } from "vite";
|
|
1
|
+
import type { Plugin, ResolvedConfig } from "vite";
|
|
2
2
|
import * as Vite from "vite";
|
|
3
|
+
import { isAbsolute, resolve } from "node:path";
|
|
3
4
|
import { getPublishedPackageName } from "./package-resolution.js";
|
|
4
5
|
import { performanceTracksOptimizeDepsPlugin } from "../plugins/performance-tracks.js";
|
|
5
6
|
import {
|
|
6
7
|
VIRTUAL_ENTRY_BROWSER,
|
|
7
8
|
VIRTUAL_ENTRY_SSR,
|
|
8
9
|
getVirtualEntryRSC,
|
|
10
|
+
getVirtualEntryRSCHost,
|
|
11
|
+
getVirtualVersionContent,
|
|
9
12
|
VIRTUAL_IDS,
|
|
10
13
|
} from "../plugins/virtual-entries.js";
|
|
11
14
|
|
|
15
|
+
// Cloudflare preset: @cloudflare/vite-plugin sets optimizeDeps.entries (string
|
|
16
|
+
// or array) on the rsc environment. Single source for both the discovery plugin
|
|
17
|
+
// and the version injector so they target the same entry.
|
|
18
|
+
export function resolveRscEntryFromConfig(
|
|
19
|
+
config: ResolvedConfig,
|
|
20
|
+
): string | undefined {
|
|
21
|
+
const entries = (config.environments as any)?.["rsc"]?.optimizeDeps?.entries;
|
|
22
|
+
if (typeof entries === "string") return entries;
|
|
23
|
+
if (Array.isArray(entries) && entries.length > 0) return entries[0];
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
12
27
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
28
|
+
* Rolldown plugin to provide the version virtual module during dependency
|
|
29
|
+
* optimization. Vite 8 optimizes deps with Rolldown (a Rollup-style plugin
|
|
30
|
+
* pipeline that is separate from the main plugin set), so this is a
|
|
31
|
+
* resolveId/load plugin under optimizeDeps.rolldownOptions. Any dep pulled into
|
|
32
|
+
* optimization that imports the version virtual module gets a "dev" stub here;
|
|
33
|
+
* the real VERSION is injected into runtime modules by the version plugin.
|
|
16
34
|
*/
|
|
17
|
-
const
|
|
35
|
+
const versionRolldownPlugin = {
|
|
18
36
|
name: "@rangojs/router-version",
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
loader: "js",
|
|
29
|
-
}),
|
|
30
|
-
);
|
|
37
|
+
resolveId(id: string): string | undefined {
|
|
38
|
+
if (id === VIRTUAL_IDS.version) return "\0" + VIRTUAL_IDS.version;
|
|
39
|
+
return undefined;
|
|
40
|
+
},
|
|
41
|
+
load(id: string): string | undefined {
|
|
42
|
+
if (id === "\0" + VIRTUAL_IDS.version) {
|
|
43
|
+
return getVirtualVersionContent("dev");
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
31
46
|
},
|
|
32
47
|
};
|
|
33
48
|
|
|
34
49
|
/**
|
|
35
|
-
* Shared
|
|
36
|
-
* Includes the version stub plugin
|
|
50
|
+
* Shared Rolldown options for dependency optimization (Vite 8).
|
|
51
|
+
* Includes the version stub plugin and the performance-tracks RSDW patch.
|
|
37
52
|
*/
|
|
38
|
-
export const
|
|
53
|
+
export const sharedRolldownOptions: {
|
|
39
54
|
plugins: any[];
|
|
40
55
|
} = {
|
|
41
|
-
plugins: [
|
|
56
|
+
plugins: [versionRolldownPlugin, performanceTracksOptimizeDepsPlugin()],
|
|
42
57
|
};
|
|
43
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Normalize an explicit `hostRouter` option into the specifier emitted as the
|
|
61
|
+
* host entry's `import ... from "<path>"`, and — for the forms that resolve
|
|
62
|
+
* unambiguously against the project root — verify the file exists (failing with
|
|
63
|
+
* a rango message instead of a downstream bundler "failed to resolve").
|
|
64
|
+
*
|
|
65
|
+
* Only a BARE specifier ("src/worker.rsc.tsx") that exists under the root is
|
|
66
|
+
* rewritten (to "./src/...") so it is not read as a package. A bare specifier
|
|
67
|
+
* that does NOT exist under the root is passed through VERBATIM: it may be a
|
|
68
|
+
* Vite alias ("@/worker.rsc.tsx"), an imports-map entry ("#app/worker"), or a
|
|
69
|
+
* workspace package the bundler resolves — rewriting or rejecting those was a
|
|
70
|
+
* regression (aliases worked before normalization existed). "./"/"../", a
|
|
71
|
+
* leading-slash (Vite root-relative), and a filesystem-absolute path are
|
|
72
|
+
* emitted unchanged — Vite resolves each. A leading-slash path and a
|
|
73
|
+
* filesystem-absolute path are indistinguishable on POSIX, so both are treated
|
|
74
|
+
* as "rooted": passed through WITHOUT an existence check (guessing between the
|
|
75
|
+
* two would wrongly reject a valid file — this was a regression the first time
|
|
76
|
+
* the check was added). Only the explicitly-relative forms, which resolve
|
|
77
|
+
* unambiguously against the root, fail fast with a rango message.
|
|
78
|
+
*
|
|
79
|
+
* `exists` is injected so the logic is unit-testable without a real filesystem.
|
|
80
|
+
*/
|
|
81
|
+
export function normalizeHostRouterEntry(
|
|
82
|
+
rawInput: string,
|
|
83
|
+
root: string,
|
|
84
|
+
exists: (absPath: string) => boolean,
|
|
85
|
+
): string {
|
|
86
|
+
const raw = rawInput.replaceAll("\\", "/");
|
|
87
|
+
const isRelative = raw.startsWith("./") || raw.startsWith("../");
|
|
88
|
+
const isRooted = raw.startsWith("/") || isAbsolute(rawInput);
|
|
89
|
+
if (isRooted) return raw;
|
|
90
|
+
if (isRelative) {
|
|
91
|
+
if (!exists(resolve(root, raw))) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`[rango] hostRouter entry not found: "${rawInput}" (resolved under ` +
|
|
94
|
+
`${root}). Point it at your createHostRouter() module, e.g. ` +
|
|
95
|
+
`rango({ hostRouter: "./src/worker.rsc.tsx" }).`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
return raw;
|
|
99
|
+
}
|
|
100
|
+
// Bare specifier: an existing root-relative file gets the explicit "./";
|
|
101
|
+
// anything else (alias, imports-map, package) is the bundler's to resolve.
|
|
102
|
+
return exists(resolve(root, raw)) ? "./" + raw : raw;
|
|
103
|
+
}
|
|
104
|
+
|
|
44
105
|
/**
|
|
45
106
|
* Create a virtual modules plugin for default entry files.
|
|
46
107
|
* Provides virtual module content when entries use VIRTUAL_IDS (no custom entry configured).
|
|
47
108
|
*/
|
|
48
109
|
export function createVirtualEntriesPlugin(
|
|
49
110
|
entries: { client: string; ssr: string; rsc?: string },
|
|
50
|
-
routerPathRef?: { path?: string },
|
|
111
|
+
routerPathRef?: { path?: string; kind?: "router" | "host" },
|
|
51
112
|
): Plugin {
|
|
52
113
|
// Build virtual modules map based on which entries use virtual IDs
|
|
53
114
|
const virtualModules: Record<string, string> = {};
|
|
@@ -95,7 +156,9 @@ export function createVirtualEntriesPlugin(
|
|
|
95
156
|
: routerPathRef.path;
|
|
96
157
|
// Normalize backslashes for Windows (path.join/slice preserve native separators)
|
|
97
158
|
const absoluteRouterPath = raw.replaceAll("\\", "/");
|
|
98
|
-
return
|
|
159
|
+
return routerPathRef.kind === "host"
|
|
160
|
+
? getVirtualEntryRSCHost(absoluteRouterPath)
|
|
161
|
+
: getVirtualEntryRSC(absoluteRouterPath);
|
|
99
162
|
}
|
|
100
163
|
}
|
|
101
164
|
return null;
|
|
@@ -103,14 +166,54 @@ export function createVirtualEntriesPlugin(
|
|
|
103
166
|
};
|
|
104
167
|
}
|
|
105
168
|
|
|
169
|
+
// Matches rollup's FILE_NAME_CONFLICT message and reports whether the colliding
|
|
170
|
+
// file is a content-hashed asset, e.g.
|
|
171
|
+
// The emitted file "assets/index-DlGNrvnU.css" overwrites a previously ...
|
|
172
|
+
// The emitted file "assets/inter-latin-Dx4kXJAl.woff2" overwrites a ...
|
|
173
|
+
// The match is UNANCHORED on purpose: by the time the warning reaches this user
|
|
174
|
+
// onwarn handler, Vite's logger has wrapped rollup's raw message with an ANSI
|
|
175
|
+
// color sequence and a "[CODE] " label, e.g.
|
|
176
|
+
// "[33m[FILE_NAME_CONFLICT] [0mThe emitted file \"...\" overwrites ..."
|
|
177
|
+
// A "^The emitted file" anchor sits behind that prefix and never matches; and
|
|
178
|
+
// Vite also strips the JSON.stringify quotes rollup puts around the filename, so
|
|
179
|
+
// the match is UNANCHORED and quote-OPTIONAL ("?...?"?). The non-whitespace
|
|
180
|
+
// capture stops at the space before "overwrites" (Vite's unquoted display form)
|
|
181
|
+
// or the closing quote (raw rollup form); either way it carries no ANSI.
|
|
182
|
+
// A content-hashed name ends with a "-" separator + a Vite content hash. The
|
|
183
|
+
// hash is a FIXED-LENGTH base64url run ([A-Za-z0-9_-], default 8), so it can
|
|
184
|
+
// itself contain "-"/"_": it CANNOT be located by splitting on the last "-"
|
|
185
|
+
// (that lands inside the hash whenever it carries a dash, e.g. "...-Cabi7G8-" ->
|
|
186
|
+
// "" or "...-CkhJZR-_" -> "_", which let those conflicts leak). Instead take the
|
|
187
|
+
// trailing HASH_LEN chars and require the "-" separator right before them. The
|
|
188
|
+
// hash must hold an uppercase letter or digit (a real hash is never an
|
|
189
|
+
// all-lowercase word), so stable names like "assets/manifest.json" or
|
|
190
|
+
// "assets/loading-skeleton.css" still surface as potential genuine overwrites.
|
|
191
|
+
function isContentHashedAssetConflict(message: string | undefined): boolean {
|
|
192
|
+
if (!message) return false;
|
|
193
|
+
const match =
|
|
194
|
+
/The emitted file "?([^"\s]+)"? overwrites a previously emitted file/.exec(
|
|
195
|
+
message,
|
|
196
|
+
);
|
|
197
|
+
if (!match) return false;
|
|
198
|
+
const fileName = match[1];
|
|
199
|
+
const base = fileName.slice(fileName.lastIndexOf("/") + 1);
|
|
200
|
+
const dot = base.lastIndexOf(".");
|
|
201
|
+
if (dot <= 0) return false;
|
|
202
|
+
const stem = base.slice(0, dot);
|
|
203
|
+
// HASH_LEN tracks Vite's default [hash] width; bump it if an app sets a custom
|
|
204
|
+
// assetFileNames hash length.
|
|
205
|
+
const HASH_LEN = 8;
|
|
206
|
+
if (stem.length < HASH_LEN + 1 || stem[stem.length - HASH_LEN - 1] !== "-") {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
const hash = stem.slice(-HASH_LEN);
|
|
210
|
+
return /^[A-Za-z0-9_-]+$/.test(hash) && /[A-Z0-9]/.test(hash);
|
|
211
|
+
}
|
|
212
|
+
|
|
106
213
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* - sourcemap incomplete: plugins that transform without generating sourcemaps (router + RSC plugin)
|
|
111
|
-
* - dynamic/static mixed imports: expected for router internals (e.g. request-context, cache-scope)
|
|
112
|
-
* - empty bundle: @vitejs/plugin-rsc scan build (step 1/5) produces an empty "index" chunk
|
|
113
|
-
* because the RSC entry is fully externalized during client-reference analysis
|
|
214
|
+
* Suppress known harmless warnings: "use client" directives, sourcemap errors,
|
|
215
|
+
* mixed imports (expected for router internals), empty bundles, and content-hashed
|
|
216
|
+
* asset collisions from @vitejs/plugin-rsc copying RSC-env assets to the client bundle.
|
|
114
217
|
*/
|
|
115
218
|
export function onwarn(
|
|
116
219
|
warning: Vite.Rollup.RollupLog,
|
|
@@ -119,14 +222,17 @@ export function onwarn(
|
|
|
119
222
|
if (
|
|
120
223
|
warning.code === "MODULE_LEVEL_DIRECTIVE" ||
|
|
121
224
|
warning.code === "SOURCEMAP_ERROR" ||
|
|
122
|
-
warning.code === "EMPTY_BUNDLE"
|
|
225
|
+
warning.code === "EMPTY_BUNDLE" ||
|
|
226
|
+
warning.code === "INEFFECTIVE_DYNAMIC_IMPORT"
|
|
227
|
+
) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (
|
|
231
|
+
warning.code === "FILE_NAME_CONFLICT" &&
|
|
232
|
+
isContentHashedAssetConflict(warning.message)
|
|
123
233
|
) {
|
|
124
234
|
return;
|
|
125
235
|
}
|
|
126
|
-
// @vitejs/plugin-rsc@0.5.14: rsc:virtual:vite-rsc/assets-manifest renderChunk
|
|
127
|
-
// returns { code } without map, causing Rollup to warn about incorrect sourcemaps.
|
|
128
|
-
// This is harmless (simple string replacement). Remove this suppression if a
|
|
129
|
-
// future version of @vitejs/plugin-rsc fixes the missing sourcemap.
|
|
130
236
|
if (warning.message?.includes("Sourcemap is likely to be incorrect")) {
|
|
131
237
|
return;
|
|
132
238
|
}
|
|
@@ -141,10 +247,6 @@ export function onwarn(
|
|
|
141
247
|
defaultHandler(warning);
|
|
142
248
|
}
|
|
143
249
|
|
|
144
|
-
/**
|
|
145
|
-
* Manual chunks configuration for client build.
|
|
146
|
-
* Splits React and router packages into separate chunks for better caching.
|
|
147
|
-
*/
|
|
148
250
|
export function getManualChunks(id: string): string | undefined {
|
|
149
251
|
const normalized = Vite.normalizePath(id);
|
|
150
252
|
|
|
@@ -156,13 +258,10 @@ export function getManualChunks(id: string): string | undefined {
|
|
|
156
258
|
) {
|
|
157
259
|
return "react";
|
|
158
260
|
}
|
|
159
|
-
// Use dynamic package name from package.json
|
|
160
|
-
// Check both npm install path and workspace symlink resolved path
|
|
161
261
|
const packageName = getPublishedPackageName();
|
|
162
262
|
if (
|
|
163
263
|
normalized.includes(`node_modules/${packageName}/`) ||
|
|
164
|
-
|
|
165
|
-
normalized.includes("packages/rangojs-router/")
|
|
264
|
+
/\/packages\/(rsc-router|rangojs-router)\/(src|dist)\//.test(normalized)
|
|
166
265
|
) {
|
|
167
266
|
return "router";
|
|
168
267
|
}
|