@rangojs/router 0.0.0-experimental.3 → 0.0.0-experimental.30
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 +5 -0
- package/README.md +883 -4
- package/dist/bin/rango.js +1601 -0
- package/dist/vite/index.js +4655 -747
- package/package.json +78 -50
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +54 -25
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- package/skills/document-cache/SKILL.md +23 -21
- package/skills/fonts/SKILL.md +167 -0
- package/skills/hooks/SKILL.md +390 -63
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +133 -10
- package/skills/layout/SKILL.md +102 -5
- package/skills/links/SKILL.md +239 -0
- package/skills/loader/SKILL.md +366 -29
- package/skills/middleware/SKILL.md +173 -36
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +80 -3
- package/skills/prerender/SKILL.md +643 -0
- package/skills/rango/SKILL.md +86 -16
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +227 -14
- package/skills/router-setup/SKILL.md +225 -32
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +12 -11
- package/skills/typesafety/SKILL.md +401 -75
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +10 -4
- package/src/bin/rango.ts +321 -0
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/event-controller.ts +87 -64
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +20 -4
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +201 -553
- package/src/browser/navigation-client.ts +124 -71
- package/src/browser/navigation-store.ts +33 -50
- package/src/browser/navigation-transaction.ts +295 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +267 -317
- package/src/browser/prefetch/cache.ts +146 -0
- package/src/browser/prefetch/fetch.ts +135 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +42 -0
- package/src/browser/prefetch/queue.ts +88 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +173 -73
- package/src/browser/react/NavigationProvider.tsx +138 -27
- package/src/browser/react/context.ts +6 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +12 -12
- package/src/browser/react/location-state-shared.ts +95 -53
- package/src/browser/react/location-state.ts +60 -15
- package/src/browser/react/mount-context.ts +37 -0
- 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 +29 -51
- package/src/browser/react/use-client-cache.ts +5 -3
- package/src/browser/react/use-handle.ts +49 -65
- package/src/browser/react/use-href.tsx +20 -188
- package/src/browser/react/use-link-status.ts +6 -5
- package/src/browser/react/use-mount.ts +31 -0
- package/src/browser/react/use-navigation.ts +27 -78
- package/src/browser/react/use-params.ts +65 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-router.ts +63 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +80 -97
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +111 -26
- package/src/browser/scroll-restoration.ts +92 -16
- package/src/browser/segment-reconciler.ts +216 -0
- package/src/browser/segment-structure-assert.ts +83 -0
- package/src/browser/server-action-bridge.ts +504 -584
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +92 -57
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +438 -0
- package/src/build/generate-route-types.ts +36 -0
- package/src/build/index.ts +35 -0
- package/src/build/route-trie.ts +265 -0
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +98 -0
- package/src/build/route-types/codegen.ts +102 -0
- package/src/build/route-types/include-resolution.ts +411 -0
- package/src/build/route-types/param-extraction.ts +48 -0
- package/src/build/route-types/per-module-writer.ts +128 -0
- package/src/build/route-types/router-processing.ts +469 -0
- package/src/build/route-types/scan-filter.ts +78 -0
- package/src/build/runtime-discovery.ts +231 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +338 -0
- package/src/cache/cache-scope.ts +120 -303
- package/src/cache/cf/cf-cache-store.ts +119 -7
- package/src/cache/cf/index.ts +8 -2
- package/src/cache/document-cache.ts +101 -72
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +0 -15
- package/src/cache/memory-segment-store.ts +191 -13
- package/src/cache/profile-registry.ts +73 -0
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +256 -0
- package/src/cache/taint.ts +98 -0
- package/src/cache/types.ts +72 -122
- package/src/client.rsc.tsx +10 -15
- package/src/client.tsx +114 -135
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +5 -1
- package/src/context-var.ts +86 -0
- package/src/debug.ts +17 -7
- package/src/errors.ts +108 -2
- package/src/handle.ts +34 -19
- package/src/handles/MetaTags.tsx +73 -20
- package/src/handles/meta.ts +30 -13
- package/src/host/cookie-handler.ts +165 -0
- package/src/host/errors.ts +97 -0
- package/src/host/index.ts +53 -0
- package/src/host/pattern-matcher.ts +214 -0
- package/src/host/router.ts +352 -0
- package/src/host/testing.ts +79 -0
- package/src/host/types.ts +146 -0
- package/src/host/utils.ts +25 -0
- package/src/href-client.ts +135 -49
- package/src/index.rsc.ts +182 -17
- package/src/index.ts +238 -24
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +27 -142
- package/src/loader.ts +27 -10
- package/src/network-error-thrower.tsx +3 -1
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +37 -0
- package/src/prerender/store.ts +185 -0
- package/src/prerender.ts +463 -0
- package/src/reverse.ts +330 -0
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +9 -11
- package/src/route-definition/dsl-helpers.ts +934 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +430 -0
- package/src/route-definition/index.ts +52 -0
- package/src/route-definition/redirect.ts +93 -0
- package/src/route-definition.ts +1 -1388
- package/src/route-map-builder.ts +241 -112
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +70 -9
- package/src/router/content-negotiation.ts +116 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +9 -9
- package/src/router/find-match.ts +158 -0
- package/src/router/handler-context.ts +371 -81
- package/src/router/intercept-resolution.ts +395 -0
- package/src/router/lazy-includes.ts +234 -0
- package/src/router/loader-resolution.ts +215 -122
- package/src/router/logging.ts +248 -0
- package/src/router/manifest.ts +155 -32
- package/src/router/match-api.ts +620 -0
- package/src/router/match-context.ts +5 -3
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +80 -93
- package/src/router/match-middleware/cache-lookup.ts +382 -9
- package/src/router/match-middleware/cache-store.ts +51 -22
- package/src/router/match-middleware/intercept-resolution.ts +55 -17
- package/src/router/match-middleware/segment-resolution.ts +24 -6
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +34 -29
- package/src/router/metrics.ts +235 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +324 -367
- package/src/router/pattern-matching.ts +321 -30
- package/src/router/prerender-match.ts +400 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +137 -38
- package/src/router/router-context.ts +36 -21
- package/src/router/router-interfaces.ts +452 -0
- package/src/router/router-options.ts +592 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +570 -0
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +198 -0
- package/src/router/segment-resolution/revalidation.ts +1241 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -0
- package/src/router/segment-wrappers.ts +289 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +239 -0
- package/src/router/types.ts +77 -3
- package/src/router.ts +688 -3656
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +786 -760
- package/src/rsc/helpers.ts +140 -6
- package/src/rsc/index.ts +5 -25
- package/src/rsc/loader-fetch.ts +209 -0
- package/src/rsc/manifest-init.ts +86 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +379 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +235 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +348 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +40 -14
- package/src/search-params.ts +230 -0
- package/src/segment-system.tsx +57 -61
- package/src/server/context.ts +202 -51
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +94 -15
- package/src/server/loader-registry.ts +15 -56
- package/src/server/request-context.ts +422 -70
- package/src/server.ts +36 -120
- package/src/ssr/index.tsx +157 -26
- package/src/static-handler.ts +114 -0
- package/src/theme/ThemeProvider.tsx +21 -15
- package/src/theme/ThemeScript.tsx +5 -5
- package/src/theme/constants.ts +5 -2
- package/src/theme/index.ts +4 -14
- package/src/theme/theme-context.ts +4 -30
- package/src/theme/theme-script.ts +21 -18
- package/src/types/boundaries.ts +158 -0
- package/src/types/cache-types.ts +198 -0
- package/src/types/error-types.ts +192 -0
- package/src/types/global-namespace.ts +100 -0
- package/src/types/handler-context.ts +687 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +183 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +102 -0
- package/src/types/segments.ts +148 -0
- package/src/types.ts +1 -1577
- package/src/urls/include-helper.ts +197 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +339 -0
- package/src/urls/path-helper.ts +329 -0
- package/src/urls/pattern-types.ts +95 -0
- package/src/urls/response-types.ts +106 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -726
- package/src/use-loader.tsx +85 -77
- package/src/vite/discovery/bundle-postprocess.ts +184 -0
- package/src/vite/discovery/discover-routers.ts +344 -0
- package/src/vite/discovery/prerender-collection.ts +385 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +47 -0
- package/src/vite/discovery/state.ts +110 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +11 -782
- package/src/vite/plugin-types.ts +131 -0
- package/src/vite/plugins/cjs-to-esm.ts +93 -0
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/client-ref-hashing.ts +105 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -51
- package/src/vite/plugins/expose-id-utils.ts +287 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +569 -0
- package/src/vite/plugins/refresh-cmd.ts +65 -0
- package/src/vite/plugins/use-cache-transform.ts +323 -0
- package/src/vite/plugins/version-injector.ts +83 -0
- package/src/vite/plugins/version-plugin.ts +254 -0
- package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +29 -15
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +510 -0
- package/src/vite/router-discovery.ts +785 -0
- package/src/vite/utils/ast-handler-extract.ts +517 -0
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +137 -0
- package/src/vite/utils/manifest-utils.ts +70 -0
- package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
- package/src/vite/utils/prerender-utils.ts +189 -0
- package/src/vite/utils/shared-utils.ts +169 -0
- package/CLAUDE.md +0 -3
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/memory-store.ts +0 -253
- package/src/href-context.ts +0 -33
- package/src/href.ts +0 -255
- package/src/vite/expose-handle-id.ts +0 -209
- package/src/vite/expose-loader-id.ts +0 -357
- package/src/vite/expose-location-state-id.ts +0 -177
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: composability
|
|
3
|
+
description: Reusable composition patterns with globally importable route helpers in @rangojs/router
|
|
4
|
+
argument-hint: "pattern-name"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Composability
|
|
8
|
+
|
|
9
|
+
Route helpers can be imported directly from `@rangojs/router` and used to build reusable composition factories. This enables sharing common route configurations across multiple routes and modules.
|
|
10
|
+
|
|
11
|
+
## Globally Importable Helpers
|
|
12
|
+
|
|
13
|
+
These helpers can be imported and called outside the `urls()` callback parameter:
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import {
|
|
17
|
+
layout,
|
|
18
|
+
cache,
|
|
19
|
+
middleware,
|
|
20
|
+
revalidate,
|
|
21
|
+
loader,
|
|
22
|
+
loading,
|
|
23
|
+
parallel,
|
|
24
|
+
intercept,
|
|
25
|
+
when,
|
|
26
|
+
errorBoundary,
|
|
27
|
+
notFoundBoundary,
|
|
28
|
+
} from "@rangojs/router";
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
They work because they use AsyncLocalStorage internally and resolve context at call time, not import time.
|
|
32
|
+
|
|
33
|
+
## Why path() and include() Are Not Global
|
|
34
|
+
|
|
35
|
+
`path()` and `include()` remain exclusive to the `urls()` callback:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
urls(({ path, include }) => [
|
|
39
|
+
path("/blog", BlogPage, { name: "blog" }),
|
|
40
|
+
include("/shop", shopPatterns, { name: "shop" }),
|
|
41
|
+
]);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
They define the route structure -- the URL patterns and how modules compose. Keeping them in the `urls()` callback makes the route tree readable at a glance. When scanning a URL file, `path()` and `include()` calls show what renders where. Moving them into factories would hide the routing structure and make it harder to understand which URLs exist and how they nest.
|
|
45
|
+
|
|
46
|
+
The globally importable helpers (`cache`, `middleware`, `loading`, etc.) are configuration -- they modify behavior of routes but don't define routes themselves. Extracting them into factories doesn't obscure the route structure.
|
|
47
|
+
|
|
48
|
+
## Composition Factories
|
|
49
|
+
|
|
50
|
+
Define reusable factories that return arrays of use items:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { cache, revalidate, loading, errorBoundary, middleware } from "@rangojs/router";
|
|
54
|
+
|
|
55
|
+
// Shared caching configuration
|
|
56
|
+
const withCaching = () => [
|
|
57
|
+
cache({ ttl: 600_000 }),
|
|
58
|
+
revalidate(({ actionId }) => !!actionId),
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
// Shared loading and error handling
|
|
62
|
+
const withLoadingAndError = (skeleton: ReactNode) => [
|
|
63
|
+
loading(skeleton),
|
|
64
|
+
errorBoundary(() => <div>Something went wrong</div>),
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
// Shared auth middleware
|
|
68
|
+
const withAuth = () => [
|
|
69
|
+
middleware(authMiddleware),
|
|
70
|
+
middleware(loggingMiddleware),
|
|
71
|
+
];
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Using Factories in Routes
|
|
75
|
+
|
|
76
|
+
Place factory calls inside `path()` or `layout()` use callbacks. The returned arrays are flattened automatically (up to 3 levels):
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { urls } from "@rangojs/router";
|
|
80
|
+
import { withCaching, withLoadingAndError, withAuth } from "./route-config";
|
|
81
|
+
|
|
82
|
+
export const urlpatterns = urls(({ path, layout }) => [
|
|
83
|
+
layout(<AppLayout />, () => [
|
|
84
|
+
withAuth(),
|
|
85
|
+
|
|
86
|
+
path("/blog", BlogIndex, { name: "blog" }, () => [
|
|
87
|
+
withCaching(),
|
|
88
|
+
withLoadingAndError(<BlogSkeleton />),
|
|
89
|
+
]),
|
|
90
|
+
|
|
91
|
+
path("/shop", ShopIndex, { name: "shop" }, () => [
|
|
92
|
+
withCaching(),
|
|
93
|
+
withLoadingAndError(<ShopSkeleton />),
|
|
94
|
+
]),
|
|
95
|
+
]),
|
|
96
|
+
]);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Sharing Across Modules
|
|
100
|
+
|
|
101
|
+
Factories can be defined in shared modules and reused across separate `urls()` definitions:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// src/route-config.ts
|
|
105
|
+
import { cache, revalidate, middleware } from "@rangojs/router";
|
|
106
|
+
import { authMiddleware } from "./middleware/auth";
|
|
107
|
+
|
|
108
|
+
export const withPublicDefaults = () => [
|
|
109
|
+
cache({ ttl: 300 }),
|
|
110
|
+
revalidate(({ actionId }) => !!actionId),
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
export const withProtectedDefaults = () => [
|
|
114
|
+
middleware(authMiddleware),
|
|
115
|
+
cache({ ttl: 60 }),
|
|
116
|
+
];
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// src/urls/blog.ts
|
|
121
|
+
import { urls } from "@rangojs/router";
|
|
122
|
+
import { withPublicDefaults } from "../route-config";
|
|
123
|
+
|
|
124
|
+
export const blogPatterns = urls(({ path }) => [
|
|
125
|
+
path("/", BlogIndex, { name: "index" }, () => [withPublicDefaults()]),
|
|
126
|
+
]);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// src/urls/admin.ts
|
|
131
|
+
import { urls } from "@rangojs/router";
|
|
132
|
+
import { withProtectedDefaults } from "../route-config";
|
|
133
|
+
|
|
134
|
+
export const adminPatterns = urls(({ path }) => [
|
|
135
|
+
path("/", AdminDashboard, { name: "index" }, () => [withProtectedDefaults()]),
|
|
136
|
+
]);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Composition Types
|
|
140
|
+
|
|
141
|
+
For typed factories, import the composition types:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import type { RouteUseItem, LayoutUseItem, UseItems } from "@rangojs/router";
|
|
145
|
+
|
|
146
|
+
// Factory for path() use callbacks
|
|
147
|
+
const withCaching = (): RouteUseItem[] => [
|
|
148
|
+
cache({ ttl: 600_000 }),
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
// Factory for layout() use callbacks
|
|
152
|
+
const withAuth = (): LayoutUseItem[] => [
|
|
153
|
+
middleware(authMiddleware),
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
// Factory that nests other factories (use UseItems for nested arrays)
|
|
157
|
+
const withEverything = (): UseItems<RouteUseItem> => [
|
|
158
|
+
withCaching(),
|
|
159
|
+
loading(<Skeleton />),
|
|
160
|
+
];
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
- `RouteUseItem[]` -- flat array for `path()` use callbacks
|
|
164
|
+
- `LayoutUseItem[]` -- flat array for `layout()` use callbacks
|
|
165
|
+
- `UseItems<T>` -- allows nested arrays from composing factories together
|
|
166
|
+
|
|
167
|
+
## Rules
|
|
168
|
+
|
|
169
|
+
- Helpers execute lazily -- factory functions are defined anywhere, but only called inside a `urls()` context (within `path()` or `layout()` use callbacks)
|
|
170
|
+
- Calling helpers outside a `urls()` context throws an error
|
|
171
|
+
- Nested arrays from factories are flattened automatically via `.flat(3)`
|
|
172
|
+
- `path()` and `include()` cannot be used in factories -- they define route structure and must remain visible in the `urls()` callback
|
|
@@ -11,6 +11,7 @@ Inspect the route manifest to verify parent relationships, shortCodes, and route
|
|
|
11
11
|
## Quick Access
|
|
12
12
|
|
|
13
13
|
In development, visit:
|
|
14
|
+
|
|
14
15
|
```
|
|
15
16
|
http://localhost:PORT/__debug_manifest
|
|
16
17
|
```
|
|
@@ -62,13 +63,13 @@ if (process.env.NODE_ENV !== "production") {
|
|
|
62
63
|
|
|
63
64
|
## ShortCode Format
|
|
64
65
|
|
|
65
|
-
| Prefix | Meaning
|
|
66
|
-
|
|
67
|
-
| **M**
|
|
68
|
-
| **L**
|
|
69
|
-
| **C**
|
|
70
|
-
| **R**
|
|
71
|
-
| **P**
|
|
66
|
+
| Prefix | Meaning |
|
|
67
|
+
| ------ | ---------------------------------------- |
|
|
68
|
+
| **M** | Mount index (multiple `.routes()` calls) |
|
|
69
|
+
| **L** | Layout |
|
|
70
|
+
| **C** | Cache boundary |
|
|
71
|
+
| **R** | Route |
|
|
72
|
+
| **P** | Parallel slot |
|
|
72
73
|
|
|
73
74
|
Example: `M0L0L1C0R0` = Mount 0 → Root Layout → Nested Layout → Cache → Route
|
|
74
75
|
|
|
@@ -85,7 +86,7 @@ Example: `M0L0L1C0R0` = Mount 0 → Root Layout → Nested Layout → Cache →
|
|
|
85
86
|
import {
|
|
86
87
|
serializeManifest,
|
|
87
88
|
compareManifests,
|
|
88
|
-
formatManifestDiff
|
|
89
|
+
formatManifestDiff,
|
|
89
90
|
} from "@rangojs/router/__internal";
|
|
90
91
|
|
|
91
92
|
const oldManifest = await router.debugManifest();
|
|
@@ -99,10 +100,13 @@ console.log(formatManifestDiff(diff));
|
|
|
99
100
|
## Common Issues
|
|
100
101
|
|
|
101
102
|
### Routes have `parentShortCode: null`
|
|
103
|
+
|
|
102
104
|
Routes should have a layout parent. Check that `urls()` handler is being wrapped in root layout.
|
|
103
105
|
|
|
104
106
|
### Missing layouts in hierarchy
|
|
107
|
+
|
|
105
108
|
Verify `layout()` calls wrap child routes correctly.
|
|
106
109
|
|
|
107
110
|
### Wrong mount index
|
|
111
|
+
|
|
108
112
|
Multiple `.routes()` calls create separate mounts (M0, M1, etc.). Use `include()` to share context.
|
|
@@ -13,15 +13,15 @@ Caches complete HTTP responses (HTML/RSC) at the edge based on Cache-Control hea
|
|
|
13
13
|
Configure document cache in router:
|
|
14
14
|
|
|
15
15
|
```typescript
|
|
16
|
-
import {
|
|
17
|
-
import { CFCacheStore } from "@rangojs/router/cache
|
|
16
|
+
import { createRouter } from "@rangojs/router";
|
|
17
|
+
import { CFCacheStore } from "@rangojs/router/cache";
|
|
18
18
|
import { urlpatterns } from "./urls";
|
|
19
19
|
|
|
20
|
-
const router =
|
|
20
|
+
const router = createRouter<AppBindings>({
|
|
21
21
|
document: Document,
|
|
22
22
|
urls: urlpatterns,
|
|
23
|
-
documentCache: (
|
|
24
|
-
store: new CFCacheStore({ ctx:
|
|
23
|
+
documentCache: (_env, ctx) => ({
|
|
24
|
+
store: new CFCacheStore({ ctx: ctx! }),
|
|
25
25
|
skipPaths: ["/api", "/admin"],
|
|
26
26
|
debug: process.env.NODE_ENV === "development",
|
|
27
27
|
}),
|
|
@@ -35,7 +35,7 @@ export default router;
|
|
|
35
35
|
Routes opt-in to document caching using the `cache()` DSL with `documentCache` option:
|
|
36
36
|
|
|
37
37
|
```typescript
|
|
38
|
-
import { urls } from "@rangojs/router
|
|
38
|
+
import { urls } from "@rangojs/router";
|
|
39
39
|
|
|
40
40
|
export const urlpatterns = urls(({ path, cache }) => [
|
|
41
41
|
// Cache full page for 5 min, serve stale for 1 hour
|
|
@@ -56,11 +56,11 @@ export const urlpatterns = urls(({ path, cache }) => [
|
|
|
56
56
|
## Document Cache Options
|
|
57
57
|
|
|
58
58
|
```typescript
|
|
59
|
-
|
|
59
|
+
createRouter({
|
|
60
60
|
// ...
|
|
61
|
-
documentCache: (
|
|
61
|
+
documentCache: (_env, ctx) => ({
|
|
62
62
|
// Cache store (required)
|
|
63
|
-
store: new CFCacheStore({ ctx:
|
|
63
|
+
store: new CFCacheStore({ ctx: ctx! }),
|
|
64
64
|
|
|
65
65
|
// Skip specific paths
|
|
66
66
|
skipPaths: ["/api", "/admin"],
|
|
@@ -102,6 +102,7 @@ Request → Check Cache
|
|
|
102
102
|
## Cache Status Header
|
|
103
103
|
|
|
104
104
|
Response includes `x-document-cache-status`:
|
|
105
|
+
|
|
105
106
|
- `HIT` - Fresh cache hit
|
|
106
107
|
- `STALE` - Served stale, revalidating in background
|
|
107
108
|
- `MISS` - Cache miss, response was generated fresh
|
|
@@ -109,6 +110,7 @@ Response includes `x-document-cache-status`:
|
|
|
109
110
|
## Cache Key Generation
|
|
110
111
|
|
|
111
112
|
Default keys differentiate:
|
|
113
|
+
|
|
112
114
|
- HTML requests: `{pathname}:html`
|
|
113
115
|
- RSC partials: `{pathname}:{segmentHash}:rsc`
|
|
114
116
|
|
|
@@ -131,15 +133,15 @@ Segment hash ensures different cached responses for navigations from different s
|
|
|
131
133
|
|
|
132
134
|
```typescript
|
|
133
135
|
// router.tsx
|
|
134
|
-
import {
|
|
135
|
-
import { CFCacheStore } from "@rangojs/router/cache
|
|
136
|
+
import { createRouter } from "@rangojs/router";
|
|
137
|
+
import { CFCacheStore } from "@rangojs/router/cache";
|
|
136
138
|
import { urlpatterns } from "./urls";
|
|
137
139
|
|
|
138
|
-
const router =
|
|
140
|
+
const router = createRouter<AppBindings>({
|
|
139
141
|
document: Document,
|
|
140
142
|
urls: urlpatterns,
|
|
141
|
-
documentCache: (
|
|
142
|
-
store: new CFCacheStore({ ctx:
|
|
143
|
+
documentCache: (_env, ctx) => ({
|
|
144
|
+
store: new CFCacheStore({ ctx: ctx! }),
|
|
143
145
|
skipPaths: ["/api"],
|
|
144
146
|
debug: process.env.NODE_ENV === "development",
|
|
145
147
|
}),
|
|
@@ -148,7 +150,7 @@ const router = createRSCRouter<AppEnv>({
|
|
|
148
150
|
export default router;
|
|
149
151
|
|
|
150
152
|
// urls.tsx
|
|
151
|
-
import { urls } from "@rangojs/router
|
|
153
|
+
import { urls } from "@rangojs/router";
|
|
152
154
|
|
|
153
155
|
export const urlpatterns = urls(({ path, layout, cache, loader }) => [
|
|
154
156
|
// Blog with document caching
|
|
@@ -170,11 +172,11 @@ export const urlpatterns = urls(({ path, layout, cache, loader }) => [
|
|
|
170
172
|
|
|
171
173
|
## Document Cache vs Segment Cache
|
|
172
174
|
|
|
173
|
-
| Feature
|
|
174
|
-
|
|
175
|
-
| Granularity
|
|
176
|
-
| Opt-in
|
|
177
|
-
| Use case
|
|
178
|
-
| Key includes | URL + segment hash
|
|
175
|
+
| Feature | Document Cache | Segment Cache |
|
|
176
|
+
| ------------ | -------------------------- | --------------------- |
|
|
177
|
+
| Granularity | Full response | Individual segments |
|
|
178
|
+
| Opt-in | `documentCache` in cache() | `cache({ ttl, swr })` |
|
|
179
|
+
| Use case | Static pages | Dynamic compositions |
|
|
180
|
+
| Key includes | URL + segment hash | Route params |
|
|
179
181
|
|
|
180
182
|
Use document cache for mostly-static pages. Use segment cache when different parts of a page have different cache requirements.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fonts
|
|
3
|
+
description: Load and configure web fonts with preload hints for optimal performance
|
|
4
|
+
argument-hint: [provider]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Fonts
|
|
8
|
+
|
|
9
|
+
Load web fonts in the Document component with `<link rel="preload">` for optimal performance. Fonts are declared in `<head>` alongside your stylesheet.
|
|
10
|
+
|
|
11
|
+
## Google Fonts
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
// src/document.tsx
|
|
15
|
+
"use client";
|
|
16
|
+
|
|
17
|
+
import type { ReactNode } from "react";
|
|
18
|
+
import { MetaTags } from "@rangojs/router/client";
|
|
19
|
+
import styles from "./index.css?url";
|
|
20
|
+
|
|
21
|
+
export function Document({ children }: { children: ReactNode }) {
|
|
22
|
+
return (
|
|
23
|
+
<html lang="en">
|
|
24
|
+
<head>
|
|
25
|
+
{/* Preconnect to Google Fonts */}
|
|
26
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
27
|
+
<link
|
|
28
|
+
rel="preconnect"
|
|
29
|
+
href="https://fonts.gstatic.com"
|
|
30
|
+
crossOrigin="anonymous"
|
|
31
|
+
/>
|
|
32
|
+
|
|
33
|
+
{/* Load font stylesheet */}
|
|
34
|
+
<link
|
|
35
|
+
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
|
36
|
+
rel="stylesheet"
|
|
37
|
+
/>
|
|
38
|
+
|
|
39
|
+
{/* App styles */}
|
|
40
|
+
<link rel="preload" href={styles} as="style" />
|
|
41
|
+
<link rel="stylesheet" href={styles} />
|
|
42
|
+
<MetaTags />
|
|
43
|
+
</head>
|
|
44
|
+
<body>{children}</body>
|
|
45
|
+
</html>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Then reference the font in CSS:
|
|
51
|
+
|
|
52
|
+
```css
|
|
53
|
+
/* src/index.css */
|
|
54
|
+
body {
|
|
55
|
+
font-family: "Inter", sans-serif;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Or with Tailwind (see `/tailwind`):
|
|
60
|
+
|
|
61
|
+
```css
|
|
62
|
+
/* src/index.css */
|
|
63
|
+
@theme {
|
|
64
|
+
--font-sans: "Inter", sans-serif;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Self-Hosted Fonts
|
|
69
|
+
|
|
70
|
+
Place font files in `public/fonts/` and use `@font-face`:
|
|
71
|
+
|
|
72
|
+
```css
|
|
73
|
+
/* src/index.css */
|
|
74
|
+
@font-face {
|
|
75
|
+
font-family: "CustomFont";
|
|
76
|
+
src: url("/fonts/custom-regular.woff2") format("woff2");
|
|
77
|
+
font-weight: 400;
|
|
78
|
+
font-style: normal;
|
|
79
|
+
font-display: swap;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@font-face {
|
|
83
|
+
font-family: "CustomFont";
|
|
84
|
+
src: url("/fonts/custom-bold.woff2") format("woff2");
|
|
85
|
+
font-weight: 700;
|
|
86
|
+
font-style: normal;
|
|
87
|
+
font-display: swap;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
body {
|
|
91
|
+
font-family: "CustomFont", sans-serif;
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Preload the most critical weight in the Document:
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
export function Document({ children }: { children: ReactNode }) {
|
|
99
|
+
return (
|
|
100
|
+
<html lang="en">
|
|
101
|
+
<head>
|
|
102
|
+
<link
|
|
103
|
+
rel="preload"
|
|
104
|
+
href="/fonts/custom-regular.woff2"
|
|
105
|
+
as="font"
|
|
106
|
+
type="font/woff2"
|
|
107
|
+
crossOrigin="anonymous"
|
|
108
|
+
/>
|
|
109
|
+
<link rel="preload" href={styles} as="style" />
|
|
110
|
+
<link rel="stylesheet" href={styles} />
|
|
111
|
+
<MetaTags />
|
|
112
|
+
</head>
|
|
113
|
+
<body>{children}</body>
|
|
114
|
+
</html>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Fontsource (Recommended for Vite)
|
|
120
|
+
|
|
121
|
+
`@fontsource-variable` packages are the recommended approach with Vite. Fonts are installed as npm dependencies, bundled by Vite, and served from your own domain -- no external requests, no privacy concerns, no FOUT from slow CDNs.
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
pnpm add @fontsource-variable/inter
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Import the font CSS in your stylesheet. Vite resolves the `@fontsource-variable` import from `node_modules` and bundles the woff2 files as hashed assets automatically:
|
|
128
|
+
|
|
129
|
+
```css
|
|
130
|
+
/* src/index.css */
|
|
131
|
+
@import "@fontsource-variable/inter";
|
|
132
|
+
|
|
133
|
+
body {
|
|
134
|
+
font-family: "Inter Variable", sans-serif;
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
With Tailwind:
|
|
139
|
+
|
|
140
|
+
```css
|
|
141
|
+
/* src/index.css */
|
|
142
|
+
@import "@fontsource-variable/inter";
|
|
143
|
+
@import "tailwindcss";
|
|
144
|
+
|
|
145
|
+
@theme {
|
|
146
|
+
--font-sans: "Inter Variable", sans-serif;
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Why this is preferred over Google Fonts with Vite:
|
|
151
|
+
|
|
152
|
+
- No external network requests at runtime -- fonts are bundled into your build output
|
|
153
|
+
- No `<link rel="preconnect">` or extra stylesheet needed in the Document
|
|
154
|
+
- Variable font = single file covers all weights, smaller total download
|
|
155
|
+
- Vite handles cache-busting via content hashes
|
|
156
|
+
- Works offline and in edge deployments (Cloudflare Workers) without external dependencies
|
|
157
|
+
|
|
158
|
+
Browse available fonts at fontsource.org. Use `@fontsource-variable/*` for variable fonts and `@fontsource/*` for static fonts.
|
|
159
|
+
|
|
160
|
+
## Performance Tips
|
|
161
|
+
|
|
162
|
+
- Prefer `@fontsource-variable` with Vite for self-hosted, zero-config font loading
|
|
163
|
+
- Use `font-display: swap` to prevent invisible text during font load
|
|
164
|
+
- Preload only the most critical font weight (usually regular 400)
|
|
165
|
+
- Prefer `woff2` format for smaller file sizes
|
|
166
|
+
- Use variable fonts when multiple weights are needed to reduce total file count
|
|
167
|
+
- `<link rel="preconnect">` eliminates DNS + TLS latency for external font providers
|