@kasperrt/smolter 0.0.1 → 0.2.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/README.md +47 -25
- package/dist/internal/core/index.d.ts +1 -0
- package/dist/internal/core/index.js +1 -0
- package/dist/internal/core/serialize.d.ts +3 -0
- package/dist/internal/core/serialize.js +13 -0
- package/dist/internal/server/index.d.ts +2 -3
- package/dist/internal/server/index.js +1 -13
- package/dist/internal/vite/index.d.ts +2 -1
- package/dist/internal/vite/index.js +3 -3
- package/dist/internal/vite/transport.d.ts +1 -1
- package/dist/internal/vite/transport.js +2 -2
- package/dist/preact-client.d.ts +2 -0
- package/dist/preact-client.js +2 -0
- package/dist/preact-server.d.ts +2 -0
- package/dist/preact-server.js +2 -0
- package/dist/preact-vite.d.ts +9 -0
- package/dist/preact-vite.js +9 -0
- package/dist/react-client.d.ts +2 -0
- package/dist/react-client.js +2 -0
- package/dist/react-server.d.ts +2 -0
- package/dist/react-server.js +2 -0
- package/dist/react-vite.d.ts +9 -0
- package/dist/react-vite.js +9 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +5 -0
- package/jsr.json +13 -8
- package/package.json +27 -26
- package/src/internal/core/index.ts +1 -0
- package/src/internal/core/serialize.ts +15 -0
- package/src/internal/server/index.ts +1 -14
- package/src/internal/vite/index.ts +4 -2
- package/src/internal/vite/transport.ts +2 -1
- package/src/preact-client.ts +2 -0
- package/src/preact-server.ts +2 -0
- package/src/preact-vite.ts +18 -0
- package/src/react-client.ts +2 -0
- package/src/react-server.ts +2 -0
- package/src/react-vite.ts +18 -0
- package/src/utils.ts +5 -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.2.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.2.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)
|
|
@@ -49,10 +53,10 @@ pnpm dev
|
|
|
49
53
|
|
|
50
54
|
| App | Open | Data |
|
|
51
55
|
| --- | --- | --- |
|
|
52
|
-
| [React SPA](
|
|
53
|
-
| [Preact SPA](
|
|
54
|
-
| [React SSR](
|
|
55
|
-
| [Preact SSR](
|
|
56
|
+
| [React SPA](./apps/react) | http://127.0.0.1:5173 | Client loaders/actions, localStorage |
|
|
57
|
+
| [Preact SPA](./apps/preact) | http://127.0.0.1:5174 | Client loaders/actions, localStorage |
|
|
58
|
+
| [React SSR](./apps/react-ssr) | http://127.0.0.1:5175 | Server loaders/actions, hydration |
|
|
59
|
+
| [Preact SSR](./apps/preact-ssr) | http://127.0.0.1:5176 | Server loaders/actions, hydration |
|
|
56
60
|
|
|
57
61
|
Each app has its own entrypoints, routes, and data code. Only UI components are
|
|
58
62
|
shared. Preact examples do not import React. Each includes:
|
|
@@ -81,7 +85,7 @@ or filename parser enters the browser bundle.
|
|
|
81
85
|
```ts
|
|
82
86
|
// vite.config.ts
|
|
83
87
|
import { defineConfig } from "vite";
|
|
84
|
-
import { fileRouter } from "@kasperrt/smolter/vite";
|
|
88
|
+
import { fileRouter } from "@kasperrt/smolter/react/vite";
|
|
85
89
|
|
|
86
90
|
export default defineConfig({
|
|
87
91
|
plugins: [fileRouter({ directory: "src/routes" })],
|
|
@@ -121,12 +125,12 @@ For the virtual module, add this declaration to your app:
|
|
|
121
125
|
// env.d.ts
|
|
122
126
|
// Include vite/client in your tsconfig types as usual.
|
|
123
127
|
declare module "virtual:smolter/routes" {
|
|
124
|
-
const routes: import("@kasperrt/smolter/
|
|
128
|
+
const routes: import("@kasperrt/smolter/react").Route[];
|
|
125
129
|
export default routes;
|
|
126
130
|
}
|
|
127
131
|
```
|
|
128
132
|
|
|
129
|
-
Outside Vite, `flatRoutes(directory)` from `@kasperrt/smolter/
|
|
133
|
+
Outside Vite, `flatRoutes(directory)` from `@kasperrt/smolter/react/vite` returns
|
|
130
134
|
`{ path, file }[] | Error` for your build tool to turn into imports.
|
|
131
135
|
|
|
132
136
|
### Manual routes
|
|
@@ -184,7 +188,7 @@ With the optional server integration:
|
|
|
184
188
|
|
|
185
189
|
```ts
|
|
186
190
|
// client-loader.ts
|
|
187
|
-
import type { ClientLoaderArgs } from "@kasperrt/smolter/client";
|
|
191
|
+
import type { ClientLoaderArgs } from "@kasperrt/smolter/react/client";
|
|
188
192
|
import type { loader } from "./loader";
|
|
189
193
|
|
|
190
194
|
export async function clientLoader({ serverLoader }: ClientLoaderArgs<typeof loader>) {
|
|
@@ -194,7 +198,7 @@ export async function clientLoader({ serverLoader }: ClientLoaderArgs<typeof loa
|
|
|
194
198
|
|
|
195
199
|
```ts
|
|
196
200
|
// client-action.ts
|
|
197
|
-
import type { ClientActionArgs } from "@kasperrt/smolter/client";
|
|
201
|
+
import type { ClientActionArgs } from "@kasperrt/smolter/react/client";
|
|
198
202
|
import type { action } from "./action";
|
|
199
203
|
|
|
200
204
|
export async function clientAction({ serverAction }: ClientActionArgs<typeof action>) {
|
|
@@ -234,17 +238,17 @@ in a client bundle. Type-only imports from server handlers are safe. Do not
|
|
|
234
238
|
import server code directly into client views or client handlers.
|
|
235
239
|
|
|
236
240
|
The Vite dev plugin mounts `/_smolter?url=...`. Production hosts dispatch that
|
|
237
|
-
endpoint through `handleRequest(routes, request)` from `@kasperrt/smolter/server`, using
|
|
241
|
+
endpoint through `handleRequest(routes, request)` from `@kasperrt/smolter/react/server`, using
|
|
238
242
|
the requested route URL. Both SSR examples include a working host. The host
|
|
239
243
|
owns authentication, session cookies, HTTP policy, and deployment.
|
|
240
244
|
|
|
241
245
|
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
|
|
246
|
+
from `@kasperrt/smolter/react/client` in the browser and `defineRoute` on the server. This keeps
|
|
243
247
|
the type connection without importing server code at runtime. To use manual
|
|
244
248
|
tables with the dev transport:
|
|
245
249
|
|
|
246
250
|
```ts
|
|
247
|
-
import { routerPlugin } from "@kasperrt/smolter/vite";
|
|
251
|
+
import { routerPlugin } from "@kasperrt/smolter/react/vite";
|
|
248
252
|
|
|
249
253
|
routerPlugin({
|
|
250
254
|
clientRoutes: "src/manual-browser-routes.ts",
|
|
@@ -366,7 +370,7 @@ remount the fallback during revalidation. Return a `Response` with a `Location`
|
|
|
366
370
|
## Server rendering
|
|
367
371
|
|
|
368
372
|
```tsx
|
|
369
|
-
import { loadRouter, serialize } from "@kasperrt/smolter/server";
|
|
373
|
+
import { loadRouter, serialize } from "@kasperrt/smolter/react/server";
|
|
370
374
|
|
|
371
375
|
const router = await loadRouter(routes, incomingRequest);
|
|
372
376
|
const html = renderToString(
|
|
@@ -376,13 +380,13 @@ const hydrationJSON = serialize(router.getSnapshot());
|
|
|
376
380
|
```
|
|
377
381
|
|
|
378
382
|
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
|
|
383
|
+
script, restore it with `deserialize` from `@kasperrt/smolter/react/client`, and pass it as
|
|
380
384
|
`hydrationData` to `createRouter`. This preserves loader errors through hydration
|
|
381
385
|
without exposing server stacks or causes. Error boundaries should display the
|
|
382
386
|
error message, not its stack.
|
|
383
387
|
|
|
384
388
|
```ts
|
|
385
|
-
import { deserialize } from "@kasperrt/smolter/client";
|
|
389
|
+
import { deserialize } from "@kasperrt/smolter/react/client";
|
|
386
390
|
import { createRouter } from "@kasperrt/smolter/react";
|
|
387
391
|
import routes from "virtual:smolter/routes";
|
|
388
392
|
|
|
@@ -403,15 +407,31 @@ The SSR examples use the same server route definitions for HTML and data request
|
|
|
403
407
|
## Package entries
|
|
404
408
|
|
|
405
409
|
Use `@kasperrt/smolter/react` for React 18+ and `@kasperrt/smolter/preact` for Preact 10.25+.
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
410
|
+
Choose one renderer for your application. Both expose the same routing API:
|
|
411
|
+
|
|
412
|
+
| Purpose | React | Preact |
|
|
413
|
+
| --- | --- | --- |
|
|
414
|
+
| Components, hooks, router, data types | `@kasperrt/smolter/react` | `@kasperrt/smolter/preact` |
|
|
415
|
+
| Optional browser transport | `@kasperrt/smolter/react/client` | `@kasperrt/smolter/preact/client` |
|
|
416
|
+
| SSR and HTTP data dispatch | `@kasperrt/smolter/react/server` | `@kasperrt/smolter/preact/server` |
|
|
417
|
+
| Vite plugin and flat-file discovery | `@kasperrt/smolter/react/vite` | `@kasperrt/smolter/preact/vite` |
|
|
418
|
+
|
|
419
|
+
`@kasperrt/smolter/utils` contains browser-safe matching and error helpers.
|
|
420
|
+
The main renderer entries never import server or build modules. Named imports
|
|
421
|
+
are tree-shaken; optional transport is included only when you import `/client`.
|
|
422
|
+
Server entries do not import either UI renderer. Vite entries are build-time only.
|
|
423
|
+
|
|
424
|
+
**Migrating to 0.2.0:** replace `/core` imports for types, `createRouter`, and
|
|
425
|
+
`defineRoute` with your renderer entry. Use `/utils` for `matchRoutes`,
|
|
426
|
+
`internalURL` and `safeWrapAsync`. Move `/client`, `/server`,
|
|
427
|
+
`/files`, and `/vite` imports to the corresponding renderer-prefixed path above.
|
|
428
|
+
The bare package root and old top-level subpaths are no longer exported.
|
|
409
429
|
|
|
410
430
|
On JSR, install `@kasperrt/smolter` using the
|
|
411
431
|
[JSR package instructions](https://jsr.io/docs/npm-compatibility) and import
|
|
412
432
|
`@kasperrt/smolter/react` or `@kasperrt/smolter/preact`. Its `core`, `client`,
|
|
413
433
|
`server`, and `files` subpaths match npm. The Vite plugin is npm-only:
|
|
414
|
-
use `@kasperrt/smolter/vite` from the npm package when adding file routing.
|
|
434
|
+
use `@kasperrt/smolter/react/vite` from the npm package when adding file routing.
|
|
415
435
|
|
|
416
436
|
## Size and checks
|
|
417
437
|
|
|
@@ -426,8 +446,8 @@ example labels. File discovery is build-only.
|
|
|
426
446
|
| --- | ---: |
|
|
427
447
|
| `@kasperrt/smolter/react` | 2445 |
|
|
428
448
|
| `@kasperrt/smolter/preact` | 2445 |
|
|
429
|
-
| `@kasperrt/smolter/react + @kasperrt/smolter/client` | 2782 |
|
|
430
|
-
| `@kasperrt/smolter/preact + @kasperrt/smolter/client` | 2781 |
|
|
449
|
+
| `@kasperrt/smolter/react + @kasperrt/smolter/react/client` | 2782 |
|
|
450
|
+
| `@kasperrt/smolter/preact + @kasperrt/smolter/preact/client` | 2781 |
|
|
431
451
|
| `wouter@3.13.0` | 3091 |
|
|
432
452
|
| `wouter-preact@3.13.0` | 2450 |
|
|
433
453
|
| `react-router@8.4.0` | 60994 |
|
|
@@ -438,11 +458,11 @@ using production ESM bundles, esbuild, Terser, and gzip level 9. React, React DO
|
|
|
438
458
|
and Preact are external in every bundle. Transitive library dependencies are
|
|
439
459
|
included. React Router provides a broader API; this compares complete entry
|
|
440
460
|
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
|
|
461
|
+
`@kasperrt/smolter/react/client` adds browser transport for server loaders/actions; server-only
|
|
442
462
|
rendering code and the Vite plugin are not shipped to the browser.
|
|
443
463
|
|
|
444
464
|
Exact current measurements are generated in
|
|
445
|
-
[`packages/ui/src/size.json`](
|
|
465
|
+
[`packages/ui/src/size.json`](./packages/ui/src/size.json).
|
|
446
466
|
|
|
447
467
|
```sh
|
|
448
468
|
pnpm fix # Formatting
|
|
@@ -469,3 +489,5 @@ To test a local package build in another project:
|
|
|
469
489
|
pnpm --dir packages/smolter pack --pack-destination ../..
|
|
470
490
|
pnpm add /absolute/path/to/kasperrt-smolter-0.0.1.tgz
|
|
471
491
|
```
|
|
492
|
+
|
|
493
|
+
Workspace structure and rendering checks are documented in [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Safe inside a script element. Data must be JSON serializable; error stacks and causes are omitted. */
|
|
2
|
+
export function serialize(snapshot) {
|
|
3
|
+
return JSON.stringify({
|
|
4
|
+
...snapshot,
|
|
5
|
+
error: snapshot.error && {
|
|
6
|
+
name: snapshot.error.name,
|
|
7
|
+
message: snapshot.error.message,
|
|
8
|
+
},
|
|
9
|
+
})
|
|
10
|
+
.replace(/</g, "\\u003c")
|
|
11
|
+
.replace(/\u2028/g, "\\u2028")
|
|
12
|
+
.replace(/\u2029/g, "\\u2029");
|
|
13
|
+
}
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
* Request-scoped server rendering and HTTP data dispatch.
|
|
3
3
|
* @module
|
|
4
4
|
*/
|
|
5
|
-
import { type Route, type Router
|
|
5
|
+
import { type Route, type Router } from "../core/index.ts";
|
|
6
6
|
/** Create one router per server request, await this, then render the provider. */
|
|
7
7
|
export declare function loadRouter(routes: readonly Route[], input: string | Request): Promise<Router>;
|
|
8
|
-
|
|
9
|
-
export declare function serialize(snapshot: Snapshot): string;
|
|
8
|
+
export { serialize } from "../core/index.ts";
|
|
10
9
|
/** Dispatch an HTTP data request to a registered server loader or action. */
|
|
11
10
|
export declare function handleRequest(routes: readonly Route[], request: Request): Promise<Response>;
|
|
@@ -39,19 +39,7 @@ export async function loadRouter(routes, input) {
|
|
|
39
39
|
}
|
|
40
40
|
return router;
|
|
41
41
|
}
|
|
42
|
-
|
|
43
|
-
export function serialize(snapshot) {
|
|
44
|
-
return JSON.stringify({
|
|
45
|
-
...snapshot,
|
|
46
|
-
error: snapshot.error && {
|
|
47
|
-
name: snapshot.error.name,
|
|
48
|
-
message: snapshot.error.message,
|
|
49
|
-
},
|
|
50
|
-
})
|
|
51
|
-
.replace(/</g, "\\u003c")
|
|
52
|
-
.replace(/\u2028/g, "\\u2028")
|
|
53
|
-
.replace(/\u2029/g, "\\u2029");
|
|
54
|
-
}
|
|
42
|
+
export { serialize } from "../core/index.js";
|
|
55
43
|
/** Dispatch an HTTP data request to a registered server loader or action. */
|
|
56
44
|
export async function handleRequest(routes, request) {
|
|
57
45
|
const match = matchRoutes(routes, new URL(request.url).pathname);
|
|
@@ -3,8 +3,9 @@ export interface FileRouterOptions {
|
|
|
3
3
|
directory?: string;
|
|
4
4
|
clientRoutes?: string;
|
|
5
5
|
serverRoutes?: string;
|
|
6
|
+
framework?: "react" | "preact";
|
|
6
7
|
}
|
|
7
8
|
/** Build-time flat route discovery and the optional server data transport. */
|
|
8
|
-
export declare function routerPlugin({ directory, clientRoutes, serverRoutes, }?: FileRouterOptions): Plugin;
|
|
9
|
+
export declare function routerPlugin({ directory, clientRoutes, serverRoutes, framework, }?: FileRouterOptions): Plugin;
|
|
9
10
|
/** File routing is the default; this alias keeps configuration explicit. */
|
|
10
11
|
export declare const fileRouter: typeof routerPlugin;
|
|
@@ -4,7 +4,7 @@ import { flatRoutes } from "../files/index.js";
|
|
|
4
4
|
import { transformWithOxc } from "vite";
|
|
5
5
|
import { configureTransport } from "./transport.js";
|
|
6
6
|
/** Build-time flat route discovery and the optional server data transport. */
|
|
7
|
-
export function routerPlugin({ directory = "src/routes", clientRoutes, serverRoutes, } = {}) {
|
|
7
|
+
export function routerPlugin({ directory = "src/routes", clientRoutes, serverRoutes, framework = "react", } = {}) {
|
|
8
8
|
let root;
|
|
9
9
|
let projectRoot;
|
|
10
10
|
const publicId = "virtual:smolter/routes";
|
|
@@ -103,7 +103,7 @@ export function routerPlugin({ directory = "src/routes", clientRoutes, serverRou
|
|
|
103
103
|
}
|
|
104
104
|
if (!options?.ssr &&
|
|
105
105
|
definitions.some((definition) => definition.startsWith("serverRoute(")))
|
|
106
|
-
imports.unshift(
|
|
106
|
+
imports.unshift(`import { serverRoute } from "@kasperrt/smolter/${framework}/client";`);
|
|
107
107
|
return `${imports.join("\n")}\nexport default [${definitions.join(",\n")}];\n`;
|
|
108
108
|
},
|
|
109
109
|
configureServer(server) {
|
|
@@ -124,7 +124,7 @@ export function routerPlugin({ directory = "src/routes", clientRoutes, serverRou
|
|
|
124
124
|
server.watcher.off("change", refresh);
|
|
125
125
|
server.watcher.off("unlink", refresh);
|
|
126
126
|
});
|
|
127
|
-
configureTransport(server, publicId);
|
|
127
|
+
configureTransport(server, publicId, framework);
|
|
128
128
|
},
|
|
129
129
|
};
|
|
130
130
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { ViteDevServer } from "vite";
|
|
2
|
-
export declare function configureTransport(server: ViteDevServer, publicId: string): void;
|
|
2
|
+
export declare function configureTransport(server: ViteDevServer, publicId: string, framework?: "react" | "preact"): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export function configureTransport(server, publicId) {
|
|
1
|
+
export function configureTransport(server, publicId, framework = "react") {
|
|
2
2
|
server.middlewares.use((incoming, outgoing, next) => {
|
|
3
3
|
if (!incoming.url?.startsWith("/_smolter?"))
|
|
4
4
|
return next();
|
|
@@ -30,7 +30,7 @@ export function configureTransport(server, publicId) {
|
|
|
30
30
|
});
|
|
31
31
|
const [{ default: routes }, { handleRequest }] = await Promise.all([
|
|
32
32
|
server.ssrLoadModule(publicId),
|
|
33
|
-
server.ssrLoadModule(
|
|
33
|
+
server.ssrLoadModule(`@kasperrt/smolter/${framework}/server`),
|
|
34
34
|
]);
|
|
35
35
|
const response = await handleRequest(routes, request);
|
|
36
36
|
outgoing.statusCode = response.status;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Optional flat-file routing for Preact builds. @module */
|
|
2
|
+
import type { Plugin } from "vite";
|
|
3
|
+
import { type FileRouterOptions } from "./internal/vite/index.ts";
|
|
4
|
+
export * from "./internal/files/index.ts";
|
|
5
|
+
export type { FileRouterOptions } from "./internal/vite/index.ts";
|
|
6
|
+
/** Configure flat routes and server transport for Preact. */
|
|
7
|
+
export declare function routerPlugin(options?: FileRouterOptions): Plugin;
|
|
8
|
+
/** File routing is the default; this alias keeps configuration explicit. */
|
|
9
|
+
export declare const fileRouter: typeof routerPlugin;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Optional flat-file routing for Preact builds. @module */
|
|
2
|
+
import { routerPlugin as createPlugin, } from "./internal/vite/index.js";
|
|
3
|
+
export * from "./internal/files/index.js";
|
|
4
|
+
/** Configure flat routes and server transport for Preact. */
|
|
5
|
+
export function routerPlugin(options = {}) {
|
|
6
|
+
return createPlugin({ ...options, framework: "preact" });
|
|
7
|
+
}
|
|
8
|
+
/** File routing is the default; this alias keeps configuration explicit. */
|
|
9
|
+
export const fileRouter = routerPlugin;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Optional flat-file routing for React builds. @module */
|
|
2
|
+
import type { Plugin } from "vite";
|
|
3
|
+
import { type FileRouterOptions } from "./internal/vite/index.ts";
|
|
4
|
+
export * from "./internal/files/index.ts";
|
|
5
|
+
export type { FileRouterOptions } from "./internal/vite/index.ts";
|
|
6
|
+
/** Configure flat routes and server transport for React. */
|
|
7
|
+
export declare function routerPlugin(options?: FileRouterOptions): Plugin;
|
|
8
|
+
/** File routing is the default; this alias keeps configuration explicit. */
|
|
9
|
+
export declare const fileRouter: typeof routerPlugin;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Optional flat-file routing for React builds. @module */
|
|
2
|
+
import { routerPlugin as createPlugin, } from "./internal/vite/index.js";
|
|
3
|
+
export * from "./internal/files/index.js";
|
|
4
|
+
/** Configure flat routes and server transport for React. */
|
|
5
|
+
export function routerPlugin(options = {}) {
|
|
6
|
+
return createPlugin({ ...options, framework: "react" });
|
|
7
|
+
}
|
|
8
|
+
/** File routing is the default; this alias keeps configuration explicit. */
|
|
9
|
+
export const fileRouter = routerPlugin;
|
package/dist/utils.d.ts
ADDED
package/dist/utils.js
ADDED
package/jsr.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kasperrt/smolter",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"exports": {
|
|
5
|
-
"
|
|
5
|
+
"./react": "./src/react.ts",
|
|
6
|
+
"./react/server": "./src/react-server.ts",
|
|
6
7
|
"./preact": "./src/preact.ts",
|
|
7
|
-
"./
|
|
8
|
-
"./
|
|
9
|
-
"./client": "./src/client.ts",
|
|
10
|
-
"./
|
|
11
|
-
"./react": "./src/react.ts"
|
|
8
|
+
"./preact/server": "./src/preact-server.ts",
|
|
9
|
+
"./react/client": "./src/react-client.ts",
|
|
10
|
+
"./preact/client": "./src/preact-client.ts",
|
|
11
|
+
"./utils": "./src/utils.ts"
|
|
12
12
|
},
|
|
13
13
|
"imports": {
|
|
14
14
|
"react": "npm:react@19.3.1",
|
|
@@ -16,7 +16,12 @@
|
|
|
16
16
|
},
|
|
17
17
|
"publish": {
|
|
18
18
|
"include": ["src", "README.md", "LICENSE", "jsr.json"],
|
|
19
|
-
"exclude": [
|
|
19
|
+
"exclude": [
|
|
20
|
+
"src/vite.ts",
|
|
21
|
+
"src/react-vite.ts",
|
|
22
|
+
"src/preact-vite.ts",
|
|
23
|
+
"src/internal/vite"
|
|
24
|
+
]
|
|
20
25
|
},
|
|
21
26
|
"license": "MIT",
|
|
22
27
|
"compatibility": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kasperrt/smolter",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A tiny typed data router for React and Preact.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -11,38 +11,41 @@
|
|
|
11
11
|
"directory": "packages/smolter"
|
|
12
12
|
},
|
|
13
13
|
"exports": {
|
|
14
|
-
"
|
|
15
|
-
"types": "./dist/
|
|
16
|
-
"import": "./dist/
|
|
14
|
+
"./react": {
|
|
15
|
+
"types": "./dist/react.d.ts",
|
|
16
|
+
"import": "./dist/react.js"
|
|
17
|
+
},
|
|
18
|
+
"./react/server": {
|
|
19
|
+
"types": "./dist/react-server.d.ts",
|
|
20
|
+
"import": "./dist/react-server.js"
|
|
21
|
+
},
|
|
22
|
+
"./react/vite": {
|
|
23
|
+
"types": "./dist/react-vite.d.ts",
|
|
24
|
+
"import": "./dist/react-vite.js"
|
|
17
25
|
},
|
|
18
26
|
"./preact": {
|
|
19
27
|
"types": "./dist/preact.d.ts",
|
|
20
28
|
"import": "./dist/preact.js"
|
|
21
29
|
},
|
|
22
|
-
"./
|
|
23
|
-
"types": "./dist/
|
|
24
|
-
"import": "./dist/
|
|
30
|
+
"./preact/server": {
|
|
31
|
+
"types": "./dist/preact-server.d.ts",
|
|
32
|
+
"import": "./dist/preact-server.js"
|
|
25
33
|
},
|
|
26
|
-
"./
|
|
27
|
-
"types": "./dist/
|
|
28
|
-
"import": "./dist/
|
|
34
|
+
"./preact/vite": {
|
|
35
|
+
"types": "./dist/preact-vite.d.ts",
|
|
36
|
+
"import": "./dist/preact-vite.js"
|
|
29
37
|
},
|
|
30
|
-
"./
|
|
31
|
-
"types": "./dist/
|
|
32
|
-
"import": "./dist/
|
|
38
|
+
"./react/client": {
|
|
39
|
+
"types": "./dist/react-client.d.ts",
|
|
40
|
+
"import": "./dist/react-client.js"
|
|
33
41
|
},
|
|
34
|
-
"./
|
|
35
|
-
"types": "./dist/
|
|
36
|
-
"import": "./dist/
|
|
42
|
+
"./preact/client": {
|
|
43
|
+
"types": "./dist/preact-client.d.ts",
|
|
44
|
+
"import": "./dist/preact-client.js"
|
|
37
45
|
},
|
|
38
|
-
"./
|
|
39
|
-
"types": "./dist/
|
|
40
|
-
"import": "./dist/
|
|
41
|
-
},
|
|
42
|
-
"./package.json": "./package.json",
|
|
43
|
-
"./react": {
|
|
44
|
-
"types": "./dist/react.d.ts",
|
|
45
|
-
"import": "./dist/react.js"
|
|
46
|
+
"./utils": {
|
|
47
|
+
"types": "./dist/utils.d.ts",
|
|
48
|
+
"import": "./dist/utils.js"
|
|
46
49
|
}
|
|
47
50
|
},
|
|
48
51
|
"files": [
|
|
@@ -87,8 +90,6 @@
|
|
|
87
90
|
"ssr",
|
|
88
91
|
"file-routing"
|
|
89
92
|
],
|
|
90
|
-
"main": "./dist/core.js",
|
|
91
|
-
"types": "./dist/core.d.ts",
|
|
92
93
|
"publishConfig": {
|
|
93
94
|
"access": "public",
|
|
94
95
|
"provenance": true
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Snapshot } from "./types.ts";
|
|
2
|
+
|
|
3
|
+
/** Safe inside a script element. Data must be JSON serializable; error stacks and causes are omitted. */
|
|
4
|
+
export function serialize(snapshot: Snapshot): string {
|
|
5
|
+
return JSON.stringify({
|
|
6
|
+
...snapshot,
|
|
7
|
+
error: snapshot.error && {
|
|
8
|
+
name: snapshot.error.name,
|
|
9
|
+
message: snapshot.error.message,
|
|
10
|
+
},
|
|
11
|
+
})
|
|
12
|
+
.replace(/</g, "\\u003c")
|
|
13
|
+
.replace(/\u2028/g, "\\u2028")
|
|
14
|
+
.replace(/\u2029/g, "\\u2029");
|
|
15
|
+
}
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
matchRoutes,
|
|
10
10
|
type Route,
|
|
11
11
|
type Router,
|
|
12
|
-
type Snapshot,
|
|
13
12
|
safeWrapAsync,
|
|
14
13
|
} from "../core/index.ts";
|
|
15
14
|
/** Create one router per server request, await this, then render the provider. */
|
|
@@ -61,19 +60,7 @@ export async function loadRouter(
|
|
|
61
60
|
|
|
62
61
|
return router;
|
|
63
62
|
}
|
|
64
|
-
|
|
65
|
-
export function serialize(snapshot: Snapshot): string {
|
|
66
|
-
return JSON.stringify({
|
|
67
|
-
...snapshot,
|
|
68
|
-
error: snapshot.error && {
|
|
69
|
-
name: snapshot.error.name,
|
|
70
|
-
message: snapshot.error.message,
|
|
71
|
-
},
|
|
72
|
-
})
|
|
73
|
-
.replace(/</g, "\\u003c")
|
|
74
|
-
.replace(/\u2028/g, "\\u2028")
|
|
75
|
-
.replace(/\u2029/g, "\\u2029");
|
|
76
|
-
}
|
|
63
|
+
export { serialize } from "../core/index.ts";
|
|
77
64
|
|
|
78
65
|
/** Dispatch an HTTP data request to a registered server loader or action. */
|
|
79
66
|
export async function handleRequest(
|
|
@@ -8,6 +8,7 @@ export interface FileRouterOptions {
|
|
|
8
8
|
directory?: string;
|
|
9
9
|
clientRoutes?: string;
|
|
10
10
|
serverRoutes?: string;
|
|
11
|
+
framework?: "react" | "preact";
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
/** Build-time flat route discovery and the optional server data transport. */
|
|
@@ -15,6 +16,7 @@ export function routerPlugin({
|
|
|
15
16
|
directory = "src/routes",
|
|
16
17
|
clientRoutes,
|
|
17
18
|
serverRoutes,
|
|
19
|
+
framework = "react",
|
|
18
20
|
}: FileRouterOptions = {}): Plugin {
|
|
19
21
|
let root: string;
|
|
20
22
|
let projectRoot: string;
|
|
@@ -173,7 +175,7 @@ export function routerPlugin({
|
|
|
173
175
|
definitions.some((definition) => definition.startsWith("serverRoute("))
|
|
174
176
|
)
|
|
175
177
|
imports.unshift(
|
|
176
|
-
|
|
178
|
+
`import { serverRoute } from "@kasperrt/smolter/${framework}/client";`,
|
|
177
179
|
);
|
|
178
180
|
|
|
179
181
|
return `${imports.join("\n")}\nexport default [${definitions.join(",\n")}];\n`;
|
|
@@ -201,7 +203,7 @@ export function routerPlugin({
|
|
|
201
203
|
server.watcher.off("unlink", refresh);
|
|
202
204
|
});
|
|
203
205
|
|
|
204
|
-
configureTransport(server, publicId);
|
|
206
|
+
configureTransport(server, publicId, framework);
|
|
205
207
|
},
|
|
206
208
|
};
|
|
207
209
|
}
|
|
@@ -3,6 +3,7 @@ import type { ViteDevServer } from "vite";
|
|
|
3
3
|
export function configureTransport(
|
|
4
4
|
server: ViteDevServer,
|
|
5
5
|
publicId: string,
|
|
6
|
+
framework: "react" | "preact" = "react",
|
|
6
7
|
): void {
|
|
7
8
|
server.middlewares.use((incoming, outgoing, next) => {
|
|
8
9
|
if (!incoming.url?.startsWith("/_smolter?")) return next();
|
|
@@ -43,7 +44,7 @@ export function configureTransport(
|
|
|
43
44
|
});
|
|
44
45
|
const [{ default: routes }, { handleRequest }] = await Promise.all([
|
|
45
46
|
server.ssrLoadModule(publicId),
|
|
46
|
-
server.ssrLoadModule(
|
|
47
|
+
server.ssrLoadModule(`@kasperrt/smolter/${framework}/server`),
|
|
47
48
|
]);
|
|
48
49
|
const response: Response = await handleRequest(routes, request);
|
|
49
50
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Optional flat-file routing for Preact builds. @module */
|
|
2
|
+
|
|
3
|
+
import type { Plugin } from "vite";
|
|
4
|
+
import {
|
|
5
|
+
routerPlugin as createPlugin,
|
|
6
|
+
type FileRouterOptions,
|
|
7
|
+
} from "./internal/vite/index.ts";
|
|
8
|
+
|
|
9
|
+
export * from "./internal/files/index.ts";
|
|
10
|
+
export type { FileRouterOptions } from "./internal/vite/index.ts";
|
|
11
|
+
|
|
12
|
+
/** Configure flat routes and server transport for Preact. */
|
|
13
|
+
export function routerPlugin(options: FileRouterOptions = {}): Plugin {
|
|
14
|
+
return createPlugin({ ...options, framework: "preact" });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** File routing is the default; this alias keeps configuration explicit. */
|
|
18
|
+
export const fileRouter = routerPlugin;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Optional flat-file routing for React builds. @module */
|
|
2
|
+
|
|
3
|
+
import type { Plugin } from "vite";
|
|
4
|
+
import {
|
|
5
|
+
routerPlugin as createPlugin,
|
|
6
|
+
type FileRouterOptions,
|
|
7
|
+
} from "./internal/vite/index.ts";
|
|
8
|
+
|
|
9
|
+
export * from "./internal/files/index.ts";
|
|
10
|
+
export type { FileRouterOptions } from "./internal/vite/index.ts";
|
|
11
|
+
|
|
12
|
+
/** Configure flat routes and server transport for React. */
|
|
13
|
+
export function routerPlugin(options: FileRouterOptions = {}): Plugin {
|
|
14
|
+
return createPlugin({ ...options, framework: "react" });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** File routing is the default; this alias keeps configuration explicit. */
|
|
18
|
+
export const fileRouter = routerPlugin;
|