@rangojs/router 0.0.0-experimental.eb0645d3 → 0.0.0-experimental.f1468e3c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -0
- package/README.md +126 -16
- package/dist/bin/rango.js +319 -95
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +2724 -1053
- package/package.json +68 -14
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +64 -2
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +224 -32
- package/skills/caching/SKILL.md +279 -17
- package/skills/composability/SKILL.md +27 -3
- 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 +11 -9
- package/skills/hooks/SKILL.md +243 -29
- package/skills/host-router/SKILL.md +83 -23
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +68 -19
- package/skills/layout/SKILL.md +13 -9
- package/skills/links/SKILL.md +190 -23
- package/skills/loader/SKILL.md +235 -9
- package/skills/middleware/SKILL.md +18 -10
- package/skills/migrate-nextjs/SKILL.md +43 -19
- package/skills/migrate-react-router/SKILL.md +8 -2
- package/skills/mime-routes/SKILL.md +28 -1
- package/skills/observability/SKILL.md +172 -0
- package/skills/parallel/SKILL.md +18 -7
- package/skills/prerender/SKILL.md +65 -60
- package/skills/rango/SKILL.md +251 -24
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +115 -48
- package/skills/route/SKILL.md +46 -5
- package/skills/router-setup/SKILL.md +30 -8
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +130 -0
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -0
- package/skills/testing/handles.md +129 -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 +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 +322 -29
- package/skills/use-cache/SKILL.md +57 -14
- package/skills/view-transitions/SKILL.md +337 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +192 -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/navigation-bridge.ts +94 -25
- package/src/browser/navigation-client.ts +121 -84
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +115 -67
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +147 -128
- package/src/browser/prefetch/cache.ts +107 -56
- package/src/browser/prefetch/fetch.ts +204 -34
- package/src/browser/prefetch/queue.ts +6 -3
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +30 -7
- package/src/browser/react/NavigationProvider.tsx +283 -118
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/deferred-handle-resolution.ts +75 -0
- package/src/browser/react/filter-segment-order.ts +66 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +178 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +17 -14
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +10 -5
- package/src/browser/react/use-params.ts +11 -11
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +25 -3
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +11 -21
- package/src/browser/response-adapter.ts +99 -8
- package/src/browser/rsc-router.tsx +91 -24
- package/src/browser/scroll-restoration.ts +30 -17
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +214 -55
- package/src/browser/types.ts +80 -9
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +60 -35
- package/src/build/generate-route-types.ts +2 -1
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +117 -14
- 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 +117 -23
- 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 +55 -28
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +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 +224 -41
- package/src/cache/cache-scope.ts +188 -82
- 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 +1989 -378
- package/src/cache/cf/cf-cache-types.ts +349 -0
- package/src/cache/cf/cf-kv-utils.ts +46 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +89 -21
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +10 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +46 -31
- package/src/cache/read-through-swr.ts +56 -12
- package/src/cache/segment-codec.ts +9 -17
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +37 -100
- package/src/client.rsc.tsx +44 -21
- package/src/client.tsx +36 -61
- 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 +18 -6
- 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 +31 -23
- package/src/handles/MetaTags.tsx +62 -19
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +37 -8
- 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 -2
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +96 -12
- package/src/index.ts +94 -14
- package/src/internal-debug.ts +11 -10
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +61 -6
- 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 +34 -0
- package/src/reverse.ts +65 -40
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +19 -77
- package/src/route-definition/dsl-helpers.ts +304 -309
- package/src/route-definition/helper-factories.ts +28 -140
- package/src/route-definition/helpers-types.ts +82 -55
- package/src/route-definition/index.ts +1 -2
- package/src/route-definition/redirect.ts +44 -11
- package/src/route-definition/resolve-handler-use.ts +12 -1
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-map-builder.ts +0 -16
- package/src/route-types.ts +19 -46
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +73 -25
- package/src/router/error-handling.ts +45 -18
- package/src/router/find-match.ts +44 -23
- package/src/router/handler-context.ts +27 -43
- package/src/router/instrument.ts +350 -0
- package/src/router/intercept-resolution.ts +39 -20
- package/src/router/lazy-includes.ts +10 -47
- package/src/router/loader-resolution.ts +155 -72
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +18 -29
- package/src/router/match-api.ts +9 -24
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +58 -58
- package/src/router/match-middleware/background-revalidation.ts +40 -24
- package/src/router/match-middleware/cache-lookup.ts +159 -285
- package/src/router/match-middleware/cache-store.ts +64 -52
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +44 -74
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +7 -134
- package/src/router/middleware.ts +247 -166
- package/src/router/navigation-snapshot.ts +0 -51
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +85 -94
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prerender-match.ts +104 -65
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +28 -62
- package/src/router/revalidation.ts +123 -73
- package/src/router/route-snapshot.ts +0 -1
- package/src/router/router-context.ts +3 -28
- package/src/router/router-interfaces.ts +83 -35
- package/src/router/router-options.ts +136 -5
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +97 -84
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +76 -39
- package/src/router/segment-resolution/revalidation.ts +272 -320
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +56 -0
- package/src/router/segment-resolution.ts +5 -1
- package/src/router/segment-wrappers.ts +6 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +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 +162 -64
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +0 -5
- package/src/router.ts +110 -55
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +264 -220
- package/src/rsc/helpers.ts +100 -6
- package/src/rsc/index.ts +2 -5
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +114 -38
- package/src/rsc/manifest-init.ts +28 -41
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +117 -11
- 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 +88 -188
- package/src/rsc/rsc-rendering.ts +98 -76
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +281 -117
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +23 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +35 -30
- package/src/segment-loader-promise.ts +31 -4
- package/src/segment-system.tsx +254 -143
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +163 -51
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +21 -38
- package/src/server/loader-registry.ts +33 -42
- package/src/server/request-context.ts +287 -178
- package/src/ssr/index.tsx +21 -16
- package/src/static-handler.ts +10 -13
- 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 +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 +581 -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 +20 -58
- package/src/theme/ThemeScript.tsx +7 -9
- package/src/theme/constants.ts +52 -13
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +22 -21
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +110 -62
- package/src/types/index.ts +3 -10
- package/src/types/loader-types.ts +11 -9
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +135 -14
- package/src/urls/include-helper.ts +9 -56
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +29 -12
- package/src/urls/path-helper.ts +17 -106
- package/src/urls/pattern-types.ts +36 -19
- package/src/urls/response-types.ts +22 -29
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -19
- package/src/use-loader.tsx +292 -107
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +8 -7
- package/src/vite/discovery/discover-routers.ts +126 -85
- 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 +96 -68
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +44 -0
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +2 -0
- package/src/vite/inject-client-debug.ts +36 -0
- package/src/vite/plugin-types.ts +126 -8
- package/src/vite/plugins/cjs-to-esm.ts +16 -19
- package/src/vite/plugins/client-ref-dedup.ts +16 -11
- package/src/vite/plugins/client-ref-hashing.ts +28 -15
- package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -21
- package/src/vite/plugins/expose-action-id.ts +48 -95
- package/src/vite/plugins/expose-id-utils.ts +88 -55
- package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +11 -90
- package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
- package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
- package/src/vite/plugins/expose-internal-ids.ts +505 -486
- package/src/vite/plugins/performance-tracks.ts +26 -25
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +73 -83
- package/src/vite/plugins/version-injector.ts +40 -29
- package/src/vite/plugins/version-plugin.ts +37 -40
- package/src/vite/plugins/virtual-entries.ts +39 -25
- package/src/vite/rango.ts +109 -118
- package/src/vite/router-discovery.ts +718 -119
- package/src/vite/utils/ast-handler-extract.ts +26 -35
- package/src/vite/utils/banner.ts +1 -1
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +20 -52
- package/src/vite/utils/prerender-utils.ts +54 -39
- package/src/vite/utils/shared-utils.ts +90 -41
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/network-error-thrower.tsx +0 -23
- package/src/router/middleware-cookies.ts +0 -55
package/AGENTS.md
CHANGED
|
@@ -7,3 +7,11 @@ Run `/rango` to understand the API. Detailed guides for each feature are in the
|
|
|
7
7
|
## Development rules
|
|
8
8
|
|
|
9
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
|
|
@@ -124,20 +127,29 @@ export const router = createRouter().routes(urlpatterns);
|
|
|
124
127
|
"use client";
|
|
125
128
|
|
|
126
129
|
import type { ReactNode } from "react";
|
|
127
|
-
import { MetaTags } from "@rangojs/router/client";
|
|
130
|
+
import { MetaTags, Scripts } from "@rangojs/router/client";
|
|
128
131
|
|
|
129
132
|
export function Document({ children }: { children: ReactNode }) {
|
|
130
133
|
return (
|
|
131
134
|
<html lang="en">
|
|
132
135
|
<head>
|
|
133
136
|
<MetaTags />
|
|
137
|
+
<Scripts />
|
|
134
138
|
</head>
|
|
135
|
-
<body>
|
|
139
|
+
<body>
|
|
140
|
+
<Scripts position="body" />
|
|
141
|
+
{children}
|
|
142
|
+
</body>
|
|
136
143
|
</html>
|
|
137
144
|
);
|
|
138
145
|
}
|
|
139
146
|
```
|
|
140
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
|
+
|
|
141
153
|
## Defining Routes
|
|
142
154
|
|
|
143
155
|
Rango is a named-route router first.
|
|
@@ -482,6 +494,70 @@ const urlpatterns = urls(({ path, loader }) => [
|
|
|
482
494
|
]);
|
|
483
495
|
```
|
|
484
496
|
|
|
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";
|
|
506
|
+
|
|
507
|
+
import { getRequestContext } from "@rangojs/router";
|
|
508
|
+
|
|
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
|
+
```
|
|
515
|
+
|
|
516
|
+
```tsx
|
|
517
|
+
// Client form with progressive enhancement + pending state
|
|
518
|
+
"use client";
|
|
519
|
+
import { useActionState } from "react";
|
|
520
|
+
import { saveProfile } from "../actions/profile";
|
|
521
|
+
|
|
522
|
+
export function ProfileForm() {
|
|
523
|
+
const [state, action, pending] = useActionState(saveProfile, null);
|
|
524
|
+
return (
|
|
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>
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
```
|
|
533
|
+
|
|
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:
|
|
538
|
+
|
|
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
|
+
|
|
485
561
|
## Navigation & Links
|
|
486
562
|
|
|
487
563
|
### Named Routes with `ctx.reverse()` (Server)
|
|
@@ -521,10 +597,12 @@ function BlogIndex(ctx: HandlerContext) {
|
|
|
521
597
|
/>
|
|
522
598
|
);
|
|
523
599
|
}
|
|
600
|
+
```
|
|
524
601
|
|
|
525
|
-
|
|
602
|
+
```tsx
|
|
526
603
|
"use client";
|
|
527
604
|
import { Link } from "@rangojs/router/client";
|
|
605
|
+
|
|
528
606
|
export function Nav({ home, post }: { home: string; post: string }) {
|
|
529
607
|
return (
|
|
530
608
|
<nav>
|
|
@@ -535,7 +613,7 @@ export function Nav({ home, post }: { home: string; post: string }) {
|
|
|
535
613
|
}
|
|
536
614
|
```
|
|
537
615
|
|
|
538
|
-
For client-side navigation to static paths (no named-route lookup), use `href()` — see below. For URLs tied to named routes,
|
|
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.
|
|
539
617
|
|
|
540
618
|
### `href()` for Path Validation (Client Components)
|
|
541
619
|
|
|
@@ -876,9 +954,9 @@ import { createHostRouter } from "@rangojs/router/host";
|
|
|
876
954
|
|
|
877
955
|
const hostRouter = createHostRouter();
|
|
878
956
|
|
|
879
|
-
hostRouter.host(["*.localhost"]).
|
|
880
|
-
hostRouter.host(["localhost"]).
|
|
881
|
-
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"));
|
|
882
960
|
|
|
883
961
|
export default {
|
|
884
962
|
async fetch(request, env, ctx) {
|
|
@@ -887,7 +965,7 @@ export default {
|
|
|
887
965
|
};
|
|
888
966
|
```
|
|
889
967
|
|
|
890
|
-
|
|
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.
|
|
891
969
|
|
|
892
970
|
## Meta Tags
|
|
893
971
|
|
|
@@ -909,6 +987,38 @@ export function BlogPostPage(ctx: HandlerContext) {
|
|
|
909
987
|
|
|
910
988
|
Render collected tags in the document with `<MetaTags />` from `@rangojs/router/client`.
|
|
911
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
|
+
|
|
912
1022
|
## CLI: `rango generate`
|
|
913
1023
|
|
|
914
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`):
|
|
@@ -926,16 +1036,16 @@ Auto-detects file type:
|
|
|
926
1036
|
|
|
927
1037
|
## Type Safety
|
|
928
1038
|
|
|
929
|
-
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.
|
|
930
1040
|
|
|
931
|
-
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.
|
|
932
1042
|
|
|
933
1043
|
```typescript
|
|
934
1044
|
// router.tsx
|
|
935
1045
|
const router = createRouter<AppBindings>({}).routes(urlpatterns);
|
|
936
1046
|
|
|
937
1047
|
declare global {
|
|
938
|
-
namespace
|
|
1048
|
+
namespace Rango {
|
|
939
1049
|
interface Env extends AppEnv {}
|
|
940
1050
|
interface Vars extends AppVars {}
|
|
941
1051
|
interface RegisteredRoutes extends typeof router.routeMap {}
|
|
@@ -947,7 +1057,7 @@ Quick rule of thumb:
|
|
|
947
1057
|
|
|
948
1058
|
- `GeneratedRouteMap` (auto-generated) — use for server-side named-route typing: `Handler<"name">`, `ctx.reverse()`, `Prerender<"name">`
|
|
949
1059
|
- `typeof router.routeMap` — use when you need route entries with response metadata
|
|
950
|
-
- `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
|
|
951
1061
|
|
|
952
1062
|
For extracted reusable loaders or middleware, prefer global dotted names on
|
|
953
1063
|
`ctx.reverse()` by default. If you want type-safe local names for a specific
|
|
@@ -975,9 +1085,9 @@ APIs, use their dedicated subpaths.
|
|
|
975
1085
|
|
|
976
1086
|
## Examples
|
|
977
1087
|
|
|
978
|
-
See the
|
|
1088
|
+
See the example and demo apps for full working applications:
|
|
979
1089
|
|
|
980
|
-
- [`cloudflare-basic`](../../
|
|
1090
|
+
- [`cloudflare-basic`](../../tests/cloudflare-basic) — Cloudflare Workers with caching, loaders, theme, and pre-rendering
|
|
981
1091
|
- [`cloudflare-multi-router`](../../examples/cloudflare-multi-router) — Multi-app host routing
|
|
982
1092
|
|
|
983
1093
|
## License
|