@rangojs/router 0.0.0-experimental.19 → 0.0.0-experimental.1c0bdfad
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 +291 -61
- package/dist/bin/rango.js +544 -143
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +3744 -1329
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +67 -13
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +312 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +247 -23
- package/skills/caching/SKILL.md +322 -19
- package/skills/composability/SKILL.md +27 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +4 -2
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +282 -60
- package/skills/host-router/SKILL.md +278 -0
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +50 -6
- package/skills/layout/SKILL.md +35 -9
- package/skills/links/SKILL.md +249 -17
- package/skills/loader/SKILL.md +297 -31
- package/skills/middleware/SKILL.md +52 -13
- package/skills/migrate-nextjs/SKILL.md +584 -0
- package/skills/migrate-react-router/SKILL.md +771 -0
- package/skills/mime-routes/SKILL.md +28 -1
- package/skills/observability/SKILL.md +172 -0
- package/skills/parallel/SKILL.md +203 -7
- package/skills/prerender/SKILL.md +155 -111
- package/skills/rango/SKILL.md +251 -23
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +123 -48
- package/skills/route/SKILL.md +104 -9
- package/skills/router-setup/SKILL.md +124 -11
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +125 -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 +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +121 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +123 -0
- package/skills/typesafety/SKILL.md +357 -52
- package/skills/use-cache/SKILL.md +46 -14
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +67 -40
- package/src/bin/rango.ts +18 -0
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/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 +197 -150
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/link-interceptor.ts +4 -0
- package/src/browser/navigation-bridge.ts +200 -30
- package/src/browser/navigation-client.ts +217 -58
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +76 -67
- package/src/browser/navigation-transaction.ts +18 -66
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +187 -112
- package/src/browser/prefetch/cache.ts +312 -30
- package/src/browser/prefetch/fetch.ts +344 -47
- package/src/browser/prefetch/policy.ts +6 -0
- package/src/browser/prefetch/queue.ts +126 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +125 -18
- package/src/browser/react/NavigationProvider.tsx +135 -120
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/filter-segment-order.ts +66 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +178 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +23 -69
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +32 -7
- package/src/browser/react/use-params.ts +20 -10
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +46 -11
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +11 -21
- package/src/browser/response-adapter.ts +80 -5
- package/src/browser/rsc-router.tsx +226 -75
- package/src/browser/scroll-restoration.ts +54 -42
- package/src/browser/segment-reconciler.ts +36 -9
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +619 -442
- package/src/browser/types.ts +115 -11
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +65 -40
- package/src/build/generate-route-types.ts +7 -1
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +182 -37
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +16 -5
- package/src/build/route-types/include-resolution.ts +125 -24
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +22 -6
- package/src/build/route-types/router-processing.ts +392 -106
- package/src/build/route-types/scan-filter.ts +9 -2
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +29 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +214 -48
- package/src/cache/cache-scope.ts +236 -89
- 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 +2224 -171
- 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 +11 -17
- package/src/cache/document-cache.ts +89 -27
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +11 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +31 -31
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +9 -17
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +55 -0
- package/src/cache/types.ts +37 -100
- package/src/client.rsc.tsx +45 -21
- package/src/client.tsx +120 -336
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +109 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +84 -2
- package/src/debug.ts +2 -2
- package/src/decode-loader-results.ts +52 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +30 -4
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +70 -22
- package/src/handles/MetaTags.tsx +56 -19
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +95 -0
- package/src/handles/is-thenable.ts +19 -0
- package/src/handles/meta.ts +51 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -5
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +79 -29
- package/src/index.ts +149 -65
- package/src/internal-debug.ts +11 -10
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +63 -26
- package/src/prerender.ts +198 -82
- 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 +65 -15
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +7 -72
- package/src/route-definition/dsl-helpers.ts +469 -276
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +113 -37
- package/src/route-definition/index.ts +3 -3
- package/src/route-definition/redirect.ts +53 -12
- package/src/route-definition/resolve-handler-use.ts +161 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +7 -17
- package/src/route-types.ts +37 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +164 -17
- package/src/router/error-handling.ts +45 -18
- package/src/router/find-match.ts +45 -22
- package/src/router/handler-context.ts +110 -39
- package/src/router/instrument.ts +350 -0
- package/src/router/intercept-resolution.ts +50 -24
- package/src/router/lazy-includes.ts +19 -53
- package/src/router/loader-resolution.ts +274 -56
- package/src/router/logging.ts +5 -8
- package/src/router/manifest.ts +49 -45
- package/src/router/match-api.ts +121 -205
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +58 -58
- package/src/router/match-middleware/background-revalidation.ts +33 -6
- package/src/router/match-middleware/cache-lookup.ts +214 -263
- package/src/router/match-middleware/cache-store.ts +73 -33
- package/src/router/match-middleware/intercept-resolution.ts +8 -28
- package/src/router/match-middleware/segment-resolution.ts +52 -18
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +104 -49
- package/src/router/metrics.ts +217 -26
- package/src/router/middleware-types.ts +24 -110
- package/src/router/middleware.ts +384 -197
- package/src/router/navigation-snapshot.ts +131 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +148 -91
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prerender-match.ts +199 -56
- package/src/router/preview-match.ts +32 -102
- package/src/router/request-classification.ts +276 -0
- package/src/router/revalidation.ts +144 -74
- package/src/router/route-snapshot.ts +244 -0
- package/src/router/router-context.ts +8 -28
- package/src/router/router-interfaces.ts +129 -36
- package/src/router/router-options.ts +185 -23
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +281 -76
- package/src/router/segment-resolution/helpers.ts +116 -31
- package/src/router/segment-resolution/loader-cache.ts +63 -37
- package/src/router/segment-resolution/revalidation.ts +493 -391
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/segment-resolution.ts +5 -1
- package/src/router/segment-wrappers.ts +8 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +161 -199
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +206 -0
- package/src/router/trie-matching.ts +180 -58
- package/src/router/types.ts +10 -63
- package/src/router/url-params.ts +44 -0
- package/src/router.ts +182 -54
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +702 -460
- package/src/rsc/helpers.ts +168 -46
- package/src/rsc/index.ts +2 -25
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +127 -31
- package/src/rsc/manifest-init.ts +33 -42
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +98 -19
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +99 -189
- package/src/rsc/rsc-rendering.ts +126 -106
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +269 -114
- package/src/rsc/ssr-setup.ts +144 -0
- package/src/rsc/types.ts +34 -6
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +49 -41
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +149 -0
- package/src/segment-system.tsx +281 -129
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +317 -63
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +40 -38
- package/src/server/loader-registry.ts +26 -46
- package/src/server/request-context.ts +425 -177
- package/src/server.ts +6 -0
- package/src/ssr/index.tsx +25 -16
- package/src/static-handler.ts +27 -18
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +701 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +257 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +99 -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 +343 -0
- package/src/testing/render-route.tsx +581 -0
- package/src/testing/run-loader.ts +385 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +20 -58
- package/src/theme/ThemeScript.tsx +7 -9
- package/src/theme/constants.ts +52 -13
- package/src/theme/index.ts +3 -19
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +22 -21
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +17 -8
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +236 -88
- package/src/types/index.ts +1 -10
- package/src/types/loader-types.ts +44 -15
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +10 -45
- package/src/types/route-entry.ts +19 -7
- package/src/types/segments.ts +37 -19
- package/src/urls/include-helper.ts +33 -70
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +58 -11
- package/src/urls/path-helper.ts +57 -111
- package/src/urls/pattern-types.ts +48 -19
- package/src/urls/response-types.ts +25 -22
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -18
- package/src/use-loader.tsx +346 -89
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +64 -91
- package/src/vite/discovery/discover-routers.ts +147 -88
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +247 -145
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +61 -13
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +10 -3
- package/src/vite/inject-client-debug.ts +36 -0
- package/src/vite/plugin-types.ts +155 -65
- package/src/vite/plugins/cjs-to-esm.ts +16 -19
- package/src/vite/plugins/client-ref-dedup.ts +120 -0
- package/src/vite/plugins/client-ref-hashing.ts +28 -15
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
- package/src/vite/plugins/expose-action-id.ts +49 -98
- package/src/vite/plugins/expose-id-utils.ts +96 -51
- package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
- package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
- package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
- package/src/vite/plugins/expose-internal-ids.ts +553 -317
- 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 +73 -83
- package/src/vite/plugins/version-injector.ts +21 -25
- package/src/vite/plugins/version-plugin.ts +46 -37
- package/src/vite/plugins/virtual-entries.ts +13 -18
- package/src/vite/rango.ts +241 -287
- package/src/vite/router-discovery.ts +956 -149
- package/src/vite/utils/ast-handler-extract.ts +26 -35
- package/src/vite/utils/banner.ts +4 -4
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +20 -52
- package/src/vite/utils/prerender-utils.ts +141 -34
- package/src/vite/utils/shared-utils.ts +92 -42
- package/CLAUDE.md +0 -5
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -6
- package/src/network-error-thrower.tsx +0 -23
- package/src/route-definition/route-function.ts +0 -119
- package/src/router/middleware-cookies.ts +0 -55
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,6 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Rango
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React RSC Route Wrangler
|
|
4
|
+
|
|
5
|
+
A code-first, type-safe React Server Components router
|
|
4
6
|
|
|
5
7
|
> **Experimental:** This package is under active development. APIs may change between releases. Install with `@experimental` tag.
|
|
6
8
|
|
|
@@ -10,6 +12,7 @@ Named-route RSC router with structural composability and type-safe partial rende
|
|
|
10
12
|
- **Structural composability** — Attach routes, loaders, middleware, handles, caching, prerendering, and static generation without hiding the route tree
|
|
11
13
|
- **Composable URL patterns** — Django-style `urls()` DSL with `path`, `layout`, `include`
|
|
12
14
|
- **Data loaders** — `createLoader()` with automatic streaming and Suspense integration
|
|
15
|
+
- **Server actions** — `"use server"` mutations with `useActionState`, `useOptimistic`, and per-segment + per-loader `revalidate()` rules
|
|
13
16
|
- **Live data layer** — Pre-render or cache the UI shell while loaders stay live by default at request time
|
|
14
17
|
- **Layouts & nesting** — Nested layouts with `<Outlet />` and parallel routes
|
|
15
18
|
- **Segment-level caching** — `cache()` DSL with TTL/SWR and pluggable cache stores
|
|
@@ -45,6 +48,30 @@ For Cloudflare Workers:
|
|
|
45
48
|
npm install @cloudflare/vite-plugin
|
|
46
49
|
```
|
|
47
50
|
|
|
51
|
+
## Import Paths
|
|
52
|
+
|
|
53
|
+
Use these import paths consistently:
|
|
54
|
+
|
|
55
|
+
- `@rangojs/router` — server/RSC router APIs, route DSL, `createRouter`, `urls`, `redirect`, `Prerender`, `Static`, shared types
|
|
56
|
+
- `@rangojs/router/client` — hooks and components such as `Link`, `Outlet`, `href`, `useNavigation`, `useLoader`, `useAction`, `useLocationState`
|
|
57
|
+
- `@rangojs/router/cache` — public cache APIs such as `CFCacheStore`, `MemorySegmentCacheStore`, `createDocumentCacheMiddleware`
|
|
58
|
+
- `@rangojs/router/host`, `@rangojs/router/theme`, `@rangojs/router/vite` — specialized public subpaths
|
|
59
|
+
- `@rangojs/router/rsc`, `@rangojs/router/ssr` — advanced server-only integration subpaths for custom request/HTML pipelines
|
|
60
|
+
|
|
61
|
+
Use only subpaths that are explicitly exported from the package. Avoid deep imports such as `@rangojs/router/cache/cf`.
|
|
62
|
+
|
|
63
|
+
`@rangojs/router` is conditionally resolved. Server-only root APIs such as
|
|
64
|
+
`createRouter()`, `urls()`, `redirect()`, `Prerender()`, and `cookies()` rely on
|
|
65
|
+
the `react-server` export condition and are meant to run in router definitions,
|
|
66
|
+
handlers, and other RSC/server modules. Outside that environment the root entry
|
|
67
|
+
falls back to stub implementations that throw guidance errors.
|
|
68
|
+
|
|
69
|
+
If you hit a root-entrypoint stub error:
|
|
70
|
+
|
|
71
|
+
- hooks and components like `Link`, `Outlet`, `useLoader`, `useNavigation`, and `MetaTags` belong in `@rangojs/router/client`
|
|
72
|
+
- cache APIs like `CFCacheStore` and `createDocumentCacheMiddleware` belong in `@rangojs/router/cache`
|
|
73
|
+
- host-router APIs belong in `@rangojs/router/host`
|
|
74
|
+
|
|
48
75
|
## Quick Start
|
|
49
76
|
|
|
50
77
|
### Vite Config
|
|
@@ -62,26 +89,34 @@ export default defineConfig({
|
|
|
62
89
|
|
|
63
90
|
### Router
|
|
64
91
|
|
|
92
|
+
This file is a server/RSC module and should import router construction APIs from
|
|
93
|
+
`@rangojs/router`.
|
|
94
|
+
|
|
65
95
|
```tsx
|
|
66
96
|
// src/router.tsx
|
|
67
|
-
import { createRouter
|
|
68
|
-
import { Document } from "./document";
|
|
97
|
+
import { createRouter } from "@rangojs/router";
|
|
69
98
|
|
|
70
|
-
const
|
|
71
|
-
path("/",
|
|
72
|
-
path("
|
|
99
|
+
export const router = createRouter().routes(({ path }) => [
|
|
100
|
+
path("/", HomePage, { name: "home" }),
|
|
101
|
+
path("/about", AboutPage, { name: "about" }),
|
|
73
102
|
]);
|
|
74
103
|
|
|
104
|
+
export const reverse = router.reverse;
|
|
105
|
+
// reverse("home") -> "/"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
For larger apps, extract route modules with `urls()` and compose with `include()`:
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
import { createRouter, urls } from "@rangojs/router";
|
|
112
|
+
import { blogPatterns } from "./urls/blog";
|
|
113
|
+
|
|
75
114
|
const urlpatterns = urls(({ path, include }) => [
|
|
76
115
|
path("/", HomePage, { name: "home" }),
|
|
77
116
|
include("/blog", blogPatterns, { name: "blog" }),
|
|
78
117
|
]);
|
|
79
118
|
|
|
80
|
-
export const router = createRouter(
|
|
81
|
-
|
|
82
|
-
// Export typed reverse function for URL generation by route name
|
|
83
|
-
export const reverse = router.reverse;
|
|
84
|
-
|
|
119
|
+
export const router = createRouter().routes(urlpatterns);
|
|
85
120
|
// reverse("blog.post", { slug: "hello-world" }) -> "/blog/hello-world"
|
|
86
121
|
```
|
|
87
122
|
|
|
@@ -92,20 +127,29 @@ export const reverse = router.reverse;
|
|
|
92
127
|
"use client";
|
|
93
128
|
|
|
94
129
|
import type { ReactNode } from "react";
|
|
95
|
-
import { MetaTags } from "@rangojs/router/client";
|
|
130
|
+
import { MetaTags, Scripts } from "@rangojs/router/client";
|
|
96
131
|
|
|
97
132
|
export function Document({ children }: { children: ReactNode }) {
|
|
98
133
|
return (
|
|
99
134
|
<html lang="en">
|
|
100
135
|
<head>
|
|
101
136
|
<MetaTags />
|
|
137
|
+
<Scripts />
|
|
102
138
|
</head>
|
|
103
|
-
<body>
|
|
139
|
+
<body>
|
|
140
|
+
<Scripts position="body" />
|
|
141
|
+
{children}
|
|
142
|
+
</body>
|
|
104
143
|
</html>
|
|
105
144
|
);
|
|
106
145
|
}
|
|
107
146
|
```
|
|
108
147
|
|
|
148
|
+
`<MetaTags />` and `<Scripts />` render the tags collected by the built-in `Meta`
|
|
149
|
+
and `Script` handles (see [Meta Tags](#meta-tags) and [Scripts](#scripts)). The
|
|
150
|
+
built-in `DefaultDocument` already includes all three sites, so this is only
|
|
151
|
+
needed for a custom document.
|
|
152
|
+
|
|
109
153
|
## Defining Routes
|
|
110
154
|
|
|
111
155
|
Rango is a named-route router first.
|
|
@@ -129,13 +173,18 @@ const urlpatterns = urls(({ path }) => [
|
|
|
129
173
|
]);
|
|
130
174
|
```
|
|
131
175
|
|
|
132
|
-
Use `reverse()` as the default way to link to routes:
|
|
176
|
+
Use `ctx.reverse()` from handler context as the default way to link to routes from server code:
|
|
133
177
|
|
|
134
178
|
```tsx
|
|
135
|
-
|
|
136
|
-
|
|
179
|
+
const ProductPage: Handler<"product"> = (ctx) => {
|
|
180
|
+
const url = ctx.reverse("product", { slug: "widget" }); // "/product/widget"
|
|
181
|
+
const searchUrl = ctx.reverse("search", undefined, { q: "rsc" }); // "/search?q=rsc"
|
|
182
|
+
return <Link to={url}>Widget</Link>;
|
|
183
|
+
};
|
|
137
184
|
```
|
|
138
185
|
|
|
186
|
+
`router.reverse()` (exported from the router module) is the same function without a handler context, useful in scripts or tests. In request code, prefer `ctx.reverse()` — it auto-fills mount params from the current match.
|
|
187
|
+
|
|
139
188
|
### Composable URL Modules
|
|
140
189
|
|
|
141
190
|
Local route names compose cleanly with `include(..., { name })`:
|
|
@@ -248,7 +297,8 @@ All handler typing styles are supported, but they solve different problems:
|
|
|
248
297
|
Example of a scoped local name inside a mounted module:
|
|
249
298
|
|
|
250
299
|
```tsx
|
|
251
|
-
import type { Handler
|
|
300
|
+
import type { Handler } from "@rangojs/router";
|
|
301
|
+
import type { ScopedRouteMap } from "@rangojs/router/__internal";
|
|
252
302
|
|
|
253
303
|
type BlogRoutes = ScopedRouteMap<"blog">;
|
|
254
304
|
|
|
@@ -444,41 +494,130 @@ const urlpatterns = urls(({ path, loader }) => [
|
|
|
444
494
|
]);
|
|
445
495
|
```
|
|
446
496
|
|
|
447
|
-
##
|
|
497
|
+
## Server Actions
|
|
498
|
+
|
|
499
|
+
Server actions are React's RSC mutation primitive. Define them with the
|
|
500
|
+
`"use server"` directive — Rango uses standard React 19 hooks
|
|
501
|
+
(`useActionState`, `useFormStatus`, `useOptimistic`) with no framework wrapper.
|
|
502
|
+
|
|
503
|
+
```tsx
|
|
504
|
+
// app/actions/cart.ts
|
|
505
|
+
"use server";
|
|
448
506
|
|
|
449
|
-
|
|
507
|
+
import { getRequestContext } from "@rangojs/router";
|
|
450
508
|
|
|
451
|
-
|
|
509
|
+
export async function addToCart(productId: string): Promise<void> {
|
|
510
|
+
const ctx = getRequestContext();
|
|
511
|
+
const userId = ctx.get("user").id;
|
|
512
|
+
await db.cart.insert({ userId, productId });
|
|
513
|
+
}
|
|
514
|
+
```
|
|
452
515
|
|
|
453
516
|
```tsx
|
|
454
|
-
|
|
455
|
-
|
|
517
|
+
// Client form with progressive enhancement + pending state
|
|
518
|
+
"use client";
|
|
519
|
+
import { useActionState } from "react";
|
|
520
|
+
import { saveProfile } from "../actions/profile";
|
|
456
521
|
|
|
457
|
-
function
|
|
522
|
+
export function ProfileForm() {
|
|
523
|
+
const [state, action, pending] = useActionState(saveProfile, null);
|
|
458
524
|
return (
|
|
459
|
-
<
|
|
460
|
-
<
|
|
461
|
-
<
|
|
462
|
-
<
|
|
463
|
-
</
|
|
525
|
+
<form action={action}>
|
|
526
|
+
<input name="name" defaultValue={state?.values?.name} />
|
|
527
|
+
{state?.errors?.name && <p role="alert">{state.errors.name}</p>}
|
|
528
|
+
<button disabled={pending}>{pending ? "Saving…" : "Save"}</button>
|
|
529
|
+
</form>
|
|
464
530
|
);
|
|
465
531
|
}
|
|
466
532
|
```
|
|
467
533
|
|
|
468
|
-
|
|
534
|
+
After an action runs, matched route segments (path/layout/parallel/intercept)
|
|
535
|
+
and loaders can re-render/re-resolve so the UI reflects the new state.
|
|
536
|
+
Attach a `revalidate(({ actionId }) => ...)` rule on any segment or loader
|
|
537
|
+
that owns data the action touched:
|
|
469
538
|
|
|
470
|
-
|
|
539
|
+
```tsx
|
|
540
|
+
urls(({ path, loader, revalidate }) => [
|
|
541
|
+
// Segment-level: re-render the cart page handler after cart actions.
|
|
542
|
+
// Nest loaders that belong to this route inside the same path() so the
|
|
543
|
+
// segment owns its data dependencies.
|
|
544
|
+
path("/cart", CartPage, { name: "cart" }, () => [
|
|
545
|
+
revalidate(
|
|
546
|
+
({ actionId }) => actionId?.startsWith("src/actions/cart.ts#") ?? false,
|
|
547
|
+
),
|
|
548
|
+
loader(CartLoader, () => [
|
|
549
|
+
revalidate(
|
|
550
|
+
({ actionId }) => actionId?.startsWith("src/actions/cart.ts#") ?? false,
|
|
551
|
+
),
|
|
552
|
+
]),
|
|
553
|
+
]),
|
|
554
|
+
]);
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
For the full guide — validation with Zod, error handling, file uploads,
|
|
558
|
+
`useOptimistic`, redirects, and progressive enhancement — see the
|
|
559
|
+
`/server-actions` skill.
|
|
560
|
+
|
|
561
|
+
## Navigation & Links
|
|
562
|
+
|
|
563
|
+
### Named Routes with `ctx.reverse()` (Server)
|
|
564
|
+
|
|
565
|
+
In server components and handlers, use `ctx.reverse()` to generate URLs by route name. This is the default — it is typed, auto-fills mount params from the current match, and resolves both local (`.name`) and absolute (`name.sub`) names:
|
|
471
566
|
|
|
472
567
|
```tsx
|
|
568
|
+
import { Link } from "@rangojs/router/client";
|
|
569
|
+
import type { Handler } from "@rangojs/router";
|
|
570
|
+
|
|
473
571
|
const BlogPostPage: Handler<"blogPost"> = (ctx) => {
|
|
474
572
|
const backUrl = ctx.reverse("blog");
|
|
475
573
|
return <Link to={backUrl}>Back to blog</Link>;
|
|
476
574
|
};
|
|
477
575
|
```
|
|
478
576
|
|
|
577
|
+
`reverse()` is type-safe — route names and required params are checked at compile time. Included routes use dotted names: `ctx.reverse("api.health")`.
|
|
578
|
+
|
|
579
|
+
For scripts, tests, or other code without a handler context, import the router-level `reverse`:
|
|
580
|
+
|
|
581
|
+
```tsx
|
|
582
|
+
import { reverse } from "./router";
|
|
583
|
+
reverse("blogPost", { slug: "my-post" });
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
### Client Components
|
|
587
|
+
|
|
588
|
+
**`reverse()` is server-only.** It depends on the route manifest and handler context — neither is available in the browser bundle. Client components receive URLs as props, loader data, or server-action return values:
|
|
589
|
+
|
|
590
|
+
```tsx
|
|
591
|
+
// server
|
|
592
|
+
function BlogIndex(ctx: HandlerContext) {
|
|
593
|
+
return (
|
|
594
|
+
<Nav
|
|
595
|
+
home={ctx.reverse("home")}
|
|
596
|
+
post={ctx.reverse("blogPost", { slug: "my-post" })}
|
|
597
|
+
/>
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
```tsx
|
|
603
|
+
"use client";
|
|
604
|
+
import { Link } from "@rangojs/router/client";
|
|
605
|
+
|
|
606
|
+
export function Nav({ home, post }: { home: string; post: string }) {
|
|
607
|
+
return (
|
|
608
|
+
<nav>
|
|
609
|
+
<Link to={home}>Home</Link>
|
|
610
|
+
<Link to={post}>My Post</Link>
|
|
611
|
+
</nav>
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
For client-side navigation to static paths (no named-route lookup), use `href()` — see below. For URLs tied to named routes, you have two options: import the per-module generated `routes` map and use `useReverse(routes)` for in-module names (see [`/links` skill](./skills/links/SKILL.md)), or generate the URL on the server and pass the string in for cross-module URLs.
|
|
617
|
+
|
|
479
618
|
### `href()` for Path Validation (Client Components)
|
|
480
619
|
|
|
481
|
-
In client components, use `href()` for compile-time path validation:
|
|
620
|
+
In client components, use `href()` for compile-time path validation on static path strings:
|
|
482
621
|
|
|
483
622
|
```tsx
|
|
484
623
|
"use client";
|
|
@@ -488,7 +627,7 @@ function Nav() {
|
|
|
488
627
|
return (
|
|
489
628
|
<nav>
|
|
490
629
|
<Link to={href("/")}>Home</Link>
|
|
491
|
-
<Link to={href("/blog")} prefetch="
|
|
630
|
+
<Link to={href("/blog")} prefetch="adaptive">
|
|
492
631
|
Blog
|
|
493
632
|
</Link>
|
|
494
633
|
<Link to={href("/about")}>About</Link>
|
|
@@ -683,10 +822,12 @@ export const BlogPost = Prerender(
|
|
|
683
822
|
|
|
684
823
|
### Passthrough for Unknown Params
|
|
685
824
|
|
|
825
|
+
Wrap a `Prerender` definition with `Passthrough()` to add a live handler for unknown params at runtime. The build handler runs at build time, the live handler runs at request time for params not in the prerender cache.
|
|
826
|
+
|
|
686
827
|
```tsx
|
|
687
|
-
import { Prerender } from "@rangojs/router";
|
|
828
|
+
import { Prerender, Passthrough } from "@rangojs/router";
|
|
688
829
|
|
|
689
|
-
export const
|
|
830
|
+
export const ProductPageDef = Prerender(
|
|
690
831
|
async () => {
|
|
691
832
|
const featured = await db.getFeaturedProducts();
|
|
692
833
|
return featured.map((p) => ({ id: p.id }));
|
|
@@ -695,16 +836,22 @@ export const ProductPage = Prerender(
|
|
|
695
836
|
const product = await db.getProduct(ctx.params.id);
|
|
696
837
|
return <Product data={product} />;
|
|
697
838
|
},
|
|
698
|
-
{ passthrough: true },
|
|
699
839
|
);
|
|
700
|
-
```
|
|
701
840
|
|
|
702
|
-
|
|
841
|
+
// In route definition:
|
|
842
|
+
path(
|
|
843
|
+
"/products/:id",
|
|
844
|
+
Passthrough(ProductPageDef, async (ctx) => {
|
|
845
|
+
const product = await ctx.env.DB.getProduct(ctx.params.id);
|
|
846
|
+
return <Product data={product} />;
|
|
847
|
+
}),
|
|
848
|
+
);
|
|
849
|
+
```
|
|
703
850
|
|
|
704
|
-
|
|
851
|
+
Build handlers can also skip individual param sets with `ctx.passthrough()`, deferring them to the live handler:
|
|
705
852
|
|
|
706
853
|
```tsx
|
|
707
|
-
export const
|
|
854
|
+
export const ProductPageDef = Prerender(
|
|
708
855
|
async () => {
|
|
709
856
|
const all = await db.getAllProducts();
|
|
710
857
|
return all.map((p) => ({ id: p.id }));
|
|
@@ -714,10 +861,55 @@ export const ProductPage = Prerender(
|
|
|
714
861
|
if (!product.published) return ctx.passthrough();
|
|
715
862
|
return <Product data={product} />;
|
|
716
863
|
},
|
|
717
|
-
{ passthrough: true },
|
|
718
864
|
);
|
|
719
865
|
```
|
|
720
866
|
|
|
867
|
+
### Build-Time Environment Bindings
|
|
868
|
+
|
|
869
|
+
Prerender handlers can access platform bindings (KV, D1, R2) at build time when `buildEnv` is configured in the Vite plugin:
|
|
870
|
+
|
|
871
|
+
```ts
|
|
872
|
+
// vite.config.ts
|
|
873
|
+
import { rango } from "@rangojs/router/vite";
|
|
874
|
+
|
|
875
|
+
rango({ preset: "cloudflare", buildEnv: "auto" });
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
With `buildEnv: "auto"`, the plugin calls `wrangler.getPlatformProxy()` to provide local bindings. Handlers then access `ctx.env` during build:
|
|
879
|
+
|
|
880
|
+
```tsx
|
|
881
|
+
export const BlogPosts = Prerender<{ slug: string }>(
|
|
882
|
+
async (ctx) => {
|
|
883
|
+
const rows = await ctx.env.DB.prepare("SELECT slug FROM posts").all();
|
|
884
|
+
return rows.map((r) => ({ slug: r.slug }));
|
|
885
|
+
},
|
|
886
|
+
async (ctx) => {
|
|
887
|
+
const post = await ctx.env.DB.prepare("SELECT * FROM posts WHERE slug = ?")
|
|
888
|
+
.bind(ctx.params.slug)
|
|
889
|
+
.first();
|
|
890
|
+
return <BlogPost post={post} />;
|
|
891
|
+
},
|
|
892
|
+
);
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
`buildEnv` also accepts a factory function or plain object:
|
|
896
|
+
|
|
897
|
+
```ts
|
|
898
|
+
// Custom factory
|
|
899
|
+
rango({
|
|
900
|
+
buildEnv: async (ctx) => {
|
|
901
|
+
const { getPlatformProxy } = await import("wrangler");
|
|
902
|
+
const proxy = await getPlatformProxy();
|
|
903
|
+
return { env: proxy.env, dispose: proxy.dispose };
|
|
904
|
+
},
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
// Plain object (Node.js)
|
|
908
|
+
rango({ buildEnv: { DATABASE_URL: process.env.DATABASE_URL } });
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
Build-time env applies to both production builds and dev on-demand prerender. Without `buildEnv`, accessing `ctx.env` in a Prerender handler throws with a clear error.
|
|
912
|
+
|
|
721
913
|
## Theme
|
|
722
914
|
|
|
723
915
|
### Router Configuration
|
|
@@ -762,9 +954,9 @@ import { createHostRouter } from "@rangojs/router/host";
|
|
|
762
954
|
|
|
763
955
|
const hostRouter = createHostRouter();
|
|
764
956
|
|
|
765
|
-
hostRouter.host(["*.localhost"]).
|
|
766
|
-
hostRouter.host(["localhost"]).
|
|
767
|
-
hostRouter.fallback().
|
|
957
|
+
hostRouter.host(["*.localhost"]).lazy(() => import("./apps/admin/handler.js"));
|
|
958
|
+
hostRouter.host(["localhost"]).lazy(() => import("./apps/site/handler.js"));
|
|
959
|
+
hostRouter.fallback().lazy(() => import("./apps/site/handler.js"));
|
|
768
960
|
|
|
769
961
|
export default {
|
|
770
962
|
async fetch(request, env, ctx) {
|
|
@@ -773,7 +965,7 @@ export default {
|
|
|
773
965
|
};
|
|
774
966
|
```
|
|
775
967
|
|
|
776
|
-
|
|
968
|
+
Use `.lazy(() => import("./sub-app"))` to mount a lazily-imported sub-app (a module whose `default` export is a handler or nested host router), and `.map((request) => Response)` for an inline request handler. Only `.lazy()` mounts are imported during build-time discovery; `.map(() => import(...))` is a type error. Each sub-app has its own `createRouter()` and `urls()`. Patterns are matched in registration order — register more specific patterns (subdomains) before catch-alls.
|
|
777
969
|
|
|
778
970
|
## Meta Tags
|
|
779
971
|
|
|
@@ -795,6 +987,38 @@ export function BlogPostPage(ctx: HandlerContext) {
|
|
|
795
987
|
|
|
796
988
|
Render collected tags in the document with `<MetaTags />` from `@rangojs/router/client`.
|
|
797
989
|
|
|
990
|
+
## Scripts
|
|
991
|
+
|
|
992
|
+
Inject `<script>` tags (analytics, GTM, widgets) the same way, using the built-in
|
|
993
|
+
`Script` handle — push a config from a handler, render with `<Scripts />`:
|
|
994
|
+
|
|
995
|
+
```tsx
|
|
996
|
+
import { Script } from "@rangojs/router";
|
|
997
|
+
import type { HandlerContext } from "@rangojs/router";
|
|
998
|
+
import { Outlet } from "@rangojs/router/client";
|
|
999
|
+
|
|
1000
|
+
export function RootLayout(ctx: HandlerContext) {
|
|
1001
|
+
// Inline bootstrap (GTM/GA4/Segment) — rendered with the request CSP nonce.
|
|
1002
|
+
ctx.use(Script)({ id: "gtm", children: gtmBootstrap("GTM-XXXX") });
|
|
1003
|
+
// External async resource (loads on first encounter, deduped by src).
|
|
1004
|
+
ctx.use(Script)({
|
|
1005
|
+
id: "plausible",
|
|
1006
|
+
src: "https://plausible.io/js/script.js",
|
|
1007
|
+
async: true,
|
|
1008
|
+
attributes: { "data-domain": "example.com" },
|
|
1009
|
+
});
|
|
1010
|
+
return <Outlet />;
|
|
1011
|
+
}
|
|
1012
|
+
```
|
|
1013
|
+
|
|
1014
|
+
Render with `<Scripts />` (head) and `<Scripts position="body" />` (body) from
|
|
1015
|
+
`@rangojs/router/client` (both are wired in `DefaultDocument`). The request CSP
|
|
1016
|
+
nonce is applied automatically to document-rendered scripts. `ScriptConfig` is a
|
|
1017
|
+
discriminated union (inline / external-async / external-ordered), and inline +
|
|
1018
|
+
ordered scripts are document-load while async externals are React resources — see
|
|
1019
|
+
the [`/scripts` skill](./skills/scripts/SKILL.md) for the full execution contract
|
|
1020
|
+
and CSP guidance.
|
|
1021
|
+
|
|
798
1022
|
## CLI: `rango generate`
|
|
799
1023
|
|
|
800
1024
|
Route types are generated automatically by the Vite plugin. The CLI is a manual fallback for generating types outside the dev server (e.g. in CI or for IDE support before first `pnpm dev`):
|
|
@@ -812,16 +1036,16 @@ Auto-detects file type:
|
|
|
812
1036
|
|
|
813
1037
|
## Type Safety
|
|
814
1038
|
|
|
815
|
-
The Vite plugin automatically generates a `router.named-routes.gen.ts` file that globally registers route names, patterns, and search schemas via `
|
|
1039
|
+
The Vite plugin automatically generates a `router.named-routes.gen.ts` file that globally registers route names, patterns, and search schemas via `Rango.GeneratedRouteMap`. This powers server-side named-route typing such as `Handler<"name">`, `ctx.reverse()`, `getRequestContext().reverse()`, and `RouteParams<"name">` without any manual route registration. The gen file is updated on dev server startup, HMR, and production builds.
|
|
816
1040
|
|
|
817
|
-
Use the generated map by default. Augment `
|
|
1041
|
+
Use the generated map by default. Augment `Rango.RegisteredRoutes` only when you need the richer `typeof router.routeMap` shape globally, especially for response-aware and path-based utilities.
|
|
818
1042
|
|
|
819
1043
|
```typescript
|
|
820
1044
|
// router.tsx
|
|
821
1045
|
const router = createRouter<AppBindings>({}).routes(urlpatterns);
|
|
822
1046
|
|
|
823
1047
|
declare global {
|
|
824
|
-
namespace
|
|
1048
|
+
namespace Rango {
|
|
825
1049
|
interface Env extends AppEnv {}
|
|
826
1050
|
interface Vars extends AppVars {}
|
|
827
1051
|
interface RegisteredRoutes extends typeof router.routeMap {}
|
|
@@ -833,7 +1057,7 @@ Quick rule of thumb:
|
|
|
833
1057
|
|
|
834
1058
|
- `GeneratedRouteMap` (auto-generated) — use for server-side named-route typing: `Handler<"name">`, `ctx.reverse()`, `Prerender<"name">`
|
|
835
1059
|
- `typeof router.routeMap` — use when you need route entries with response metadata
|
|
836
|
-
- `RegisteredRoutes` (manual augmentation) — use to expose `typeof router.routeMap` globally for `href()`, `
|
|
1060
|
+
- `RegisteredRoutes` (manual augmentation) — use to expose `typeof router.routeMap` globally for `href()`, `Rango.Path`, `Rango.PathResponse`, and other path/response-aware utilities
|
|
837
1061
|
|
|
838
1062
|
For extracted reusable loaders or middleware, prefer global dotted names on
|
|
839
1063
|
`ctx.reverse()` by default. If you want type-safe local names for a specific
|
|
@@ -842,22 +1066,28 @@ module, use `scopedReverse<typeof localPatterns>(ctx.reverse)` or
|
|
|
842
1066
|
|
|
843
1067
|
## Subpath Exports
|
|
844
1068
|
|
|
845
|
-
| Export | Description
|
|
846
|
-
| ------------------------ |
|
|
847
|
-
| `@rangojs/router` |
|
|
848
|
-
| `@rangojs/router/client` | Client: `Link`, `Outlet`, `href`, `useNavigation`, `useLoader`, `MetaTags`
|
|
849
|
-
| `@rangojs/router/cache` | Cache: `CFCacheStore`, `MemorySegmentCacheStore`, `createDocumentCacheMiddleware`
|
|
850
|
-
| `@rangojs/router/theme` | Theme: `useTheme`, `ThemeProvider`, `ThemeScript`
|
|
851
|
-
| `@rangojs/router/host` | Host routing: `createHostRouter`, `defineHosts`
|
|
852
|
-
| `@rangojs/router/vite` | Vite plugin: `rango()`
|
|
853
|
-
| `@rangojs/router/server`
|
|
854
|
-
| `@rangojs/router/
|
|
1069
|
+
| Export | Description |
|
|
1070
|
+
| ------------------------ | -------------------------------------------------------------------------------------------------------- |
|
|
1071
|
+
| `@rangojs/router` | Server/RSC core and shared types: `createRouter`, `urls`, `createLoader`, `Handler`, `Prerender`, `Meta` |
|
|
1072
|
+
| `@rangojs/router/client` | Client: `Link`, `Outlet`, `href`, `useNavigation`, `useLoader`, `MetaTags` |
|
|
1073
|
+
| `@rangojs/router/cache` | Cache: `CFCacheStore`, `MemorySegmentCacheStore`, `createDocumentCacheMiddleware` |
|
|
1074
|
+
| `@rangojs/router/theme` | Theme: `useTheme`, `ThemeProvider`, `ThemeScript` |
|
|
1075
|
+
| `@rangojs/router/host` | Host routing: `createHostRouter`, `defineHosts` |
|
|
1076
|
+
| `@rangojs/router/vite` | Vite plugin: `rango()` |
|
|
1077
|
+
| `@rangojs/router/rsc` | Advanced server pipeline APIs: `createRSCHandler`, request-context access |
|
|
1078
|
+
| `@rangojs/router/ssr` | Advanced SSR bridge APIs: `createSSRHandler` |
|
|
1079
|
+
| `@rangojs/router/server` | Internal build/runtime utilities for advanced integrations |
|
|
1080
|
+
| `@rangojs/router/build` | Build utilities |
|
|
1081
|
+
|
|
1082
|
+
The root entrypoint is not a generic client/runtime barrel. If you need hooks
|
|
1083
|
+
or components, import from `@rangojs/router/client`; if you need cache or host
|
|
1084
|
+
APIs, use their dedicated subpaths.
|
|
855
1085
|
|
|
856
1086
|
## Examples
|
|
857
1087
|
|
|
858
|
-
See the
|
|
1088
|
+
See the example and demo apps for full working applications:
|
|
859
1089
|
|
|
860
|
-
- [`cloudflare-basic`](../../
|
|
1090
|
+
- [`cloudflare-basic`](../../tests/cloudflare-basic) — Cloudflare Workers with caching, loaders, theme, and pre-rendering
|
|
861
1091
|
- [`cloudflare-multi-router`](../../examples/cloudflare-multi-router) — Multi-app host routing
|
|
862
1092
|
|
|
863
1093
|
## License
|