@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
package/AGENTS.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @rangojs/router
|
|
2
|
+
|
|
3
|
+
A file-system based React Server Components router.
|
|
4
|
+
|
|
5
|
+
Run `/rango` to understand the API. Detailed guides for each feature are in the `skills/` directory (e.g. `node_modules/@rangojs/router/skills/loader`, `skills/caching`, `skills/middleware`, etc.).
|
|
6
|
+
|
|
7
|
+
## Development rules
|
|
8
|
+
|
|
9
|
+
- Always commit generated files (e.g. `*.gen.ts`) alongside the source changes that produced them.
|
|
10
|
+
|
|
11
|
+
## Repo-wide rules (read before pushing)
|
|
12
|
+
|
|
13
|
+
This package inherits the repo-wide conventions in the root [`AGENTS.md`](../../AGENTS.md) and [`CLAUDE.md`](../../CLAUDE.md). The ones a package-scoped reader is most likely to miss:
|
|
14
|
+
|
|
15
|
+
- **Pre-push gate** — before EVERY push, run all of the following from the **repo root** and fix any failures: `pnpm run typecheck`, `pnpm run test:unit:all`, `pnpm run lint`, `pnpm run format`.
|
|
16
|
+
- **`test:unit:all` is recursive** — it runs the unit AND Flight/RSC suites for every package and consumer app (cloudflare-basic, mini, vite-rsc-demo, ...), not just `@rangojs/router`. A change can pass this package's own tests while breaking a consumer app's `@rangojs/router/testing` dogfood suite, so do not run only `pnpm --filter @rangojs/router test:unit`.
|
|
17
|
+
- **Dev + prod e2e parity is mandatory** — every e2e test must cover BOTH dev and production modes; never add a dev-only test without its production counterpart. See the dev/prod bucketing convention in the root `AGENTS.md`.
|
package/README.md
CHANGED
|
@@ -1,18 +1,443 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Rango
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A code-first, type-safe React Server Components router. Django-inspired:
|
|
4
|
+
routes are expressed in one visible tree, URLs are built from names, and
|
|
5
|
+
everything past the core is opt-in.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
> **Experimental:** This package is under active development. APIs may change
|
|
8
|
+
> between releases. Install with `@experimental` tag.
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
This page is a tour: it builds one small shop and meets the entire core API
|
|
11
|
+
along the way — about six primitives. Everything else is opt-in and linked at
|
|
12
|
+
the end. For the design rationale behind these APIs, read
|
|
13
|
+
[Why Rango](https://github.com/ivogt/vite-rsc/blob/main/packages/rangojs-router/docs/why-rango.md); this page shows how it feels, that page
|
|
14
|
+
argues why it's right.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @rangojs/router@experimental react @vitejs/plugin-rsc
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
// vite.config.ts
|
|
24
|
+
import react from "@vitejs/plugin-react";
|
|
25
|
+
import { defineConfig } from "vite";
|
|
26
|
+
import { rango } from "@rangojs/router/vite";
|
|
27
|
+
|
|
28
|
+
export default defineConfig({
|
|
29
|
+
plugins: [react(), rango({ preset: "cloudflare" })],
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The `cloudflare` preset targets Cloudflare Workers (add
|
|
34
|
+
`@cloudflare/vite-plugin`); the `vercel` preset emits a ready-to-deploy
|
|
35
|
+
`.vercel/output` (Build Output API) from a plain `vite build` — see the
|
|
36
|
+
[`/vercel` skill](./skills/vercel/SKILL.md); omit `preset` for the default
|
|
37
|
+
Node setup.
|
|
38
|
+
|
|
39
|
+
## 1. Pages
|
|
40
|
+
|
|
41
|
+
A router is a tree. `path()` places a page, `layout()` wraps children,
|
|
42
|
+
`{ name }` gives a route an identity:
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
// src/router.tsx
|
|
46
|
+
import { createRouter, urls } from "@rangojs/router";
|
|
47
|
+
import { Document } from "./document";
|
|
48
|
+
import { ShopLayout } from "./layouts/shop";
|
|
49
|
+
import { HomePage } from "./routes/home";
|
|
50
|
+
import { ProductPage } from "./routes/product";
|
|
51
|
+
|
|
52
|
+
const urlpatterns = urls(({ path, layout }) => [
|
|
53
|
+
layout(<ShopLayout />, () => [
|
|
54
|
+
path("/", HomePage, { name: "home" }),
|
|
55
|
+
path("/products/:slug", ProductPage, { name: "product" }),
|
|
56
|
+
]),
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
export const router = createRouter({ document: Document }).routes(urlpatterns);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
// src/layouts/shop.tsx
|
|
64
|
+
import { Outlet } from "@rangojs/router/client";
|
|
65
|
+
|
|
66
|
+
export function ShopLayout() {
|
|
67
|
+
return (
|
|
68
|
+
<div>
|
|
69
|
+
<nav>Shop</nav>
|
|
70
|
+
<main>
|
|
71
|
+
<Outlet /> {/* child routes render here */}
|
|
72
|
+
</main>
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
// src/document.tsx
|
|
80
|
+
"use client";
|
|
81
|
+
|
|
82
|
+
import type { ReactNode } from "react";
|
|
83
|
+
import { MetaTags, Scripts } from "@rangojs/router/client";
|
|
84
|
+
|
|
85
|
+
export function Document({ children }: { children: ReactNode }) {
|
|
86
|
+
return (
|
|
87
|
+
<html lang="en">
|
|
88
|
+
<head>
|
|
89
|
+
<MetaTags />
|
|
90
|
+
<Scripts />
|
|
91
|
+
</head>
|
|
92
|
+
<body>
|
|
93
|
+
<Scripts position="body" />
|
|
94
|
+
{children}
|
|
95
|
+
</body>
|
|
96
|
+
</html>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
(The built-in `DefaultDocument` already wires all of this — a custom document
|
|
102
|
+
is optional.)
|
|
103
|
+
|
|
104
|
+
A handler is a function of `ctx`. Typing it by route name gives typed params
|
|
105
|
+
— the Vite plugin generates the route map automatically, nothing to register:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
// src/routes/product.tsx
|
|
109
|
+
import type { Handler } from "@rangojs/router";
|
|
110
|
+
|
|
111
|
+
export const ProductPage: Handler<"product"> = (ctx) => {
|
|
112
|
+
return <h1>{ctx.params.slug}</h1>; // slug: string, from the pattern
|
|
113
|
+
};
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
And because routes have names, URLs are built, never hand-written:
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
const url = ctx.reverse("product", { slug: "espresso-cup" });
|
|
120
|
+
// "/products/espresso-cup" — name and params compile-time checked
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Rename `/products/:slug` to `/shop/:slug` in the one place it's defined and
|
|
124
|
+
every link, redirect, and prefetch follows. In client components, `href()`
|
|
125
|
+
validates static paths against the registered patterns:
|
|
126
|
+
`<Link to={href("/")}>Home</Link>`.
|
|
127
|
+
|
|
128
|
+
The tree is also lazy-first, which is the shape serverless cold starts want.
|
|
129
|
+
`include()` mounts a whole route module under a prefix — and with the async
|
|
130
|
+
form, `include("/shop", () => import("./shop"))`, the group is code-split:
|
|
131
|
+
its module doesn't load or run until a request matches it, a group nobody
|
|
132
|
+
visits never evaluates at all, and warm requests run zero route handlers.
|
|
133
|
+
Boot cost stays flat as the app grows — one module body at startup, not one
|
|
134
|
+
per group — while matching stays an `O(path length)` prefix trie, identical
|
|
135
|
+
in dev and production. None of this is assumed: the trie is benchmarked
|
|
136
|
+
in-repo against multi-thousand-route manifests, and the lazy guarantees are
|
|
137
|
+
pinned by run-count tests (see
|
|
138
|
+
[matching & lazy discovery](https://github.com/ivogt/vite-rsc/blob/main/packages/rangojs-router/docs/internal/matching-and-lazy-discovery.md)).
|
|
139
|
+
Grow the tree without watching the boot time.
|
|
140
|
+
|
|
141
|
+
That's a working site. Everything below adds to this app.
|
|
142
|
+
|
|
143
|
+
## 2. Data
|
|
144
|
+
|
|
145
|
+
The product page needs data. A handler is an async server component — fetch
|
|
146
|
+
where you render:
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
// src/routes/product.tsx
|
|
150
|
+
export const ProductPage: Handler<"product"> = async (ctx) => {
|
|
151
|
+
const product = await db.products.find(ctx.params.slug);
|
|
152
|
+
ctx.use(Meta)({ title: product.name }); // metadata where the data is
|
|
153
|
+
return <ProductView product={product} />;
|
|
154
|
+
};
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
That's the default data path. React Router and Remix split data into a
|
|
158
|
+
loader beside the component because components couldn't fetch; RSC collapses
|
|
159
|
+
the split, and Rango doesn't reintroduce it. (That `ctx.use(Meta)` line is
|
|
160
|
+
also the whole metadata story: push tags where the data already is, layouts
|
|
161
|
+
set title templates, deeper segments override — no separate metadata export,
|
|
162
|
+
no second fetch.)
|
|
163
|
+
|
|
164
|
+
Loaders enter when data needs a life of its own. First case: a **client
|
|
165
|
+
component** needs server data — the stock badge is interactive, but the
|
|
166
|
+
stock lives in the database:
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
// src/loaders/stock.ts
|
|
170
|
+
import { createLoader } from "@rangojs/router";
|
|
171
|
+
|
|
172
|
+
export const StockLoader = createLoader(async (ctx) => {
|
|
173
|
+
"use server";
|
|
174
|
+
return db.stockFor(ctx.params.slug);
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
path("/products/:slug", ProductPage, { name: "product" }, () => [
|
|
180
|
+
loader(StockLoader),
|
|
181
|
+
loading(<ProductSkeleton />),
|
|
182
|
+
]),
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
// src/components/stock-badge.tsx
|
|
187
|
+
"use client";
|
|
188
|
+
import { useLoader } from "@rangojs/router/client";
|
|
189
|
+
import { StockLoader } from "../loaders/stock";
|
|
190
|
+
|
|
191
|
+
export function StockBadge() {
|
|
192
|
+
const { data } = useLoader(StockLoader);
|
|
193
|
+
return <span>{data.inStock ? "In stock" : "Sold out"}</span>;
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Loaders run in parallel with the handler and stream; `loading()` opts the
|
|
198
|
+
segment into skeleton-then-stream. Without it, document requests arrive
|
|
199
|
+
**ready** — the HTML ships with data in place; the skeleton is a per-segment
|
|
200
|
+
choice, not the first impression.
|
|
201
|
+
|
|
202
|
+
The rule of thumb: fetch in the **handler** when the data belongs to the
|
|
203
|
+
rendered page — it will be frozen with the shell if you cache it (step 4).
|
|
204
|
+
Put data in a **loader** when it must outlive the shell: shared with client
|
|
205
|
+
components, fresh on every hit even when the segment is cached, refetchable
|
|
206
|
+
from the client, or revalidated on its own after actions.
|
|
207
|
+
|
|
208
|
+
## 3. Mutations
|
|
209
|
+
|
|
210
|
+
Users add to cart. A server action is a plain `"use server"` function; the
|
|
211
|
+
form posts to it with standard React 19 hooks — and it works without
|
|
212
|
+
JavaScript:
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
// src/actions/cart.ts
|
|
216
|
+
"use server";
|
|
217
|
+
|
|
218
|
+
export async function addToCart(productId: string) {
|
|
219
|
+
await db.cart.insert({ productId });
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
// src/components/add-to-cart.tsx
|
|
225
|
+
"use client";
|
|
226
|
+
import { useActionState } from "react";
|
|
227
|
+
import { addToCart } from "../actions/cart";
|
|
228
|
+
|
|
229
|
+
export function AddToCart({ productId }: { productId: string }) {
|
|
230
|
+
const [, action, pending] = useActionState(() => addToCart(productId), null);
|
|
231
|
+
return (
|
|
232
|
+
<form action={action}>
|
|
233
|
+
<button disabled={pending}>{pending ? "Adding…" : "Add to cart"}</button>
|
|
234
|
+
</form>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
After an action, route segments and loaders re-render by default so the UI
|
|
240
|
+
reflects the new state. `revalidate()` narrows that to the segments that
|
|
241
|
+
actually own the data — matched by action **reference**, so renames are
|
|
242
|
+
compile errors, not stale predicates:
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
import * as CartActions from "./actions/cart";
|
|
246
|
+
|
|
247
|
+
path("/cart", CartPage, { name: "cart" }, () => [
|
|
248
|
+
loader(CartLoader, () => [
|
|
249
|
+
revalidate((ctx) => ctx.isAction(CartActions) || undefined),
|
|
250
|
+
]),
|
|
251
|
+
]),
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Notice what you didn't write: no API endpoint, no fetch wrapper, and no
|
|
255
|
+
client-cache invalidation call. Actions invalidate the client-side caches
|
|
256
|
+
(history entries, prefetches, HTTP cache key) automatically — a no-op action
|
|
257
|
+
can opt out per invocation with `keepClientCache()`.
|
|
258
|
+
|
|
259
|
+
## 4. Speed
|
|
260
|
+
|
|
261
|
+
Production traffic. Wrap a segment in `cache()` and the rendered shell —
|
|
262
|
+
including everything the handler fetched — is stored, while every loader on
|
|
263
|
+
it keeps running fresh on each hit. This is where the handler-vs-loader
|
|
264
|
+
choice from step 2 pays off: handler data freezes with the shell, the
|
|
265
|
+
`StockLoader` stays live. Cached shell, live data, one line:
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
const urlpatterns = urls(({ path, layout, loader, loading, cache }) => [
|
|
269
|
+
layout(<ShopLayout />, () => [
|
|
270
|
+
path("/", HomePage, { name: "home" }),
|
|
271
|
+
cache({ ttl: 600, swr: 3600, tags: ["products"] }, () => [
|
|
272
|
+
path("/products/:slug", ProductPage, { name: "product" }, () => [
|
|
273
|
+
loader(StockLoader), // never cached: re-runs on every hit
|
|
274
|
+
loading(<ProductSkeleton />),
|
|
275
|
+
]),
|
|
276
|
+
]),
|
|
277
|
+
]),
|
|
278
|
+
]);
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Wire a store once on the router (`MemorySegmentCacheStore` for dev,
|
|
282
|
+
`CFCacheStore` for Cloudflare — see the [`/caching` skill](./skills/caching/SKILL.md)),
|
|
283
|
+
and bust by tag from the mutation that changes the data:
|
|
284
|
+
|
|
285
|
+
```tsx
|
|
286
|
+
// src/actions/products.ts
|
|
287
|
+
"use server";
|
|
288
|
+
import { updateTag } from "@rangojs/router";
|
|
289
|
+
|
|
290
|
+
export async function renameProduct(id: string, name: string) {
|
|
291
|
+
await db.products.rename(id, name);
|
|
292
|
+
await updateTag("products"); // awaitable, read-your-own-writes
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Navigation speed is a `Link` prop away:
|
|
297
|
+
|
|
298
|
+
```tsx
|
|
299
|
+
<Link to={url} prefetch="viewport">
|
|
300
|
+
{product.name}
|
|
301
|
+
</Link>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
A fully-prefetched navigation commits a **finished page** — no skeleton, no
|
|
305
|
+
loading flash — and staying correct is the router's job: every action
|
|
306
|
+
invalidates the prefetch caches by default, so a prefetched page can't show
|
|
307
|
+
pre-mutation data.
|
|
308
|
+
|
|
309
|
+
To move the shell's cost to build time entirely, `Prerender()` bakes it while
|
|
310
|
+
loaders stay live at runtime — same mental model, earlier cache write. See
|
|
311
|
+
the [`/prerender` skill](./skills/prerender/SKILL.md).
|
|
312
|
+
|
|
313
|
+
## 5. An API, when you need one
|
|
314
|
+
|
|
315
|
+
Response routes live in the same tree — `path.json()`, `path.text()`,
|
|
316
|
+
`path.xml()`, `path.image()`, `path.stream()`:
|
|
317
|
+
|
|
318
|
+
```tsx
|
|
319
|
+
path("/products/:slug", ProductPage, { name: "product" }),
|
|
320
|
+
path.json("/products/:slug", (ctx) => db.products.find(ctx.params.slug), {
|
|
321
|
+
name: "productJson",
|
|
322
|
+
}),
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Same URL: browsers get the page, API clients get JSON, negotiated by
|
|
326
|
+
`Accept` header in the route trie. Handlers return bare values; errors
|
|
327
|
+
serialize as RFC 9457 `application/problem+json`. The payload type is
|
|
328
|
+
inferred from the handler — no codegen:
|
|
329
|
+
|
|
330
|
+
```ts
|
|
331
|
+
type Product = RouteResponse<typeof urlpatterns, "productJson">;
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
See the [`/api-client` skill](./skills/api-client/SKILL.md) for a small typed
|
|
335
|
+
client over these endpoints.
|
|
336
|
+
|
|
337
|
+
## Everything else, when you need it
|
|
338
|
+
|
|
339
|
+
That was the core: `path`/`layout`/`include`, names, loaders, actions +
|
|
340
|
+
`revalidate`, `cache`, response routes. The rest is opt-in — reach for it
|
|
341
|
+
when the requirement appears:
|
|
342
|
+
|
|
343
|
+
| I need to… | Skill |
|
|
344
|
+
| ----------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
345
|
+
| guard or shape requests (auth, headers) | [`/middleware`](./skills/middleware/SKILL.md) |
|
|
346
|
+
| multi-column layouts, independent slots | [`/parallel`](./skills/parallel/SKILL.md) |
|
|
347
|
+
| open a route as a modal on soft navigation | [`/intercept`](./skills/intercept/SKILL.md) |
|
|
348
|
+
| compose route modules / sub-apps | [`/route`](./skills/route/SKILL.md), [`/composability`](./skills/composability/SKILL.md) |
|
|
349
|
+
| cache a single function or component | [`/use-cache`](./skills/use-cache/SKILL.md), [`/cache-guide`](./skills/cache-guide/SKILL.md) |
|
|
350
|
+
| feed live loaders from a cached shell | [`/shell-manifest`](./skills/shell-manifest/SKILL.md) |
|
|
351
|
+
| edge caching with Cache-Control | [`/document-cache`](./skills/document-cache/SKILL.md) |
|
|
352
|
+
| light/dark mode without FOUC | [`/theme`](./skills/theme/SKILL.md) |
|
|
353
|
+
| analytics / third-party scripts with CSP nonce | [`/scripts`](./skills/scripts/SKILL.md) |
|
|
354
|
+
| locale routing | [`/i18n`](./skills/i18n/SKILL.md) |
|
|
355
|
+
| SSE and WebSockets | [`/streams-and-websockets`](./skills/streams-and-websockets/SKILL.md) |
|
|
356
|
+
| multi-app routing by domain | [`/host-router`](./skills/host-router/SKILL.md) |
|
|
357
|
+
| animate navigations | [`/view-transitions`](./skills/view-transitions/SKILL.md) |
|
|
358
|
+
| test loaders, middleware, handlers, Flight | [`/testing`](./skills/testing/SKILL.md) |
|
|
359
|
+
| see where request time goes | [`/observability`](./skills/observability/SKILL.md) |
|
|
360
|
+
| deploy to Vercel (cache store, tracing, output) | [`/vercel`](./skills/vercel/SKILL.md) |
|
|
361
|
+
| compare Rango with Next.js / TanStack / Waku | [`/comparison`](./skills/comparison/SKILL.md) |
|
|
362
|
+
|
|
363
|
+
The [`/rango` skill](./skills/rango/SKILL.md) is the full catalog and the
|
|
364
|
+
mental model that ties it together.
|
|
365
|
+
|
|
366
|
+
## Reference
|
|
367
|
+
|
|
368
|
+
### Imports and subpaths
|
|
369
|
+
|
|
370
|
+
| Export | Description |
|
|
371
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
372
|
+
| `@rangojs/router` | Server/RSC core and shared types: `createRouter`, `urls`, `createLoader`, `Handler`, `Prerender`, `Meta` |
|
|
373
|
+
| `@rangojs/router/client` | Client: `Link`, `Outlet`, `href`, `useNavigation`, `useLoader`, `MetaTags` |
|
|
374
|
+
| `@rangojs/router/cache` | Cache: `CFCacheStore`, `VercelCacheStore`, `MemorySegmentCacheStore`, `createDocumentCacheMiddleware` |
|
|
375
|
+
| `@rangojs/router/theme` | Theme: `useTheme`, `ThemeProvider`, `ThemeScript` |
|
|
376
|
+
| `@rangojs/router/host` | Host routing: `createHostRouter`, `defineHosts`, `isNoRouteMatchError` |
|
|
377
|
+
| `@rangojs/router/vercel` | Vercel: `createVercelTracing` (phase spans via `@vercel/otel`'s global tracer) |
|
|
378
|
+
| `@rangojs/router/vite` | Vite plugin: `rango()` |
|
|
379
|
+
| `@rangojs/router/testing` | Consumer testing primitives: `runLoader`, `runMiddleware`, `dispatch` (plus `/testing/dom`, `/testing/flight`, `/testing/e2e`) |
|
|
380
|
+
| `@rangojs/router/rsc` | Advanced server pipeline APIs: `createRSCHandler`, request-context access |
|
|
381
|
+
| `@rangojs/router/ssr` | Advanced SSR bridge APIs: `createSSRHandler` |
|
|
382
|
+
|
|
383
|
+
Use only subpaths that are explicitly exported; avoid deep imports.
|
|
384
|
+
|
|
385
|
+
The root entry is conditionally resolved: server-only APIs (`createRouter`,
|
|
386
|
+
`urls`, `redirect`, `Prerender`, `cookies`) run under the `react-server`
|
|
387
|
+
condition and throw guidance errors elsewhere. If you hit a root-entrypoint
|
|
388
|
+
stub error: hooks and components (`Link`, `Outlet`, `useLoader`, `MetaTags`)
|
|
389
|
+
live in `@rangojs/router/client`; cache APIs in `@rangojs/router/cache`;
|
|
390
|
+
host APIs in `@rangojs/router/host`.
|
|
391
|
+
|
|
392
|
+
### Type safety
|
|
393
|
+
|
|
394
|
+
The Vite plugin generates `router.named-routes.gen.ts` automatically (on dev
|
|
395
|
+
startup, HMR, and builds), registering route names, params, and search
|
|
396
|
+
schemas globally via `Rango.GeneratedRouteMap`. That powers `Handler<"name">`,
|
|
397
|
+
`ctx.reverse()`, and `RouteParams<"name">` with no manual registration.
|
|
398
|
+
|
|
399
|
+
For response-aware and path-based utilities (`href()`, `Rango.Path`,
|
|
400
|
+
`RouteResponse`), augment `Rango.RegisteredRoutes` once:
|
|
401
|
+
|
|
402
|
+
```ts
|
|
403
|
+
// router.tsx
|
|
404
|
+
const router = createRouter<AppBindings>({}).routes(urlpatterns);
|
|
405
|
+
|
|
406
|
+
declare global {
|
|
407
|
+
namespace Rango {
|
|
408
|
+
interface Env extends AppEnv {}
|
|
409
|
+
interface RegisteredRoutes extends typeof router.routeMap {}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
See the [`/typesafety` skill](./skills/typesafety/SKILL.md) for the full
|
|
415
|
+
surface breakdown.
|
|
416
|
+
|
|
417
|
+
### CLI
|
|
418
|
+
|
|
419
|
+
Route types are generated by the Vite plugin; the CLI is the manual fallback
|
|
420
|
+
for CI or pre-first-run IDE support:
|
|
8
421
|
|
|
9
422
|
```bash
|
|
10
|
-
|
|
423
|
+
npx rango generate src/router.tsx # global named-route map
|
|
424
|
+
npx rango generate src/ # recursive scan
|
|
11
425
|
```
|
|
12
426
|
|
|
13
|
-
|
|
427
|
+
### Examples
|
|
428
|
+
|
|
429
|
+
- [`e2e/mini`](https://github.com/ivogt/vite-rsc/tree/main/packages/rangojs-router/e2e/mini) — single-file demo app
|
|
430
|
+
- [`cloudflare-basic`](https://github.com/ivogt/vite-rsc/tree/main/tests/cloudflare-basic) — Cloudflare Workers with caching, loaders, theme, and pre-rendering
|
|
431
|
+
- [`cloudflare-multi-router`](https://github.com/ivogt/vite-rsc/tree/main/examples/cloudflare-multi-router) — multi-app host routing
|
|
432
|
+
- [`vercel-basic`](https://github.com/ivogt/vite-rsc/tree/main/examples/vercel-basic) — Vercel deployment with `preset: "vercel"`, `VercelCacheStore`, and OTel tracing
|
|
433
|
+
- [`vercel-multi-router`](https://github.com/ivogt/vite-rsc/tree/main/examples/vercel-multi-router) — multi-app host routing on Vercel (single function, routed by Host header)
|
|
434
|
+
|
|
435
|
+
### Going deeper
|
|
14
436
|
|
|
15
|
-
|
|
437
|
+
- [Why Rango](https://github.com/ivogt/vite-rsc/blob/main/packages/rangojs-router/docs/why-rango.md) — the design rationale, claim by claim
|
|
438
|
+
- [Framework comparison](./skills/comparison/references/framework-comparison.md) — Rango vs Next.js App Router, TanStack Start, and Waku, capability by capability
|
|
439
|
+
- [Docs index](https://github.com/ivogt/vite-rsc/blob/main/packages/rangojs-router/docs/README.md) — architecture, caching, prerender, testing
|
|
440
|
+
- [Execution model](https://github.com/ivogt/vite-rsc/blob/main/packages/rangojs-router/docs/internal/execution-model.md) — the runtime contract
|
|
16
441
|
|
|
17
442
|
## License
|
|
18
443
|
|