@kasperrt/smolter 0.0.1 → 0.3.0
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/{src/internal → .generated}/client/index.ts +1 -0
- package/.generated/core/environment.ts +43 -0
- package/{src/internal → .generated}/core/errors.ts +1 -1
- package/{src/internal → .generated}/core/index.ts +2 -0
- package/.generated/core/navigation-router.ts +107 -0
- package/.generated/core/navigation.ts +147 -0
- package/.generated/core/presentation.ts +108 -0
- package/.generated/core/resource-types.ts +44 -0
- package/.generated/core/resources.ts +444 -0
- package/.generated/core/responses.ts +86 -0
- package/{src/internal → .generated}/core/router.ts +136 -63
- package/.generated/core/serialize.ts +20 -0
- package/.generated/core/store.ts +25 -0
- package/.generated/core/submission.ts +116 -0
- package/{src/internal → .generated}/core/types.ts +18 -1
- package/.generated/core/url.ts +29 -0
- package/.generated/core/utils.ts +5 -0
- package/.generated/preact/await.tsx +41 -0
- package/.generated/preact/client.tsx +93 -0
- package/.generated/preact/context.ts +59 -0
- package/.generated/preact/document.tsx +198 -0
- package/{src/internal → .generated}/preact/fetcher.ts +43 -23
- package/.generated/preact/form.ts +58 -0
- package/{src/internal → .generated}/preact/hooks.ts +25 -28
- package/.generated/preact/index.ts +34 -0
- package/.generated/preact/lazy-route.ts +100 -0
- package/.generated/preact/navigation-state.ts +9 -0
- package/.generated/preact/navigation.tsx +147 -0
- package/.generated/preact/root-context.ts +21 -0
- package/.generated/preact/root-data.ts +45 -0
- package/.generated/preact/route-hooks.tsx +170 -0
- package/.generated/preact/route-types.ts +76 -0
- package/.generated/preact/router.tsx +107 -0
- package/{src/internal → .generated}/preact/routes.ts +17 -9
- package/.generated/react/context.ts +59 -0
- package/.generated/react/data.ts +25 -0
- package/{src/internal → .generated}/react/fetcher.ts +13 -11
- package/.generated/react/form.ts +58 -0
- package/{src/internal → .generated}/react/hooks.ts +9 -14
- package/{src/internal/preact → .generated/react}/index.ts +5 -1
- package/{src/internal → .generated}/react/link.ts +13 -21
- package/.generated/react/resources/components.tsx +404 -0
- package/{src/internal → .generated}/react/routes.ts +17 -9
- package/.generated/server/application.tsx +185 -0
- package/.generated/server/assets.ts +19 -0
- package/.generated/server/handler.ts +69 -0
- package/.generated/server/http.ts +55 -0
- package/{src/internal → .generated}/server/index.ts +4 -17
- package/.generated/server/node.ts +4 -0
- package/.generated/server/preact.ts +7 -0
- package/.generated/vite/application/browser-boundary.ts +42 -0
- package/.generated/vite/application/lazy-files.ts +136 -0
- package/.generated/vite/application/vite.ts +144 -0
- package/{src/internal → .generated}/vite/index.ts +4 -2
- package/.generated/vite/preact.ts +24 -0
- package/.generated/vite/react.ts +18 -0
- package/{src/internal → .generated}/vite/transport.ts +2 -1
- package/CHANGELOG.md +54 -0
- package/README.md +269 -55
- package/dist/client/deserialize.js +10 -0
- package/dist/{internal/client → client}/index.d.ts +1 -0
- package/dist/client/index.js +46 -0
- package/dist/core/environment.d.ts +12 -0
- package/dist/core/environment.js +23 -0
- package/dist/core/errors.js +7 -0
- package/dist/{internal/core → core}/index.d.ts +2 -0
- package/dist/core/match.js +33 -0
- package/dist/core/navigation-router.d.ts +15 -0
- package/dist/core/navigation-router.js +64 -0
- package/dist/core/navigation.d.ts +15 -0
- package/dist/core/navigation.js +92 -0
- package/dist/core/presentation.d.ts +5 -0
- package/dist/core/presentation.js +69 -0
- package/dist/core/resource-types.d.ts +37 -0
- package/dist/core/resources.d.ts +19 -0
- package/dist/core/resources.js +345 -0
- package/dist/core/responses.d.ts +15 -0
- package/dist/core/responses.js +48 -0
- package/dist/{internal/core → core}/router.d.ts +1 -1
- package/dist/core/router.js +204 -0
- package/dist/core/serialize.d.ts +5 -0
- package/dist/core/serialize.js +17 -0
- package/dist/core/store.d.ts +6 -0
- package/dist/core/store.js +21 -0
- package/dist/core/submission.d.ts +30 -0
- package/dist/core/submission.js +41 -0
- package/dist/{internal/core → core}/types.d.ts +16 -1
- package/dist/core/url.d.ts +7 -0
- package/dist/core/url.js +12 -0
- package/dist/core/utils.d.ts +5 -0
- package/dist/core/utils.js +5 -0
- package/dist/files/index.js +64 -0
- package/dist/preact/await.d.ts +7 -0
- package/dist/preact/await.js +19 -0
- package/dist/preact/client.d.ts +7 -0
- package/dist/preact/client.js +67 -0
- package/dist/preact/context.d.ts +18 -0
- package/dist/preact/context.js +23 -0
- package/dist/preact/document.d.ts +15 -0
- package/dist/preact/document.js +155 -0
- package/dist/{internal/preact → preact}/fetcher.d.ts +9 -5
- package/dist/preact/fetcher.js +45 -0
- package/dist/{internal/preact → preact}/form.d.ts +5 -6
- package/dist/preact/form.js +21 -0
- package/dist/{internal/preact → preact}/hooks.d.ts +7 -6
- package/dist/preact/hooks.js +25 -0
- package/dist/preact/index.d.ts +18 -0
- package/dist/preact/index.js +15 -0
- package/dist/preact/lazy-route.d.ts +19 -0
- package/dist/preact/lazy-route.js +51 -0
- package/dist/preact/navigation-state.d.ts +2 -0
- package/dist/preact/navigation-state.js +9 -0
- package/dist/preact/navigation.d.ts +28 -0
- package/dist/preact/navigation.js +60 -0
- package/dist/preact/root-context.d.ts +13 -0
- package/dist/preact/root-context.js +9 -0
- package/dist/preact/root-data.d.ts +8 -0
- package/dist/preact/root-data.js +28 -0
- package/dist/preact/route-hooks.d.ts +32 -0
- package/dist/preact/route-hooks.js +94 -0
- package/dist/preact/route-types.d.ts +54 -0
- package/dist/preact/router.d.ts +16 -0
- package/dist/preact/router.js +63 -0
- package/dist/{internal/preact → preact}/routes.d.ts +1 -1
- package/dist/preact/routes.js +12 -0
- package/dist/{internal/preact → preact}/runtime.js +1 -1
- package/dist/react/context.d.ts +18 -0
- package/dist/react/context.js +23 -0
- package/dist/react/data.d.ts +5 -0
- package/dist/react/data.js +3 -0
- package/dist/{internal/react → react}/fetcher.d.ts +2 -2
- package/dist/react/fetcher.js +34 -0
- package/dist/{internal/react → react}/form.d.ts +5 -6
- package/dist/react/form.js +21 -0
- package/dist/react/hooks.js +25 -0
- package/dist/{internal/react → react}/index.d.ts +1 -1
- package/dist/react/index.js +10 -0
- package/dist/{internal/react → react}/link.d.ts +2 -2
- package/dist/react/link.js +27 -0
- package/dist/react/resources/components.d.ts +64 -0
- package/dist/react/resources/components.js +239 -0
- package/dist/{internal/react → react}/routes.d.ts +1 -1
- package/dist/react/routes.js +12 -0
- package/dist/react/runtime.js +1 -0
- package/dist/server/application.d.ts +4 -0
- package/dist/server/application.js +119 -0
- package/dist/server/assets.d.ts +5 -0
- package/dist/server/assets.js +7 -0
- package/dist/server/handler.d.ts +19 -0
- package/dist/server/handler.js +22 -0
- package/dist/server/http.d.ts +4 -0
- package/dist/server/http.js +27 -0
- package/dist/{internal/server → server}/index.d.ts +2 -3
- package/dist/server/index.js +76 -0
- package/dist/server/node.d.ts +3 -0
- package/dist/server/node.js +3 -0
- package/dist/server/preact.d.ts +3 -0
- package/dist/server/preact.js +4 -0
- package/dist/vite/application/browser-boundary.d.ts +3 -0
- package/dist/vite/application/browser-boundary.js +35 -0
- package/dist/vite/application/lazy-files.d.ts +2 -0
- package/dist/vite/application/lazy-files.js +87 -0
- package/dist/vite/application/vite.d.ts +9 -0
- package/dist/vite/application/vite.js +101 -0
- package/dist/{internal/vite → vite}/index.d.ts +2 -1
- package/dist/vite/index.js +104 -0
- package/dist/vite/preact.d.ts +11 -0
- package/dist/vite/preact.js +15 -0
- package/dist/vite/react.d.ts +9 -0
- package/dist/vite/react.js +14 -0
- package/dist/{internal/vite → vite}/transport.d.ts +1 -1
- package/dist/vite/transport.js +35 -0
- package/jsr.json +28 -11
- package/package.json +119 -38
- package/dist/client.d.ts +0 -2
- package/dist/client.js +0 -2
- package/dist/core.d.ts +0 -2
- package/dist/core.js +0 -2
- package/dist/files.d.ts +0 -2
- package/dist/files.js +0 -2
- package/dist/internal/client/deserialize.js +0 -11
- package/dist/internal/client/index.js +0 -44
- package/dist/internal/core/errors.js +0 -6
- package/dist/internal/core/index.js +0 -6
- package/dist/internal/core/match.js +0 -27
- package/dist/internal/core/router.js +0 -189
- package/dist/internal/core/types.js +0 -5
- package/dist/internal/core/url.d.ts +0 -2
- package/dist/internal/core/url.js +0 -6
- package/dist/internal/files/index.js +0 -77
- package/dist/internal/preact/context.d.ts +0 -18
- package/dist/internal/preact/context.js +0 -20
- package/dist/internal/preact/fetcher.js +0 -28
- package/dist/internal/preact/form.js +0 -41
- package/dist/internal/preact/hooks.js +0 -35
- package/dist/internal/preact/index.d.ts +0 -9
- package/dist/internal/preact/index.js +0 -7
- package/dist/internal/preact/link.d.ts +0 -12
- package/dist/internal/preact/link.js +0 -28
- package/dist/internal/preact/routes.js +0 -22
- package/dist/internal/react/context.d.ts +0 -18
- package/dist/internal/react/context.js +0 -20
- package/dist/internal/react/fetcher.js +0 -28
- package/dist/internal/react/form.js +0 -41
- package/dist/internal/react/hooks.js +0 -35
- package/dist/internal/react/index.js +0 -7
- package/dist/internal/react/link.js +0 -28
- package/dist/internal/react/routes.js +0 -22
- package/dist/internal/react/runtime.js +0 -2
- package/dist/internal/server/index.js +0 -81
- package/dist/internal/vite/index.js +0 -132
- package/dist/internal/vite/transport.js +0 -42
- package/dist/preact.d.ts +0 -2
- package/dist/preact.js +0 -2
- package/dist/react.d.ts +0 -2
- package/dist/react.js +0 -2
- package/dist/server.d.ts +0 -2
- package/dist/server.js +0 -2
- package/dist/vite.d.ts +0 -2
- package/dist/vite.js +0 -2
- package/src/client.ts +0 -2
- package/src/core.ts +0 -2
- package/src/files.ts +0 -2
- package/src/internal/core/url.ts +0 -6
- package/src/internal/preact/context.ts +0 -46
- package/src/internal/preact/form.ts +0 -79
- package/src/internal/preact/link.ts +0 -46
- package/src/internal/react/context.ts +0 -46
- package/src/internal/react/form.ts +0 -79
- package/src/internal/react/index.ts +0 -13
- package/src/preact.ts +0 -2
- package/src/react.ts +0 -2
- package/src/server.ts +0 -2
- package/src/vite.ts +0 -2
- /package/{src/internal → .generated}/client/deserialize.ts +0 -0
- /package/{src/internal → .generated}/core/match.ts +0 -0
- /package/{src/internal → .generated}/files/index.ts +0 -0
- /package/{src/internal → .generated}/preact/runtime.ts +0 -0
- /package/{src/internal → .generated}/react/runtime.ts +0 -0
- /package/dist/{internal/client → client}/deserialize.d.ts +0 -0
- /package/dist/{internal/core → core}/errors.d.ts +0 -0
- /package/dist/{internal/core → core}/match.d.ts +0 -0
- /package/dist/{internal/files → files}/index.d.ts +0 -0
- /package/dist/{internal/preact → preact}/runtime.d.ts +0 -0
- /package/dist/{internal/react → react}/hooks.d.ts +0 -0
- /package/dist/{internal/react → react}/runtime.d.ts +0 -0
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# smolter _
|
|
2
2
|
|
|
3
3
|
<!-- bundlejs:start -->
|
|
4
|
-
[](https://bundlejs.com/?q=%40kasperrt%2Fsmolter%400.3.0%2Freact&treeshake=%5B*%5D&config=%7B%22compression%22%3A%22gzip%22%2C%22esbuild%22%3A%7B%22external%22%3A%5B%22react%22%2C%22react%2F*%22%5D%7D%7D&bundle)
|
|
5
|
+
[](https://bundlejs.com/?q=%40kasperrt%2Fsmolter%400.3.0%2Fpreact&treeshake=%5B*%5D&config=%7B%22compression%22%3A%22gzip%22%2C%22esbuild%22%3A%7B%22external%22%3A%5B%22preact%22%2C%22preact%2F*%22%5D%7D%7D&bundle)
|
|
6
6
|
<!-- bundlejs:end -->
|
|
7
7
|
|
|
8
8
|
A typed data router for React and Preact. **Zero runtime dependencies.**
|
|
@@ -14,6 +14,10 @@ loader; `shouldRevalidate` decides when that work is needed.
|
|
|
14
14
|
Inspired by [wouter](https://github.com/molefrog/wouter)
|
|
15
15
|
and [React Router](https://reactrouter.com/).
|
|
16
16
|
|
|
17
|
+
[Read the documentation](https://kasperrt.github.io/smolter/react/docs/) for guides and the complete API reference. The site itself uses smolter routes.
|
|
18
|
+
|
|
19
|
+
Start with [loaders](https://kasperrt.github.io/smolter/react/docs/loaders/), [actions](https://kasperrt.github.io/smolter/react/docs/actions/), [forms and validation](https://kasperrt.github.io/smolter/react/docs/forms/), or [fetcher reads and mutations](https://kasperrt.github.io/smolter/react/docs/fetchers/). Each guide connects the handler to an actual route URL and its consuming view.
|
|
20
|
+
|
|
17
21
|
## Contents
|
|
18
22
|
|
|
19
23
|
- [Install](#install)
|
|
@@ -25,7 +29,10 @@ and [React Router](https://reactrouter.com/).
|
|
|
25
29
|
- [Types follow the handler](#types-follow-the-handler)
|
|
26
30
|
- [Server rendering](#server-rendering)
|
|
27
31
|
- [Package entries](#package-entries)
|
|
32
|
+
- [Application integration](#application-integration)
|
|
33
|
+
- [Resource subscriptions](#resource-subscriptions)
|
|
28
34
|
- [Size and checks](#size-and-checks)
|
|
35
|
+
- [Routing without data hooks](#routing-without-data-hooks)
|
|
29
36
|
|
|
30
37
|
## Install
|
|
31
38
|
|
|
@@ -36,7 +43,7 @@ pnpm add @kasperrt/smolter
|
|
|
36
43
|
```
|
|
37
44
|
|
|
38
45
|
```ts
|
|
39
|
-
import {
|
|
46
|
+
import { createDataRouter, useFetcher } from "@kasperrt/smolter/react";
|
|
40
47
|
// Preact: import from "@kasperrt/smolter/preact".
|
|
41
48
|
```
|
|
42
49
|
|
|
@@ -49,15 +56,16 @@ pnpm dev
|
|
|
49
56
|
|
|
50
57
|
| App | Open | Data |
|
|
51
58
|
| --- | --- | --- |
|
|
52
|
-
| [React SPA](
|
|
53
|
-
| [Preact SPA](
|
|
54
|
-
| [React SSR](
|
|
55
|
-
| [Preact SSR](
|
|
59
|
+
| [React SPA](./apps/react) | http://127.0.0.1:5173 | Client loaders/actions, localStorage |
|
|
60
|
+
| [Preact SPA](./apps/preact) | http://127.0.0.1:5174 | Client loaders/actions, localStorage |
|
|
61
|
+
| [React SSR](./apps/react-ssr) | http://127.0.0.1:5175 | Server loaders/actions, hydration |
|
|
62
|
+
| [Preact SSR](./apps/preact-ssr) | http://127.0.0.1:5176 | Server loaders/actions, hydration |
|
|
56
63
|
|
|
57
64
|
Each app has its own entrypoints, routes, and data code. Only UI components are
|
|
58
65
|
shared. Preact examples do not import React. Each includes:
|
|
59
66
|
|
|
60
|
-
- `/`:
|
|
67
|
+
- `/`: a short introduction and a link to the docs.
|
|
68
|
+
- `/examples/counter`: fetcher POST, automatic and manual revalidation.
|
|
61
69
|
- `/tasks`: list, create form, and a fetcher-only task preview.
|
|
62
70
|
- `/tasks/:id`: PATCH, DELETE, validation, and skipping no-op revalidation.
|
|
63
71
|
- `/about`: the separation between data and rendering.
|
|
@@ -81,7 +89,7 @@ or filename parser enters the browser bundle.
|
|
|
81
89
|
```ts
|
|
82
90
|
// vite.config.ts
|
|
83
91
|
import { defineConfig } from "vite";
|
|
84
|
-
import { fileRouter } from "@kasperrt/smolter/vite";
|
|
92
|
+
import { fileRouter } from "@kasperrt/smolter/react/vite";
|
|
85
93
|
|
|
86
94
|
export default defineConfig({
|
|
87
95
|
plugins: [fileRouter({ directory: "src/routes" })],
|
|
@@ -90,10 +98,10 @@ export default defineConfig({
|
|
|
90
98
|
|
|
91
99
|
```ts
|
|
92
100
|
// app.ts
|
|
93
|
-
import {
|
|
101
|
+
import { createDataRouter } from "@kasperrt/smolter/react";
|
|
94
102
|
import routes from "virtual:smolter/routes";
|
|
95
103
|
|
|
96
|
-
export const router =
|
|
104
|
+
export const router = createDataRouter(routes, { browser: true });
|
|
97
105
|
```
|
|
98
106
|
|
|
99
107
|
| File or folder | URL |
|
|
@@ -121,25 +129,25 @@ For the virtual module, add this declaration to your app:
|
|
|
121
129
|
// env.d.ts
|
|
122
130
|
// Include vite/client in your tsconfig types as usual.
|
|
123
131
|
declare module "virtual:smolter/routes" {
|
|
124
|
-
const routes: import("@kasperrt/smolter/
|
|
132
|
+
const routes: import("@kasperrt/smolter/react").Route[];
|
|
125
133
|
export default routes;
|
|
126
134
|
}
|
|
127
135
|
```
|
|
128
136
|
|
|
129
|
-
Outside Vite, `flatRoutes(directory)` from `@kasperrt/smolter/
|
|
137
|
+
Outside Vite, `flatRoutes(directory)` from `@kasperrt/smolter/react/vite` returns
|
|
130
138
|
`{ path, file }[] | Error` for your build tool to turn into imports.
|
|
131
139
|
|
|
132
140
|
### Manual routes
|
|
133
141
|
|
|
134
142
|
```tsx
|
|
135
|
-
import {
|
|
143
|
+
import { createDataRouter, defineRoute } from "@kasperrt/smolter/react";
|
|
136
144
|
import * as tasks from "./tasks/route";
|
|
137
145
|
import * as task from "./task/route";
|
|
138
146
|
|
|
139
147
|
export const tasksRoute = defineRoute("/tasks", tasks);
|
|
140
148
|
export const taskRoute = defineRoute("/tasks/:id", task);
|
|
141
149
|
export const routes = [tasksRoute, taskRoute];
|
|
142
|
-
export const router =
|
|
150
|
+
export const router = createDataRouter(routes, { browser: true });
|
|
143
151
|
```
|
|
144
152
|
|
|
145
153
|
Or pass handlers directly to `defineRoute(path, { loader, action, default: View })`.
|
|
@@ -167,11 +175,12 @@ export { default } from "./view";
|
|
|
167
175
|
export { loader } from "./loader";
|
|
168
176
|
export { action } from "./action";
|
|
169
177
|
|
|
170
|
-
export { clientLoader } from "./
|
|
171
|
-
export { clientAction } from "./
|
|
178
|
+
export { clientLoader } from "./clientLoader";
|
|
179
|
+
export { clientAction } from "./clientAction";
|
|
172
180
|
|
|
173
|
-
export { shouldRevalidate } from "./
|
|
174
|
-
export { HydrateFallback
|
|
181
|
+
export { shouldRevalidate } from "./shouldRevalidate";
|
|
182
|
+
export { HydrateFallback } from "./HydrateFallback";
|
|
183
|
+
export { ErrorBoundary } from "./ErrorBoundary";
|
|
175
184
|
```
|
|
176
185
|
|
|
177
186
|
With the optional server integration:
|
|
@@ -183,8 +192,8 @@ With the optional server integration:
|
|
|
183
192
|
- SSR executes the server loader and hydration reuses that data.
|
|
184
193
|
|
|
185
194
|
```ts
|
|
186
|
-
//
|
|
187
|
-
import type { ClientLoaderArgs } from "@kasperrt/smolter/client";
|
|
195
|
+
// clientLoader.ts
|
|
196
|
+
import type { ClientLoaderArgs } from "@kasperrt/smolter/react/client";
|
|
188
197
|
import type { loader } from "./loader";
|
|
189
198
|
|
|
190
199
|
export async function clientLoader({ serverLoader }: ClientLoaderArgs<typeof loader>) {
|
|
@@ -193,8 +202,8 @@ export async function clientLoader({ serverLoader }: ClientLoaderArgs<typeof loa
|
|
|
193
202
|
```
|
|
194
203
|
|
|
195
204
|
```ts
|
|
196
|
-
//
|
|
197
|
-
import type { ClientActionArgs } from "@kasperrt/smolter/client";
|
|
205
|
+
// clientAction.ts
|
|
206
|
+
import type { ClientActionArgs } from "@kasperrt/smolter/react/client";
|
|
198
207
|
import type { action } from "./action";
|
|
199
208
|
|
|
200
209
|
export async function clientAction({ serverAction }: ClientActionArgs<typeof action>) {
|
|
@@ -234,17 +243,17 @@ in a client bundle. Type-only imports from server handlers are safe. Do not
|
|
|
234
243
|
import server code directly into client views or client handlers.
|
|
235
244
|
|
|
236
245
|
The Vite dev plugin mounts `/_smolter?url=...`. Production hosts dispatch that
|
|
237
|
-
endpoint through `handleRequest(routes, request)` from `@kasperrt/smolter/server`, using
|
|
246
|
+
endpoint through `handleRequest(routes, request)` from `@kasperrt/smolter/react/server`, using
|
|
238
247
|
the requested route URL. Both SSR examples include a working host. The host
|
|
239
248
|
owns authentication, session cookies, HTTP policy, and deployment.
|
|
240
249
|
|
|
241
250
|
Manual server routes use `serverRoute<typeof import("./route")>(path, clientModule)`
|
|
242
|
-
from `@kasperrt/smolter/client` in the browser and `defineRoute` on the server. This keeps
|
|
251
|
+
from `@kasperrt/smolter/react/client` in the browser and `defineRoute` on the server. This keeps
|
|
243
252
|
the type connection without importing server code at runtime. To use manual
|
|
244
253
|
tables with the dev transport:
|
|
245
254
|
|
|
246
255
|
```ts
|
|
247
|
-
import { routerPlugin } from "@kasperrt/smolter/vite";
|
|
256
|
+
import { routerPlugin } from "@kasperrt/smolter/react/vite";
|
|
248
257
|
|
|
249
258
|
routerPlugin({
|
|
250
259
|
clientRoutes: "src/manual-browser-routes.ts",
|
|
@@ -254,7 +263,7 @@ routerPlugin({
|
|
|
254
263
|
|
|
255
264
|
Each table exports `routes`. The standalone examples contain both tables.
|
|
256
265
|
|
|
257
|
-
Without the optional integration, `
|
|
266
|
+
Without the optional integration, `createDataRouter` invokes handlers locally:
|
|
258
267
|
client handlers take precedence, with ordinary handlers as fallbacks.
|
|
259
268
|
`loadRouter` selects server handlers only. Core-only usage does not create HTTP
|
|
260
269
|
endpoints or compiler boundaries by itself.
|
|
@@ -315,7 +324,7 @@ Fetcher results belong to `fetcher.data`, not `useActionData()`.
|
|
|
315
324
|
## Decide when to revalidate
|
|
316
325
|
|
|
317
326
|
```ts
|
|
318
|
-
//
|
|
327
|
+
// shouldRevalidate.ts
|
|
319
328
|
import type { RevalidationArgs } from "@kasperrt/smolter/react";
|
|
320
329
|
|
|
321
330
|
export function shouldRevalidate({ actionResult, defaultShouldRevalidate }: RevalidationArgs) {
|
|
@@ -340,7 +349,25 @@ and explicit `fetcher.load()` calls always load their destination.
|
|
|
340
349
|
This controls loader refreshes; it does not rerun actions or reload the document.
|
|
341
350
|
Existing page data stays visible during manual and post-action refreshes.
|
|
342
351
|
|
|
343
|
-
`
|
|
352
|
+
`useRevalidator()` returns an async function. Target a registered route ID or path
|
|
353
|
+
pattern to refresh only its active data, including loaded fetchers:
|
|
354
|
+
|
|
355
|
+
```tsx
|
|
356
|
+
const revalidate = useRevalidator();
|
|
357
|
+
|
|
358
|
+
await revalidate({ route: "/tasks/:id" });
|
|
359
|
+
await revalidate({ route: "root" });
|
|
360
|
+
await revalidate({ route: ["root", "/tasks/:id"] });
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Without a target, `revalidate()` refreshes the active page, loaded fetchers, and
|
|
364
|
+
registered root/layout data. `shouldRevalidate` still applies. Inactive routes
|
|
365
|
+
are not loaded, unknown targets do nothing, and revalidation never navigates.
|
|
366
|
+
|
|
367
|
+
The Preact root integration uses `root` as its default ID. Configure its
|
|
368
|
+
`loaderPath` with a registered data route to enable root refreshes. Custom React
|
|
369
|
+
or Preact layouts can use `router.registerRevalidator(id, callback)`; call its
|
|
370
|
+
returned cleanup function when the layout is removed.
|
|
344
371
|
The task-detail examples return `{ changed: false }` for an unchanged title;
|
|
345
372
|
the corresponding loader is skipped.
|
|
346
373
|
|
|
@@ -366,7 +393,7 @@ remount the fallback during revalidation. Return a `Response` with a `Location`
|
|
|
366
393
|
## Server rendering
|
|
367
394
|
|
|
368
395
|
```tsx
|
|
369
|
-
import { loadRouter, serialize } from "@kasperrt/smolter/server";
|
|
396
|
+
import { loadRouter, serialize } from "@kasperrt/smolter/react/server";
|
|
370
397
|
|
|
371
398
|
const router = await loadRouter(routes, incomingRequest);
|
|
372
399
|
const html = renderToString(
|
|
@@ -376,18 +403,18 @@ const hydrationJSON = serialize(router.getSnapshot());
|
|
|
376
403
|
```
|
|
377
404
|
|
|
378
405
|
Create a fresh router per request. Embed the serialized snapshot in a JSON
|
|
379
|
-
script, restore it with `deserialize` from `@kasperrt/smolter/client`, and pass it as
|
|
380
|
-
`hydrationData` to `
|
|
406
|
+
script, restore it with `deserialize` from `@kasperrt/smolter/react/client`, and pass it as
|
|
407
|
+
`hydrationData` to `createDataRouter`. This preserves loader errors through hydration
|
|
381
408
|
without exposing server stacks or causes. Error boundaries should display the
|
|
382
409
|
error message, not its stack.
|
|
383
410
|
|
|
384
411
|
```ts
|
|
385
|
-
import { deserialize } from "@kasperrt/smolter/client";
|
|
386
|
-
import {
|
|
412
|
+
import { deserialize } from "@kasperrt/smolter/react/client";
|
|
413
|
+
import { createDataRouter } from "@kasperrt/smolter/react";
|
|
387
414
|
import routes from "virtual:smolter/routes";
|
|
388
415
|
|
|
389
416
|
const data = document.getElementById("smolter-data");
|
|
390
|
-
const router =
|
|
417
|
+
const router = createDataRouter(routes, {
|
|
391
418
|
browser: true,
|
|
392
419
|
hydrationData: data?.textContent ? deserialize(data.textContent) : undefined,
|
|
393
420
|
});
|
|
@@ -402,47 +429,232 @@ The SSR examples use the same server route definitions for HTML and data request
|
|
|
402
429
|
|
|
403
430
|
## Package entries
|
|
404
431
|
|
|
405
|
-
Use `@kasperrt/smolter/react` for React 18+ and `@kasperrt/smolter/preact` for Preact
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
432
|
+
Use `@kasperrt/smolter/react` for React 18+ and `@kasperrt/smolter/preact` for Preact 11.0.1+.
|
|
433
|
+
Choose one renderer for your application. Both expose the same routing API:
|
|
434
|
+
|
|
435
|
+
| Purpose | React | Preact |
|
|
436
|
+
| --- | --- | --- |
|
|
437
|
+
| Components, hooks, router, data types | `@kasperrt/smolter/react` | `@kasperrt/smolter/preact` |
|
|
438
|
+
| Optional browser transport | `@kasperrt/smolter/react/client` | `@kasperrt/smolter/preact/client` |
|
|
439
|
+
| SSR and HTTP data dispatch | `@kasperrt/smolter/react/server` | `@kasperrt/smolter/preact/server` |
|
|
440
|
+
| Vite plugin and flat-file discovery | `@kasperrt/smolter/react/vite` | `@kasperrt/smolter/preact/vite` |
|
|
441
|
+
|
|
442
|
+
`@kasperrt/smolter/utils` contains browser-safe matching and error helpers.
|
|
443
|
+
The main renderer entries never import server or build modules. Named imports
|
|
444
|
+
are tree-shaken; optional transport is included only when you import `/client`.
|
|
445
|
+
Server entries do not import either UI renderer. Vite entries are build-time only.
|
|
446
|
+
|
|
447
|
+
**Migrating renderer subpaths:** replace `/core` imports for types, router factories, and
|
|
448
|
+
`defineRoute` with your renderer entry. Use `/utils` for `matchRoutes`,
|
|
449
|
+
`internalURL` and `safeWrapAsync`. Move `/client`, `/server`,
|
|
450
|
+
`/files`, and `/vite` imports to the corresponding renderer-prefixed path above.
|
|
451
|
+
The bare package root and old top-level subpaths are no longer exported.
|
|
452
|
+
|
|
453
|
+
See the [0.3 migration guide](https://kasperrt.github.io/smolter/react/docs/migration-0.3/) and [changelog](./CHANGELOG.md).
|
|
454
|
+
|
|
455
|
+
**Router factory migration:** code that previously used `createRouter` with
|
|
456
|
+
loaders, actions, fetchers or revalidation must now use `createDataRouter`.
|
|
457
|
+
`createRouter` now creates a navigation-only router. SSR and file-router
|
|
458
|
+
application helpers select `createDataRouter` automatically.
|
|
409
459
|
|
|
410
460
|
On JSR, install `@kasperrt/smolter` using the
|
|
411
461
|
[JSR package instructions](https://jsr.io/docs/npm-compatibility) and import
|
|
412
|
-
`@kasperrt/smolter/react` or `@kasperrt/smolter/preact`. Its
|
|
413
|
-
|
|
414
|
-
|
|
462
|
+
`@kasperrt/smolter/react` or `@kasperrt/smolter/preact`. Its renderer, client, server and utility subpaths match npm. The Vite plugin is npm-only:
|
|
463
|
+
use `@kasperrt/smolter/react/vite` from the npm package when adding file routing.
|
|
464
|
+
|
|
465
|
+
## Application integration
|
|
466
|
+
|
|
467
|
+
Import routing, forms and data hooks from `@kasperrt/smolter/preact`.
|
|
468
|
+
Document rendering is optional: `@kasperrt/smolter/preact/document` supplies
|
|
469
|
+
`Document`, `Meta`, `Links`, `Scripts` and `ScrollRestoration`.
|
|
470
|
+
`@kasperrt/smolter/preact/client` supplies `mountApplication`,
|
|
471
|
+
`configureApplication` and the server transport helpers. Mounting connects
|
|
472
|
+
hydration, root data and navigation presentation to the same core router.
|
|
473
|
+
These modules remain tree-shakable; basic routing does not import the document
|
|
474
|
+
or mounting code. The size table also measures all three together, because
|
|
475
|
+
moving APIs to subpaths does not make their implementation disappear.
|
|
476
|
+
|
|
477
|
+
```ts
|
|
478
|
+
// vite.config.ts
|
|
479
|
+
import { defineConfig } from "vite";
|
|
480
|
+
import { applicationPlugins } from "@kasperrt/smolter/preact/vite";
|
|
481
|
+
|
|
482
|
+
export default defineConfig({
|
|
483
|
+
plugins: applicationPlugins({ directory: "src/routes" }),
|
|
484
|
+
});
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
```tsx
|
|
488
|
+
// src/entry.client.tsx
|
|
489
|
+
import routes from "virtual:smolter/routes";
|
|
490
|
+
import { mountApplication } from "@kasperrt/smolter/preact/client";
|
|
491
|
+
import * as root from "./root";
|
|
492
|
+
|
|
493
|
+
mountApplication(routes, root);
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
`root` exports a default component containing `Outlet` and a `Layout` wrapping
|
|
497
|
+
it in `Document`, a head, and a body containing `Scripts`. Its optional loader
|
|
498
|
+
supplies root data. `renderApplication(request, routes, root, entry)` from
|
|
499
|
+
`preact/server` renders the same tree and serializes hydration data;
|
|
500
|
+
`dispatchRoute(request, routes)` handles route data requests. Server rendering
|
|
501
|
+
requires the optional `preact-render-to-string` peer.
|
|
502
|
+
|
|
503
|
+
Deployment-specific URL mapping can be configured once at startup with
|
|
504
|
+
`configureApplication({ resolveURL, isDocumentHandoff, leaveDocument,
|
|
505
|
+
entryScript })`. Do not put user-specific or request-specific state there.
|
|
506
|
+
The library does not define application domains, ports, or branding.
|
|
507
|
+
|
|
508
|
+
`utils/http` contains the Node request/response adapter; `utils/assets` contains
|
|
509
|
+
manifest/preload helpers; `utils/responses` contains response normalization.
|
|
510
|
+
Keep the first two in server/build entrypoints. Browser application imports do
|
|
511
|
+
not include them.
|
|
512
|
+
|
|
513
|
+
### Virtual modules and entrypoints
|
|
514
|
+
|
|
515
|
+
`virtual:smolter/routes` is the default route-array export generated by the Vite
|
|
516
|
+
plugin from `src/routes`. It is not a physical file or a runtime package.
|
|
517
|
+
The server build retains loaders/actions; the browser build strips their
|
|
518
|
+
re-exports and installs server proxies. `entry.client.tsx` and `entry.server.tsx`
|
|
519
|
+
are application-owned files wiring those manifests to hydration and SSR.
|
|
520
|
+
Manual tables can be imported directly instead.
|
|
521
|
+
|
|
522
|
+
See the [virtual routes guide](https://kasperrt.github.io/smolter/react/docs/virtual-routes)
|
|
523
|
+
for the exact contract, TypeScript declaration, and both entrypoint examples.
|
|
524
|
+
|
|
525
|
+
### Express hosting
|
|
526
|
+
|
|
527
|
+
Keep Express in control of metrics, tracing, authentication and static files.
|
|
528
|
+
Mount `createRequestHandler({ build, entry })` from
|
|
529
|
+
`@kasperrt/smolter/utils/http` after those middleware. `build` is the compiled
|
|
530
|
+
server entry and `entry` is the browser entry URL from Vite's manifest. Do not
|
|
531
|
+
consume request bodies with Express body parsers before this handler.
|
|
532
|
+
The adapter has no Express dependency and forwards failures to `next(error)`.
|
|
533
|
+
|
|
534
|
+
See the [Express guide](https://kasperrt.github.io/smolter/react/docs/express)
|
|
535
|
+
for a complete server example and current buffering limitations.
|
|
536
|
+
|
|
537
|
+
## Resource subscriptions
|
|
538
|
+
|
|
539
|
+
`@kasperrt/smolter/react/data` adds subscriptions to named resources when their
|
|
540
|
+
lifetime is independent of URL navigation. The state and cancellation logic
|
|
541
|
+
lives in core; the entry adds React bindings without DOM or HTTP globals.
|
|
542
|
+
|
|
543
|
+
```ts
|
|
544
|
+
import { createResourceRouter } from "@kasperrt/smolter/react/data";
|
|
545
|
+
|
|
546
|
+
const resources = createResourceRouter(new Map([
|
|
547
|
+
["settings", {
|
|
548
|
+
loader: async ({ signal }) => ({
|
|
549
|
+
data: await readSettings(signal),
|
|
550
|
+
error: "",
|
|
551
|
+
}),
|
|
552
|
+
action: async ({ input, signal }) => ({
|
|
553
|
+
data: await saveSettings(input, signal),
|
|
554
|
+
error: "",
|
|
555
|
+
}),
|
|
556
|
+
}],
|
|
557
|
+
]));
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
`ResourceProvider` owns the store lifetime. `Resource` selects a resource by
|
|
561
|
+
`routeId` and params. `useResourceData` reads it; `useRouteLoaderData` reads a
|
|
562
|
+
named resource. `useResourceFetcher` returns `[state, operations]`, with
|
|
563
|
+
independent `load` and `submit` operations. Successful mutations consult the
|
|
564
|
+
resource's `shouldRevalidate` before reloading its data. Last-subscriber cleanup
|
|
565
|
+
aborts pending work; `persistent` keeps a resource until explicitly disposed.
|
|
566
|
+
This optional entry does not contribute to the base React bundle measurement.
|
|
415
567
|
|
|
416
568
|
## Size and checks
|
|
417
569
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
570
|
+
Use `createRouter` for navigation only, or `createDataRouter` for loaders,
|
|
571
|
+
actions, fetchers and revalidation. Both are named exports from
|
|
572
|
+
`@kasperrt/smolter/preact` and `/react`. No extra package or plugin is required.
|
|
573
|
+
The production bundler can remove the data engine when only `createRouter` is used.
|
|
574
|
+
|
|
575
|
+
`pnpm size` regenerates this table and the site's size data using identical
|
|
576
|
+
minifiers. The routing-only gate compares our selected exports with wouter's
|
|
577
|
+
routing subset: `Router`, `Route`, `Switch`, `Link`, `useParams`, and `useLocation`.
|
|
578
|
+
Both complete wouter entries are reported too. The APIs differ; this is not
|
|
579
|
+
a claim of identical features.
|
|
423
580
|
|
|
424
581
|
<!-- size-comparison:start -->
|
|
425
582
|
| Browser exports | Gzip bytes |
|
|
426
583
|
| --- | ---: |
|
|
427
|
-
|
|
|
428
|
-
|
|
|
429
|
-
| `@kasperrt/smolter/react
|
|
430
|
-
| `@kasperrt/smolter/preact
|
|
584
|
+
| `React: routing-only named exports` | 1245 |
|
|
585
|
+
| `Preact: routing-only named exports` | 1405 |
|
|
586
|
+
| `@kasperrt/smolter/react` | 2873 |
|
|
587
|
+
| `@kasperrt/smolter/preact` | 4748 |
|
|
588
|
+
| `@kasperrt/smolter/react + @kasperrt/smolter/react/client` | 3219 |
|
|
589
|
+
| `@kasperrt/smolter/preact + server transport` | 5059 |
|
|
590
|
+
| `@kasperrt/smolter/preact + client + document (application without lazy routes)` | 7415 |
|
|
591
|
+
| `@kasperrt/smolter/preact + client + document + lazy-route (file-routed application)` | 7696 |
|
|
592
|
+
| `@kasperrt/smolter/react/data (optional resource API)` | 2962 |
|
|
593
|
+
| `React: common routing/data exports` | 2683 |
|
|
594
|
+
| `Preact: common routing/data exports` | 2966 |
|
|
595
|
+
| `wouter: routing subset (Router, Route, Switch, Link, useParams, useLocation)` | 2854 |
|
|
596
|
+
| `wouter-preact: same routing subset` | 2211 |
|
|
431
597
|
| `wouter@3.13.0` | 3091 |
|
|
432
598
|
| `wouter-preact@3.13.0` | 2450 |
|
|
433
599
|
| `react-router@8.4.0` | 60994 |
|
|
434
600
|
<!-- size-comparison:end -->
|
|
435
601
|
|
|
436
|
-
The
|
|
602
|
+
The common-export rows measure the same named API set: `createDataRouter`,
|
|
603
|
+
`defineRoute`, `RouterProvider`, `Routes`, `Link`, `Form`, `useRouter`,
|
|
604
|
+
`useLoaderData`, `useActionData`, `useParams`, `useLocation`,
|
|
605
|
+
`useRevalidator` and `useFetcher`. Preact’s link and submission APIs currently
|
|
606
|
+
have additional behavior; equal names do not imply identical implementations.
|
|
607
|
+
The routing-only rows retain `createRouter`, `defineRoute`, `RouterProvider`,
|
|
608
|
+
`Routes`, `Link`, `useParams` and `useLocation`. Full Preact also exposes richer
|
|
609
|
+
application APIs. These tiers overlap: do not add the rows together.
|
|
610
|
+
|
|
611
|
+
The table is generated by `pnpm size` from the named subsets above or all exports of each other listed entry,
|
|
437
612
|
using production ESM bundles, esbuild, Terser, and gzip level 9. React, React DOM,
|
|
438
613
|
and Preact are external in every bundle. Transitive library dependencies are
|
|
439
614
|
included. React Router provides a broader API; this compares complete entry
|
|
440
615
|
sizes, not equivalent feature sets or the minimum code for one route.
|
|
441
|
-
`@kasperrt/smolter/client` adds browser transport for server loaders/actions; server-only
|
|
616
|
+
`@kasperrt/smolter/react/client` adds browser transport for server loaders/actions; server-only
|
|
442
617
|
rendering code and the Vite plugin are not shipped to the browser.
|
|
443
618
|
|
|
619
|
+
### Routing without data hooks
|
|
620
|
+
|
|
621
|
+
```tsx
|
|
622
|
+
import { render } from "preact";
|
|
623
|
+
import {
|
|
624
|
+
createRouter,
|
|
625
|
+
defineRoute,
|
|
626
|
+
Link,
|
|
627
|
+
RouterProvider,
|
|
628
|
+
Routes,
|
|
629
|
+
} from "@kasperrt/smolter/preact";
|
|
630
|
+
import Home from "./routes/home";
|
|
631
|
+
import About from "./routes/about";
|
|
632
|
+
|
|
633
|
+
const router = createRouter([
|
|
634
|
+
defineRoute("/", { default: Home }),
|
|
635
|
+
defineRoute("/about", { default: About }),
|
|
636
|
+
], { browser: true });
|
|
637
|
+
|
|
638
|
+
render(
|
|
639
|
+
<RouterProvider router={router}>
|
|
640
|
+
<nav>
|
|
641
|
+
<Link href="/">Home</Link>
|
|
642
|
+
<Link href="/about">About</Link>
|
|
643
|
+
</nav>
|
|
644
|
+
<Routes />
|
|
645
|
+
</RouterProvider>,
|
|
646
|
+
document.getElementById("app")!,
|
|
647
|
+
);
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
Add `useParams` for dynamic paths such as `/tasks/:id` and `useLocation` for
|
|
651
|
+
the current URL. Both are included in the routing-only measurement, even though
|
|
652
|
+
this example does not need them. Switch the factory to `createDataRouter` when
|
|
653
|
+
adding loaders, actions or fetchers, importing it from the same entry. SSR hydration and file-routed applications use the
|
|
654
|
+
larger client/document/lazy-route tier; they are not represented by the routing-only number.
|
|
655
|
+
|
|
444
656
|
Exact current measurements are generated in
|
|
445
|
-
[`packages/ui/src/size.json`](
|
|
657
|
+
[`packages/ui/src/size.json`](./packages/ui/src/size.json).
|
|
446
658
|
|
|
447
659
|
```sh
|
|
448
660
|
pnpm fix # Formatting
|
|
@@ -466,6 +678,8 @@ PRs. [Release workflow](https://github.com/kasperrt/smolter/blob/main/RELEASING.
|
|
|
466
678
|
To test a local package build in another project:
|
|
467
679
|
|
|
468
680
|
```sh
|
|
469
|
-
pnpm
|
|
681
|
+
pnpm pack
|
|
470
682
|
pnpm add /absolute/path/to/kasperrt-smolter-0.0.1.tgz
|
|
471
683
|
```
|
|
684
|
+
|
|
685
|
+
Workspace structure and rendering checks are documented in [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region .generated/client/deserialize.ts
|
|
2
|
+
/** Restore a trusted snapshot produced by @kasperrt/smolter/server serialize, including its route error. */
|
|
3
|
+
function deserialize(json) {
|
|
4
|
+
const snapshot = JSON.parse(json);
|
|
5
|
+
const error = snapshot.error;
|
|
6
|
+
if (error) snapshot.error = Object.assign(new Error(error.message), { name: error.name });
|
|
7
|
+
return snapshot;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { deserialize };
|
|
@@ -7,6 +7,7 @@ export type { ClientActionArgs, ClientLoaderArgs } from "../core/index.ts";
|
|
|
7
7
|
export { deserialize } from "./deserialize.ts";
|
|
8
8
|
/** Browser-safe route exports, excluding server implementation code. */
|
|
9
9
|
export interface ClientRouteModule {
|
|
10
|
+
id?: string;
|
|
10
11
|
default?: unknown;
|
|
11
12
|
HydrateFallback?: unknown;
|
|
12
13
|
ErrorBoundary?: unknown;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { deserialize } from "./deserialize.js";
|
|
2
|
+
//#region .generated/client/index.ts
|
|
3
|
+
/** Browser transport for server routes. File-router builds generate this call. */
|
|
4
|
+
function serverRoute(path, module, handlers = {
|
|
5
|
+
loader: true,
|
|
6
|
+
action: true
|
|
7
|
+
}) {
|
|
8
|
+
const remote = async ({ request, signal }) => {
|
|
9
|
+
const url = new URL(request.url);
|
|
10
|
+
const response = await fetch(`/_smolter?url=${encodeURIComponent(url.pathname + url.search)}`, {
|
|
11
|
+
method: request.method,
|
|
12
|
+
signal,
|
|
13
|
+
...request.method !== "GET" && { body: await request.formData() }
|
|
14
|
+
});
|
|
15
|
+
const location = response.headers.get("X-Smolter-Redirect");
|
|
16
|
+
if (location) return new Response(null, {
|
|
17
|
+
status: 303,
|
|
18
|
+
headers: { Location: location }
|
|
19
|
+
});
|
|
20
|
+
const data = await response.json();
|
|
21
|
+
if (!response.ok) return new Error(data.error ?? "Route request failed");
|
|
22
|
+
return data;
|
|
23
|
+
};
|
|
24
|
+
return {
|
|
25
|
+
...module,
|
|
26
|
+
path,
|
|
27
|
+
...handlers.loader && { loader: remote },
|
|
28
|
+
...handlers.action && { action: remote },
|
|
29
|
+
...module.clientLoader && { clientLoader: (args) => module.clientLoader({
|
|
30
|
+
...args,
|
|
31
|
+
serverLoader: () => remote(args)
|
|
32
|
+
}) },
|
|
33
|
+
...module.clientAction && { clientAction: (args) => {
|
|
34
|
+
const request = args.request.clone();
|
|
35
|
+
return module.clientAction({
|
|
36
|
+
...args,
|
|
37
|
+
serverAction: () => remote({
|
|
38
|
+
...args,
|
|
39
|
+
request: request.clone()
|
|
40
|
+
})
|
|
41
|
+
});
|
|
42
|
+
} }
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { deserialize, serverRoute };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ApplicationEnvironment {
|
|
2
|
+
resolveURL?: (url: URL) => URL;
|
|
3
|
+
isDocumentHandoff?: (from: URL, to: URL) => boolean;
|
|
4
|
+
leaveDocument?: (destination: URL) => void;
|
|
5
|
+
entryScript?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare let applicationEnvironment: ApplicationEnvironment | undefined;
|
|
8
|
+
/** Configure deployment-specific navigation before rendering or mounting. */
|
|
9
|
+
export declare function configureApplication(environment: ApplicationEnvironment): void;
|
|
10
|
+
export declare function resolveApplicationURL(url: URL): URL;
|
|
11
|
+
export declare function handoffDocument(event: MouseEvent, destination: URL): void;
|
|
12
|
+
export declare function leaveDocument(destination: URL): void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region .generated/core/environment.ts
|
|
2
|
+
var applicationEnvironment;
|
|
3
|
+
/** Configure deployment-specific navigation before rendering or mounting. */
|
|
4
|
+
function configureApplication(environment) {
|
|
5
|
+
applicationEnvironment = environment;
|
|
6
|
+
}
|
|
7
|
+
function resolveApplicationURL(url) {
|
|
8
|
+
return applicationEnvironment?.resolveURL?.(url) ?? url;
|
|
9
|
+
}
|
|
10
|
+
function handoffDocument(event, destination) {
|
|
11
|
+
if (!applicationEnvironment?.isDocumentHandoff?.(new URL(location.href), destination)) return;
|
|
12
|
+
event.preventDefault();
|
|
13
|
+
leaveDocument(destination);
|
|
14
|
+
}
|
|
15
|
+
function leaveDocument(destination) {
|
|
16
|
+
if (applicationEnvironment?.leaveDocument) {
|
|
17
|
+
applicationEnvironment.leaveDocument(destination);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
location.assign(destination.href);
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { applicationEnvironment, configureApplication, handoffDocument, leaveDocument, resolveApplicationURL };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region .generated/core/errors.ts
|
|
2
|
+
/** Resolve returned or rejected errors into Error values without losing their cause. */
|
|
3
|
+
function safeWrapAsync(work) {
|
|
4
|
+
return Promise.resolve().then(work).then((data) => data instanceof Error ? { error: data } : { data }, (cause) => ({ error: Error(String(cause), { cause }) }));
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
7
|
+
export { safeWrapAsync };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/** Framework-independent data routing. @module */
|
|
2
2
|
export * from "./errors.ts";
|
|
3
3
|
export * from "./match.ts";
|
|
4
|
+
export * from "./navigation-router.ts";
|
|
4
5
|
export * from "./router.ts";
|
|
6
|
+
export * from "./serialize.ts";
|
|
5
7
|
export * from "./types.ts";
|
|
6
8
|
export * from "./url.ts";
|