@rangojs/router 0.0.0-experimental.14 → 0.0.0-experimental.141
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 +17 -0
- package/README.md +432 -7
- package/dist/bin/rango.js +2073 -213
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +7258 -2714
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +140 -67
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +329 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +487 -0
- package/skills/caching/SKILL.md +357 -25
- 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 +246 -0
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +16 -10
- package/skills/document-cache/SKILL.md +87 -62
- package/skills/fonts/SKILL.md +6 -4
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +557 -79
- package/skills/host-router/SKILL.md +320 -0
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +207 -15
- package/skills/layout/SKILL.md +146 -6
- package/skills/links/SKILL.md +304 -25
- package/skills/loader/SKILL.md +616 -54
- package/skills/middleware/SKILL.md +217 -37
- package/skills/migrate-nextjs/SKILL.md +611 -0
- package/skills/migrate-react-router/SKILL.md +927 -0
- package/skills/mime-routes/SKILL.md +42 -11
- package/skills/observability/SKILL.md +194 -0
- package/skills/parallel/SKILL.md +284 -3
- package/skills/ppr/SKILL.md +293 -0
- package/skills/prerender/SKILL.md +437 -52
- package/skills/rango/SKILL.md +369 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +263 -121
- package/skills/route/SKILL.md +350 -21
- package/skills/router-setup/SKILL.md +246 -33
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +126 -222
- 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 +9 -8
- package/skills/typesafety/SKILL.md +532 -103
- package/skills/use-cache/SKILL.md +367 -0
- 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 +77 -44
- package/src/bin/rango.ts +312 -15
- package/src/browser/action-coordinator.ts +114 -0
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +293 -202
- package/src/browser/history-state.ts +101 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +11 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +385 -576
- package/src/browser/navigation-client.ts +245 -75
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +184 -118
- package/src/browser/navigation-transaction.ts +247 -0
- package/src/browser/network-error-handler.ts +88 -0
- package/src/browser/partial-update.ts +412 -364
- package/src/browser/prefetch/cache.ts +359 -0
- package/src/browser/prefetch/fetch.ts +452 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +209 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +194 -0
- package/src/browser/react/Link.tsx +275 -68
- package/src/browser/react/NavigationProvider.tsx +265 -109
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +11 -0
- package/src/browser/react/filter-segment-order.ts +70 -0
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +272 -60
- package/src/browser/react/location-state.ts +90 -20
- package/src/browser/react/mount-context.ts +6 -1
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +35 -66
- package/src/browser/react/use-handle.ts +39 -126
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +39 -13
- package/src/browser/react/use-navigation.ts +53 -69
- package/src/browser/react/use-params.ts +75 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +98 -0
- package/src/browser/react/use-search-params.ts +51 -0
- package/src/browser/react/use-segments.ts +72 -99
- package/src/browser/response-adapter.ts +164 -0
- package/src/browser/rsc-router.tsx +300 -72
- package/src/browser/scroll-restoration.ts +138 -50
- package/src/browser/segment-reconciler.ts +243 -0
- package/src/browser/segment-structure-assert.ts +17 -1
- package/src/browser/server-action-bridge.ts +668 -613
- package/src/browser/types.ts +223 -51
- package/src/browser/validate-redirect-origin.ts +56 -0
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +252 -161
- package/src/build/generate-route-types.ts +41 -1038
- package/src/build/index.ts +12 -7
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +225 -42
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +105 -0
- package/src/build/route-types/codegen.ts +113 -0
- package/src/build/route-types/include-resolution.ts +812 -0
- package/src/build/route-types/param-extraction.ts +51 -0
- package/src/build/route-types/per-module-writer.ts +144 -0
- package/src/build/route-types/router-processing.ts +695 -0
- package/src/build/route-types/scan-filter.ts +85 -0
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +223 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +60 -0
- package/src/cache/cache-policy.ts +199 -0
- package/src/cache/cache-runtime.ts +525 -0
- package/src/cache/cache-scope.ts +298 -332
- package/src/cache/cache-tag.ts +103 -0
- package/src/cache/cf/cf-base64.ts +33 -0
- package/src/cache/cf/cf-cache-constants.ts +127 -0
- package/src/cache/cf/cf-cache-store.ts +2508 -158
- 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 +17 -17
- package/src/cache/document-cache.ts +199 -92
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +111 -0
- package/src/cache/index.ts +24 -35
- package/src/cache/memory-segment-store.ts +363 -30
- package/src/cache/profile-registry.ts +88 -0
- package/src/cache/read-through-swr.ts +178 -0
- package/src/cache/segment-codec.ts +248 -0
- package/src/cache/shell-snapshot.ts +368 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +153 -0
- package/src/cache/types.ts +222 -211
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1113 -0
- package/src/client.rsc.tsx +43 -21
- package/src/client.tsx +131 -347
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +109 -0
- package/src/component-utils.ts +23 -4
- package/src/components/DefaultDocument.tsx +13 -3
- package/src/context-var.ts +168 -0
- package/src/debug.ts +19 -9
- 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 +106 -10
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +110 -35
- package/src/handles/MetaTags.tsx +83 -59
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +93 -0
- package/src/handles/deferred-resolution.ts +127 -0
- package/src/handles/is-thenable.ts +18 -0
- package/src/handles/meta.ts +44 -53
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +20 -65
- package/src/host/errors.ts +21 -30
- package/src/host/index.ts +13 -9
- package/src/host/pattern-matcher.ts +50 -79
- package/src/host/router.ts +151 -121
- package/src/host/testing.ts +45 -32
- package/src/host/types.ts +52 -11
- package/src/host/utils.ts +2 -2
- package/src/href-client.ts +192 -57
- package/src/index.rsc.ts +173 -35
- package/src/index.ts +241 -73
- package/src/internal-debug.ts +9 -2
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +31 -99
- package/src/loader.ts +30 -12
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +41 -0
- package/src/prerender/param-hash.ts +16 -14
- package/src/prerender/store.ts +121 -21
- package/src/prerender.ts +460 -26
- package/src/redirect-origin.ts +100 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +62 -0
- package/src/reverse.ts +198 -128
- package/src/root-error-boundary.tsx +42 -48
- package/src/route-content-wrapper.tsx +22 -77
- package/src/route-definition/dsl-helpers.ts +1116 -0
- package/src/route-definition/helper-factories.ts +88 -0
- package/src/route-definition/helpers-types.ts +505 -0
- package/src/route-definition/index.ts +54 -0
- package/src/route-definition/redirect.ts +134 -0
- package/src/route-definition/resolve-handler-use.ts +160 -0
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-definition.ts +1 -1481
- package/src/route-map-builder.ts +82 -144
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +71 -45
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +263 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +54 -27
- package/src/router/find-match.ts +245 -0
- package/src/router/handler-context.ts +377 -125
- package/src/router/instrument.ts +350 -0
- package/src/router/intercept-resolution.ts +59 -28
- package/src/router/lazy-includes.ts +254 -0
- package/src/router/loader-resolution.ts +421 -157
- package/src/router/logging.ts +106 -6
- package/src/router/manifest.ts +131 -57
- package/src/router/match-api.ts +167 -246
- package/src/router/match-context.ts +4 -24
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +117 -93
- package/src/router/match-middleware/cache-lookup.ts +297 -150
- package/src/router/match-middleware/cache-store.ts +123 -51
- package/src/router/match-middleware/intercept-resolution.ts +44 -43
- package/src/router/match-middleware/segment-resolution.ts +64 -22
- package/src/router/match-pipelines.ts +11 -87
- package/src/router/match-result.ts +121 -50
- package/src/router/metrics.ts +219 -28
- package/src/router/middleware-types.ts +93 -0
- package/src/router/middleware.ts +505 -441
- package/src/router/navigation-snapshot.ts +133 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/parse-pattern.ts +115 -0
- package/src/router/pattern-matching.ts +311 -142
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +547 -0
- package/src/router/preview-match.ts +102 -0
- package/src/router/request-classification.ts +278 -0
- package/src/router/revalidation.ts +203 -62
- package/src/router/route-snapshot.ts +246 -0
- package/src/router/router-context.ts +45 -48
- package/src/router/router-interfaces.ts +554 -0
- package/src/router/router-options.ts +779 -0
- package/src/router/router-registry.ts +21 -0
- package/src/router/segment-resolution/fresh.ts +772 -0
- package/src/router/segment-resolution/helpers.ts +348 -0
- package/src/router/segment-resolution/loader-cache.ts +250 -0
- package/src/router/segment-resolution/loader-mask.ts +44 -0
- package/src/router/segment-resolution/revalidation.ts +1331 -0
- package/src/router/segment-resolution/static-store.ts +81 -0
- 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 +25 -1354
- package/src/router/segment-wrappers.ts +292 -0
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +75 -0
- package/src/router/telemetry-otel.ts +261 -0
- package/src/router/telemetry.ts +377 -0
- package/src/router/timeout.ts +128 -0
- package/src/router/tracing.ts +206 -0
- package/src/router/trie-matching.ts +240 -61
- package/src/router/types.ts +23 -70
- package/src/router/url-params.ts +57 -0
- package/src/router.ts +781 -2378
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +46 -0
- package/src/rsc/handler.ts +905 -1142
- package/src/rsc/helpers.ts +275 -19
- package/src/rsc/index.ts +2 -25
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +305 -0
- package/src/rsc/manifest-init.ts +77 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +155 -0
- package/src/rsc/progressive-enhancement.ts +502 -0
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +104 -0
- package/src/rsc/response-route-handler.ts +257 -0
- package/src/rsc/rsc-rendering.ts +527 -0
- package/src/rsc/runtime-warnings.ts +55 -0
- package/src/rsc/server-action.ts +522 -0
- package/src/rsc/shell-capture.ts +897 -0
- package/src/rsc/shell-serve.ts +124 -0
- package/src/rsc/ssr-setup.ts +144 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +95 -12
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +99 -82
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +149 -0
- package/src/segment-system.tsx +349 -134
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +459 -85
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +310 -0
- package/src/server/fetchable-loader-store.ts +11 -6
- package/src/server/handle-store.ts +123 -42
- package/src/server/loader-registry.ts +51 -100
- package/src/server/request-context.ts +848 -157
- package/src/server.ts +15 -8
- package/src/ssr/index.tsx +443 -135
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +45 -18
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +46 -0
- package/src/testing/dispatch.ts +701 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +257 -0
- package/src/testing/generated-routes.ts +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 +76 -98
- package/src/theme/ThemeScript.tsx +12 -14
- package/src/theme/constants.ts +57 -15
- package/src/theme/index.ts +3 -20
- package/src/theme/theme-context.ts +5 -35
- package/src/theme/theme-script.ts +43 -39
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +123 -0
- package/src/types/cache-types.ts +207 -0
- package/src/types/error-types.ts +132 -0
- package/src/types/global-namespace.ts +113 -0
- package/src/types/handler-context.ts +839 -0
- package/src/types/index.ts +81 -0
- package/src/types/loader-types.ts +212 -0
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +138 -0
- package/src/types/route-entry.ts +114 -0
- package/src/types/segments.ts +271 -0
- package/src/types.ts +1 -1795
- package/src/urls/include-helper.ts +162 -0
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +44 -0
- package/src/urls/path-helper-types.ts +413 -0
- package/src/urls/path-helper.ts +280 -0
- package/src/urls/pattern-types.ts +160 -0
- package/src/urls/response-types.ts +109 -0
- package/src/urls/type-extraction.ts +316 -0
- package/src/urls/urls-function.ts +80 -0
- package/src/urls.ts +1 -1341
- package/src/use-loader.tsx +406 -141
- 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 +182 -0
- package/src/vite/discovery/discover-routers.ts +389 -0
- 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 +467 -0
- package/src/vite/discovery/route-types-writer.ts +214 -0
- package/src/vite/discovery/self-gen-tracking.ts +73 -0
- package/src/vite/discovery/state.ts +161 -0
- package/src/vite/discovery/virtual-module-codegen.ts +183 -0
- package/src/vite/index.ts +23 -2255
- package/src/vite/inject-client-debug.ts +36 -0
- package/src/vite/plugin-types.ts +303 -0
- package/src/vite/plugins/cjs-to-esm.ts +90 -0
- package/src/vite/plugins/client-ref-dedup.ts +120 -0
- package/src/vite/plugins/client-ref-hashing.ts +118 -0
- 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/{expose-action-id.ts → plugins/expose-action-id.ts} +88 -110
- package/src/vite/{expose-id-utils.ts → plugins/expose-id-utils.ts} +89 -79
- package/src/vite/plugins/expose-ids/export-analysis.ts +363 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +130 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +64 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +199 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +805 -0
- package/src/vite/plugins/performance-tracks.ts +89 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +313 -0
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +94 -0
- package/src/vite/plugins/version-plugin.ts +263 -0
- package/src/vite/plugins/virtual-entries.ts +234 -0
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +560 -0
- package/src/vite/router-discovery.ts +1638 -0
- package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +200 -37
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +132 -0
- 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 +15 -0
- package/src/vite/utils/package-resolution.ts +89 -0
- package/src/vite/utils/prerender-utils.ts +249 -0
- package/src/vite/utils/shared-utils.ts +269 -0
- package/CLAUDE.md +0 -43
- package/dist/vite/index.named-routes.gen.ts +0 -103
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/react/use-client-cache.ts +0 -56
- package/src/browser/request-controller.ts +0 -164
- package/src/browser/shallow.ts +0 -35
- package/src/cache/memory-store.ts +0 -253
- package/src/handles/index.ts +0 -6
- package/src/href-context.ts +0 -33
- package/src/network-error-thrower.tsx +0 -21
- package/src/router.gen.ts +0 -6
- package/src/static-handler.gen.ts +0 -5
- package/src/urls.gen.ts +0 -8
- package/src/vite/expose-internal-ids.ts +0 -1167
- package/src/vite/package-resolution.ts +0 -125
- package/src/vite/virtual-entries.ts +0 -114
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
copyFileSync,
|
|
4
|
+
existsSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
rmSync,
|
|
7
|
+
statSync,
|
|
8
|
+
writeFileSync,
|
|
9
|
+
} from "node:fs";
|
|
10
|
+
import { resolve } from "node:path";
|
|
11
|
+
|
|
12
|
+
import { escapeRegExp } from "../../regex-escape.js";
|
|
13
|
+
import { encodePathRemainder } from "../../router/url-params.js";
|
|
14
|
+
|
|
15
|
+
export function encodePathParam(value: unknown): string {
|
|
16
|
+
return encodePathRemainder(String(value), encodeURIComponent);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function substituteRouteParams(
|
|
20
|
+
pattern: string,
|
|
21
|
+
params: Record<string, string>,
|
|
22
|
+
encode: (value: string) => string = encodeURIComponent,
|
|
23
|
+
): string {
|
|
24
|
+
let result = pattern;
|
|
25
|
+
let hadOmittedOptional = false;
|
|
26
|
+
|
|
27
|
+
for (const [key, value] of Object.entries(params)) {
|
|
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
|
+
}
|
|
44
|
+
if (value === "") {
|
|
45
|
+
result = result.replace(
|
|
46
|
+
new RegExp(`:${escaped}(\\([^)]*\\))?(?!\\?)`),
|
|
47
|
+
"",
|
|
48
|
+
);
|
|
49
|
+
result = result.replace(`*${key}`, "");
|
|
50
|
+
} else {
|
|
51
|
+
result = result.replace(
|
|
52
|
+
new RegExp(`:${escaped}(\\([^)]*\\))?\\??`),
|
|
53
|
+
encode(value),
|
|
54
|
+
);
|
|
55
|
+
result = result.replace(`*${key}`, encode(value));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
result = result.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\([^)]*\))?\?/g, () => {
|
|
60
|
+
hadOmittedOptional = true;
|
|
61
|
+
return "";
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (hadOmittedOptional) {
|
|
65
|
+
const hadTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
|
|
66
|
+
result = result.replace(/\/\/+/g, "/").replace(/\/+$/, "") || "/";
|
|
67
|
+
if (hadTrailingSlash && !result.endsWith("/")) result += "/";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function runWithConcurrency<T>(
|
|
74
|
+
items: T[],
|
|
75
|
+
concurrency: number,
|
|
76
|
+
fn: (item: T) => Promise<void>,
|
|
77
|
+
): Promise<void> {
|
|
78
|
+
const limit = Math.max(1, Math.min(concurrency, items.length));
|
|
79
|
+
if (limit <= 1) {
|
|
80
|
+
for (const item of items) await fn(item);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
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;
|
|
90
|
+
async function worker() {
|
|
91
|
+
while (nextIndex < items.length && !failed) {
|
|
92
|
+
const idx = nextIndex++;
|
|
93
|
+
try {
|
|
94
|
+
await fn(items[idx]);
|
|
95
|
+
} catch (err) {
|
|
96
|
+
if (!failed) {
|
|
97
|
+
failed = true;
|
|
98
|
+
firstError = err;
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
await Promise.all(Array.from({ length: limit }, () => worker()));
|
|
105
|
+
if (failed) throw firstError;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function groupByConcurrency<T extends { concurrency: number }>(
|
|
109
|
+
entries: T[],
|
|
110
|
+
): { concurrency: number; entries: T[] }[] {
|
|
111
|
+
const map = new Map<number, T[]>();
|
|
112
|
+
for (const entry of entries) {
|
|
113
|
+
const key = entry.concurrency;
|
|
114
|
+
let group = map.get(key);
|
|
115
|
+
if (!group) {
|
|
116
|
+
group = [];
|
|
117
|
+
map.set(key, group);
|
|
118
|
+
}
|
|
119
|
+
group.push(entry);
|
|
120
|
+
}
|
|
121
|
+
return Array.from(map.entries(), ([concurrency, items]) => ({
|
|
122
|
+
concurrency,
|
|
123
|
+
entries: items,
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function notifyOnError(
|
|
128
|
+
registry: Map<string, any>,
|
|
129
|
+
error: unknown,
|
|
130
|
+
phase: "prerender" | "static",
|
|
131
|
+
routeKey?: string,
|
|
132
|
+
pathname?: string,
|
|
133
|
+
skipped?: boolean,
|
|
134
|
+
): void {
|
|
135
|
+
for (const [, routerInstance] of registry) {
|
|
136
|
+
const onError = routerInstance.onError;
|
|
137
|
+
if (!onError) continue;
|
|
138
|
+
|
|
139
|
+
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
140
|
+
const syntheticUrl = new URL("http://prerender" + (pathname || "/"));
|
|
141
|
+
const context = {
|
|
142
|
+
error: errorObj,
|
|
143
|
+
phase,
|
|
144
|
+
request: new Request(syntheticUrl),
|
|
145
|
+
url: syntheticUrl,
|
|
146
|
+
pathname: syntheticUrl.pathname,
|
|
147
|
+
method: "GET",
|
|
148
|
+
routeKey,
|
|
149
|
+
metadata: skipped ? { skipped: true } : undefined,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
const result = onError(context);
|
|
154
|
+
if (result instanceof Promise) {
|
|
155
|
+
result.catch((cbErr: unknown) => {
|
|
156
|
+
console.error(`[Build.onError] Callback error:`, cbErr);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
} catch (cbErr) {
|
|
160
|
+
console.error(`[Build.onError] Callback error:`, cbErr);
|
|
161
|
+
}
|
|
162
|
+
break; // Only notify the first router with onError
|
|
163
|
+
}
|
|
164
|
+
}
|
|
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
|
+
|
|
202
|
+
function getStagedAssetDir(projectRoot: string): string {
|
|
203
|
+
return resolve(projectRoot, "node_modules/.rangojs-router-build/rsc-assets");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function resetStagedBuildAssets(projectRoot: string): void {
|
|
207
|
+
rmSync(getStagedAssetDir(projectRoot), { recursive: true, force: true });
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function stageBuildAssetModule(
|
|
211
|
+
projectRoot: string,
|
|
212
|
+
prefix: "__pr" | "__st",
|
|
213
|
+
exportValue: string,
|
|
214
|
+
): string {
|
|
215
|
+
const stagedDir = getStagedAssetDir(projectRoot);
|
|
216
|
+
mkdirSync(stagedDir, { recursive: true });
|
|
217
|
+
|
|
218
|
+
const contentHash = createHash("sha256")
|
|
219
|
+
.update(exportValue)
|
|
220
|
+
.digest("hex")
|
|
221
|
+
.slice(0, 8);
|
|
222
|
+
const fileName = `${prefix}-${contentHash}.js`;
|
|
223
|
+
const filePath = resolve(stagedDir, fileName);
|
|
224
|
+
|
|
225
|
+
if (!existsSync(filePath)) {
|
|
226
|
+
writeFileSync(filePath, `export default ${exportValue};\n`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return fileName;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function copyStagedBuildAssets(
|
|
233
|
+
projectRoot: string,
|
|
234
|
+
fileNames: Iterable<string>,
|
|
235
|
+
): number {
|
|
236
|
+
const stagedDir = getStagedAssetDir(projectRoot);
|
|
237
|
+
const distAssetsDir = resolve(projectRoot, "dist/rsc/assets");
|
|
238
|
+
mkdirSync(distAssetsDir, { recursive: true });
|
|
239
|
+
|
|
240
|
+
let totalBytes = 0;
|
|
241
|
+
for (const fileName of new Set(fileNames)) {
|
|
242
|
+
const stagedPath = resolve(stagedDir, fileName);
|
|
243
|
+
const distPath = resolve(distAssetsDir, fileName);
|
|
244
|
+
copyFileSync(stagedPath, distPath);
|
|
245
|
+
totalBytes += statSync(stagedPath).size;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return totalBytes;
|
|
249
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import type { Plugin, ResolvedConfig } from "vite";
|
|
2
|
+
import * as Vite from "vite";
|
|
3
|
+
import { isAbsolute, resolve } from "node:path";
|
|
4
|
+
import { getPublishedPackageName } from "./package-resolution.js";
|
|
5
|
+
import { performanceTracksOptimizeDepsPlugin } from "../plugins/performance-tracks.js";
|
|
6
|
+
import {
|
|
7
|
+
VIRTUAL_ENTRY_BROWSER,
|
|
8
|
+
VIRTUAL_ENTRY_SSR,
|
|
9
|
+
getVirtualEntryRSC,
|
|
10
|
+
getVirtualEntryRSCHost,
|
|
11
|
+
getVirtualVersionContent,
|
|
12
|
+
VIRTUAL_IDS,
|
|
13
|
+
} from "../plugins/virtual-entries.js";
|
|
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
|
+
|
|
27
|
+
/**
|
|
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.
|
|
34
|
+
*/
|
|
35
|
+
const versionRolldownPlugin = {
|
|
36
|
+
name: "@rangojs/router-version",
|
|
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;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Shared Rolldown options for dependency optimization (Vite 8).
|
|
51
|
+
* Includes the version stub plugin and the performance-tracks RSDW patch.
|
|
52
|
+
*/
|
|
53
|
+
export const sharedRolldownOptions: {
|
|
54
|
+
plugins: any[];
|
|
55
|
+
} = {
|
|
56
|
+
plugins: [versionRolldownPlugin, performanceTracksOptimizeDepsPlugin()],
|
|
57
|
+
};
|
|
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
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Create a virtual modules plugin for default entry files.
|
|
107
|
+
* Provides virtual module content when entries use VIRTUAL_IDS (no custom entry configured).
|
|
108
|
+
*/
|
|
109
|
+
export function createVirtualEntriesPlugin(
|
|
110
|
+
entries: { client: string; ssr: string; rsc?: string },
|
|
111
|
+
routerPathRef?: { path?: string; kind?: "router" | "host" },
|
|
112
|
+
): Plugin {
|
|
113
|
+
// Build virtual modules map based on which entries use virtual IDs
|
|
114
|
+
const virtualModules: Record<string, string> = {};
|
|
115
|
+
|
|
116
|
+
if (entries.client === VIRTUAL_IDS.browser) {
|
|
117
|
+
virtualModules[VIRTUAL_IDS.browser] = VIRTUAL_ENTRY_BROWSER;
|
|
118
|
+
}
|
|
119
|
+
if (entries.ssr === VIRTUAL_IDS.ssr) {
|
|
120
|
+
virtualModules[VIRTUAL_IDS.ssr] = VIRTUAL_ENTRY_SSR;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// RSC entry is resolved lazily in load() because routerPath may be
|
|
124
|
+
// set after plugin creation (e.g. by the auto-discover config() hook).
|
|
125
|
+
// Track all known virtual IDs for resolveId (content is separate).
|
|
126
|
+
const knownIds = new Set(Object.keys(virtualModules));
|
|
127
|
+
if (entries.rsc === VIRTUAL_IDS.rsc) {
|
|
128
|
+
knownIds.add(VIRTUAL_IDS.rsc);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
name: "@rangojs/router:virtual-entries",
|
|
133
|
+
enforce: "pre",
|
|
134
|
+
|
|
135
|
+
resolveId(id) {
|
|
136
|
+
if (knownIds.has(id)) {
|
|
137
|
+
return "\0" + id;
|
|
138
|
+
}
|
|
139
|
+
// Handle if the id already has the null prefix (RSC plugin wrapper imports)
|
|
140
|
+
if (id.startsWith("\0") && knownIds.has(id.slice(1))) {
|
|
141
|
+
return id;
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
load(id) {
|
|
147
|
+
if (id.startsWith("\0virtual:rsc-router/")) {
|
|
148
|
+
const virtualId = id.slice(1);
|
|
149
|
+
if (virtualId in virtualModules) {
|
|
150
|
+
return virtualModules[virtualId];
|
|
151
|
+
}
|
|
152
|
+
// Lazy RSC entry: routerPath may have been set by a config() hook
|
|
153
|
+
if (virtualId === VIRTUAL_IDS.rsc && routerPathRef?.path) {
|
|
154
|
+
const raw = routerPathRef.path.startsWith(".")
|
|
155
|
+
? "/" + routerPathRef.path.slice(2) // ./src/router.tsx -> /src/router.tsx
|
|
156
|
+
: routerPathRef.path;
|
|
157
|
+
// Normalize backslashes for Windows (path.join/slice preserve native separators)
|
|
158
|
+
const absoluteRouterPath = raw.replaceAll("\\", "/");
|
|
159
|
+
return routerPathRef.kind === "host"
|
|
160
|
+
? getVirtualEntryRSCHost(absoluteRouterPath)
|
|
161
|
+
: getVirtualEntryRSC(absoluteRouterPath);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
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
|
+
|
|
213
|
+
/**
|
|
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.
|
|
217
|
+
*/
|
|
218
|
+
export function onwarn(
|
|
219
|
+
warning: Vite.Rollup.RollupLog,
|
|
220
|
+
defaultHandler: (warning: Vite.Rollup.RollupLog) => void,
|
|
221
|
+
): void {
|
|
222
|
+
if (
|
|
223
|
+
warning.code === "MODULE_LEVEL_DIRECTIVE" ||
|
|
224
|
+
warning.code === "SOURCEMAP_ERROR" ||
|
|
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)
|
|
233
|
+
) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (warning.message?.includes("Sourcemap is likely to be incorrect")) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (
|
|
240
|
+
warning.plugin === "vite:reporter" &&
|
|
241
|
+
warning.message?.includes(
|
|
242
|
+
"dynamic import will not move module into another chunk",
|
|
243
|
+
)
|
|
244
|
+
) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
defaultHandler(warning);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function getManualChunks(id: string): string | undefined {
|
|
251
|
+
const normalized = Vite.normalizePath(id);
|
|
252
|
+
|
|
253
|
+
if (
|
|
254
|
+
normalized.includes("node_modules/react/") ||
|
|
255
|
+
normalized.includes("node_modules/react-dom/") ||
|
|
256
|
+
normalized.includes("node_modules/react-server-dom-webpack/") ||
|
|
257
|
+
normalized.includes("node_modules/@vitejs/plugin-rsc/")
|
|
258
|
+
) {
|
|
259
|
+
return "react";
|
|
260
|
+
}
|
|
261
|
+
const packageName = getPublishedPackageName();
|
|
262
|
+
if (
|
|
263
|
+
normalized.includes(`node_modules/${packageName}/`) ||
|
|
264
|
+
/\/packages\/(rsc-router|rangojs-router)\/(src|dist)\//.test(normalized)
|
|
265
|
+
) {
|
|
266
|
+
return "router";
|
|
267
|
+
}
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
package/CLAUDE.md
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# @rangojs/router
|
|
2
|
-
|
|
3
|
-
Run `/rango` first to understand the API. Skills are in `node_modules/@rangojs/router/skills/`.
|
|
4
|
-
|
|
5
|
-
## Tree-Structure-Critical Files (DO NOT MODIFY without understanding)
|
|
6
|
-
|
|
7
|
-
The following files control the React tree structure. Changing the tree structure
|
|
8
|
-
(element types, nesting depth, or keys at any position) between SSR, navigation,
|
|
9
|
-
and action renders will cause React to remount components, destroying client state
|
|
10
|
-
like `useActionState`, refs, and local state. This is extremely hard to debug.
|
|
11
|
-
|
|
12
|
-
**Protected files:**
|
|
13
|
-
|
|
14
|
-
- `src/segment-system.tsx` - `renderSegments()` builds the React tree from segments.
|
|
15
|
-
The `loading` property determines tree structure:
|
|
16
|
-
- `undefined` / `null` -> OutletProvider directly (no boundary)
|
|
17
|
-
- `false` -> LoaderBoundary + OutletProvider (boundary, no RouteContentWrapper)
|
|
18
|
-
- truthy (ReactNode) -> LoaderBoundary + OutletProvider + RouteContentWrapper
|
|
19
|
-
|
|
20
|
-
- `src/route-content-wrapper.tsx` - `LoaderBoundary` and `RouteContentWrapper`.
|
|
21
|
-
These add structural depth (Suspense boundaries) to the React tree.
|
|
22
|
-
|
|
23
|
-
- `src/browser/server-action-bridge.ts` - Merges server action segments with
|
|
24
|
-
cached segments. Must preserve cached `loading` values to prevent tree drift.
|
|
25
|
-
|
|
26
|
-
- `src/browser/partial-update.ts` - Merges navigation segments with cached segments.
|
|
27
|
-
|
|
28
|
-
**Rules:**
|
|
29
|
-
|
|
30
|
-
1. Never change the conditional logic in `renderSegments()` that decides between
|
|
31
|
-
LoaderBoundary/RouteContentWrapper/OutletProvider without verifying all three
|
|
32
|
-
render paths (SSR, navigation, action) produce identical tree structures.
|
|
33
|
-
|
|
34
|
-
2. Never add or remove wrapper elements (Suspense, div, Fragment) around segment
|
|
35
|
-
content without checking that the same wrappers exist in ALL render paths.
|
|
36
|
-
|
|
37
|
-
3. When merging segments (action bridge, partial update), always preserve the
|
|
38
|
-
cached `loading` value if it differs from the server value. The server may
|
|
39
|
-
return different `loading` values based on `isSSR` context.
|
|
40
|
-
|
|
41
|
-
4. Run `pnpm --filter @rangojs/router exec playwright test loader-behavior` after
|
|
42
|
-
any changes to these files. The skipSSR action tests specifically catch tree
|
|
43
|
-
structure regressions.
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
// Auto-generated by @rangojs/router - do not edit
|
|
2
|
-
export {};
|
|
3
|
-
|
|
4
|
-
declare global {
|
|
5
|
-
namespace RSCRouter {
|
|
6
|
-
interface GeneratedRouteMap {
|
|
7
|
-
"apiShop.cart": "/api/shop/cart";
|
|
8
|
-
"apiShop.cartItem": "/api/shop/cart/:itemId";
|
|
9
|
-
"apiShop.catalog": "/api/shop/catalog";
|
|
10
|
-
"apiShop.health": "/api/shop/health";
|
|
11
|
-
"apiShop.product": "/api/shop/catalog/:productId";
|
|
12
|
-
"blog.index": "/blog";
|
|
13
|
-
"blog.post": "/blog/:postId";
|
|
14
|
-
"cacheStatus.notFound": "/cache-status/not-found";
|
|
15
|
-
"cacheStatus.redirect": "/cache-status/redirect";
|
|
16
|
-
"cacheStatus.redirectTarget": "/cache-status/redirect-target";
|
|
17
|
-
"cacheStatus.serverError": "/cache-status/server-error";
|
|
18
|
-
"cacheStatus.success": "/cache-status/success";
|
|
19
|
-
"cacheTest.cachedLoader": "/cache-test/cached-loader";
|
|
20
|
-
"cacheTest.interceptDetail": "/cache-test/intercept/:itemId";
|
|
21
|
-
"cacheTest.interceptIndex": "/cache-test/intercept";
|
|
22
|
-
"cacheTest.nonCachedLoader": "/cache-test/non-cached-loader";
|
|
23
|
-
"cacheTest.useLoaderDetail": "/cache-test/useloader/:itemId";
|
|
24
|
-
"cacheTest.useLoaderIndex": "/cache-test/useloader";
|
|
25
|
-
"changelog": "/changelog";
|
|
26
|
-
"docs": "/docs";
|
|
27
|
-
"docs.article": "/docs/:slug";
|
|
28
|
-
"errors.clientError": "/errors/client-error";
|
|
29
|
-
"errors.index": "/errors";
|
|
30
|
-
"errors.serverError": "/errors/server-error";
|
|
31
|
-
"errors.streamingError": "/errors/streaming-error";
|
|
32
|
-
"fetchLoader": "/fetch-loader";
|
|
33
|
-
"handlePassthrough": "/handle-passthrough";
|
|
34
|
-
"handlePassthroughAsync": "/handle-passthrough-async";
|
|
35
|
-
"hookTests.formAction": "/hook-tests/form-action";
|
|
36
|
-
"hookTests.index": "/hook-tests";
|
|
37
|
-
"hookTests.noLoader": "/hook-tests/no-loader";
|
|
38
|
-
"hookTests.routeA": "/hook-tests/route-a";
|
|
39
|
-
"hookTests.routeB": "/hook-tests/route-b";
|
|
40
|
-
"href.detail": "/href/:id";
|
|
41
|
-
"href.index": "/href";
|
|
42
|
-
"href.nested.index": "/href/nested";
|
|
43
|
-
"hydrationTest": "/hydration-test";
|
|
44
|
-
"index": "/";
|
|
45
|
-
"inlineAction": "/inline-action";
|
|
46
|
-
"loaderComposition": "/loader-composition";
|
|
47
|
-
"metaMerge.child": "/meta-merge/child";
|
|
48
|
-
"metaMerge.deep": "/meta-merge/deep/nested";
|
|
49
|
-
"metaMerge.index": "/meta-merge";
|
|
50
|
-
"metaTemplate.absolute": "/meta-template/absolute";
|
|
51
|
-
"metaTemplate.child": "/meta-template/child";
|
|
52
|
-
"metaTemplate.index": "/meta-template";
|
|
53
|
-
"metaTemplate.nested": "/meta-template/nested";
|
|
54
|
-
"metaTemplate.nestedChild": "/meta-template/nested/child";
|
|
55
|
-
"metaUnset.child": "/meta-unset/child";
|
|
56
|
-
"metaUnset.index": "/meta-unset";
|
|
57
|
-
"metaUnset.unsetThenSet": "/meta-unset/unset-then-set";
|
|
58
|
-
"middlewareTest.cookies": "/middleware-test/cookies";
|
|
59
|
-
"middlewareTest.errorHandler": "/middleware-test/error-handler/trigger";
|
|
60
|
-
"middlewareTest.index": "/middleware-test";
|
|
61
|
-
"middlewareTest.params": "/middleware-test/params/:paramId";
|
|
62
|
-
"middlewareTest.protected": "/middleware-test/protected";
|
|
63
|
-
"middlewareTest.protectedDashboard": "/middleware-test/protected/dashboard";
|
|
64
|
-
"middlewareTest.routeLevel": "/middleware-test/route-level";
|
|
65
|
-
"middlewareTest.routeLevelWithParams": "/middleware-test/route-level/:routeId";
|
|
66
|
-
"middlewareTest.sharedVars": "/middleware-test/shared-vars";
|
|
67
|
-
"negotiateJsonFirst": "/negotiate-test-json-first";
|
|
68
|
-
"negotiateJsonFirstRsc": "/negotiate-test-json-first";
|
|
69
|
-
"negotiateTest": "/negotiate-test";
|
|
70
|
-
"negotiateTestJson": "/negotiate-test";
|
|
71
|
-
"negotiateTestMd": "/negotiate-test";
|
|
72
|
-
"proactiveCache.index": "/proactive-cache";
|
|
73
|
-
"proactiveCache.itemA": "/proactive-cache/item-a";
|
|
74
|
-
"proactiveCache.itemB": "/proactive-cache/item-b";
|
|
75
|
-
"product.detail": "/product/:productId";
|
|
76
|
-
"progressiveEnhancement": "/progressive-enhancement";
|
|
77
|
-
"refTest.bothProps": "/ref-test/both-props";
|
|
78
|
-
"refTest.handleProp": "/ref-test/handle-prop";
|
|
79
|
-
"refTest.loaderProp": "/ref-test/loader-prop";
|
|
80
|
-
"responseInLayout": "/response-in-layout";
|
|
81
|
-
"responseInLayoutMd": "/response-in-layout-md";
|
|
82
|
-
"responseMwMd": "/response-mw/md-with-mw";
|
|
83
|
-
"responseMwNested": "/response-mw/nested";
|
|
84
|
-
"responseWrapAuto": "/response-wrap/auto";
|
|
85
|
-
"responseWrapCustom": "/response-wrap/custom-response";
|
|
86
|
-
"responseWrapHtml": "/response-wrap/html";
|
|
87
|
-
"responseWrapJsonHeaders": "/response-wrap/json-headers";
|
|
88
|
-
"responseWrapText": "/response-wrap/text";
|
|
89
|
-
"responseWrapWithHeaders": "/response-wrap/with-headers";
|
|
90
|
-
"responseWrapXml": "/response-wrap/xml";
|
|
91
|
-
"shopPlayground": "/shop-playground";
|
|
92
|
-
"slow": "/slow";
|
|
93
|
-
"slowProduct.detail": "/slow-product/:productId";
|
|
94
|
-
"slowStreaming": "/slow-streaming";
|
|
95
|
-
"slowStreamingSkipSsr": "/slow-streaming-skip-ssr";
|
|
96
|
-
"theme.index": "/theme";
|
|
97
|
-
"theme.toggle": "/theme/toggle";
|
|
98
|
-
"trailingSlash.always": "/ts-always";
|
|
99
|
-
"trailingSlash.ignore": "/ts-ignore";
|
|
100
|
-
"trailingSlash.never": "/ts-never";
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|