@alxia/react-router 0.25.0 → 0.27.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 +36 -4
- package/dist/assets.d.ts +3 -1
- package/dist/assets.d.ts.map +1 -1
- package/dist/index.js +12 -8
- package/dist/index.js.map +5 -5
- package/dist/link/index.d.ts +7 -0
- package/dist/link/index.d.ts.map +1 -0
- package/dist/link/index.js +16 -0
- package/dist/link/index.js.map +10 -0
- package/dist/link/router-link.d.ts +27 -0
- package/dist/link/router-link.d.ts.map +1 -0
- package/dist/react-router.d.ts +8 -1
- package/dist/react-router.d.ts.map +1 -1
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/vite/compress.d.ts +18 -0
- package/dist/vite/compress.d.ts.map +1 -0
- package/dist/vite/index.d.ts +10 -0
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +93 -12
- package/dist/vite/index.js.map +5 -4
- package/docs/README.md +1 -0
- package/docs/guide/beside-the-pages.md +22 -0
- package/docs/guide/customising-the-server.md +2 -0
- package/docs/guide/how-it-works.md +6 -0
- package/docs/guide/link.md +32 -0
- package/docs/roadmap.md +6 -0
- package/docs/troubleshooting.md +26 -0
- package/package.json +12 -6
package/README.md
CHANGED
|
@@ -527,6 +527,16 @@ In a build, `build/client` is served before `configure`'s middlewares:
|
|
|
527
527
|
A missing asset gets alxia's JSON 404, not a page. In dev, Vite serves
|
|
528
528
|
these files.
|
|
529
529
|
|
|
530
|
+
`react-router build` also writes `.br` and `.gz` copies beside every
|
|
531
|
+
compressible file of the client build (JavaScript, CSS, HTML, SVG, JSON,
|
|
532
|
+
text, XML, web manifests, source maps, WebAssembly, icons, fonts) of at least 1 kB, and the server sends the one a
|
|
533
|
+
browser accepts, with `Content-Encoding` and `Vary: Accept-Encoding`, the
|
|
534
|
+
`Cache-Control` above unchanged. `alxia({ precompress: false })` writes none,
|
|
535
|
+
`alxia({ precompress: { minSize: 4096 } })` moves the threshold, and
|
|
536
|
+
`createServer({ precompressed: false })` (or `reactRouter(app, {
|
|
537
|
+
precompressed: false })`) serves the files as they are, behind a proxy that
|
|
538
|
+
compresses. [More](https://github.com/softistx/alxia/blob/develop/packages/react-router/docs/guide/beside-the-pages.md#compressed)
|
|
539
|
+
|
|
530
540
|
## Leaving the pages out of `matchesSpec`
|
|
531
541
|
|
|
532
542
|
An API under `/api`, spec first, is checked against its OpenAPI document
|
|
@@ -1028,6 +1038,22 @@ export const action = events.action; // POST
|
|
|
1028
1038
|
See the [subscription guide](https://github.com/softistx/alxia/blob/develop/packages/react-router/docs/guide/subscriptions.md)
|
|
1029
1039
|
for the rules, the options and the errors.
|
|
1030
1040
|
|
|
1041
|
+
## A UI library's links through React Router
|
|
1042
|
+
|
|
1043
|
+
A design system that renders its links through a component of its own (a
|
|
1044
|
+
`LinkComponentProvider`) hands it an `href`, while React Router's `Link` takes
|
|
1045
|
+
`to`. `@alxia/react-router/link` (`react` and `react-router` are its only
|
|
1046
|
+
imports) exports the adapter, so no app copies it:
|
|
1047
|
+
|
|
1048
|
+
```tsx
|
|
1049
|
+
// app/root.tsx
|
|
1050
|
+
import { RouterLink } from '@alxia/react-router/link';
|
|
1051
|
+
|
|
1052
|
+
<LinkComponentProvider component={RouterLink}>
|
|
1053
|
+
<Outlet />
|
|
1054
|
+
</LinkComponentProvider>
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1031
1057
|
## A list whose state is the URL
|
|
1032
1058
|
|
|
1033
1059
|
`@alxia/react-router/lists` (`react` and `react-router` are its only imports; every hook renders on the server)
|
|
@@ -1116,7 +1142,7 @@ export function loader({ request }: Route.LoaderArgs) {
|
|
|
1116
1142
|
|
|
1117
1143
|
| export | |
|
|
1118
1144
|
| --- | --- |
|
|
1119
|
-
| `createServer(options?)` | the server of `app/server.ts`. `beforeAll`, `configure`, `getLoadContext`, `proxy` (`alxia({ proxy })`'s, `trustProxy(…)` from `@alxia/core`), `build`, `mode`, `client`, `listen`, `onListen` |
|
|
1145
|
+
| `createServer(options?)` | the server of `app/server.ts`. `beforeAll`, `configure`, `getLoadContext`, `proxy` (`alxia({ proxy })`'s, `trustProxy(…)` from `@alxia/core`), `build`, `mode`, `client`, `precompressed`, `listen`, `onListen` |
|
|
1120
1146
|
| `ServerOptions<Before, App>` | its options |
|
|
1121
1147
|
| `ReactRouterServer<App>` | what it returns: `create(wiring)` makes the app, `start(app)` listens |
|
|
1122
1148
|
| `ServerWiring` | what `create` takes: `build`, `mode`, `client` |
|
|
@@ -1134,7 +1160,7 @@ export function loader({ request }: Route.LoaderArgs) {
|
|
|
1134
1160
|
| `AppOf<Server>` | the app a server makes |
|
|
1135
1161
|
| `alxiaContext` | the React Router context key `alxiaOf` and `context.alxia` read, set on every request |
|
|
1136
1162
|
| `nonceOf(context)` | the request's CSP nonce, for `entry.server.tsx`: the context's `nonce` when a middleware set one, such as `secureHeaders({ nonce: true })`, else `undefined` |
|
|
1137
|
-
| `reactRouter(app, options)` | the catch-all and the client's files, for a server of your own. `build`, `mode`, `getLoadContext`, `client` |
|
|
1163
|
+
| `reactRouter(app, options)` | the catch-all and the client's files, for a server of your own. `build`, `mode`, `getLoadContext`, `client`, `precompressed` |
|
|
1138
1164
|
| `ReactRouterOptions<Ctx>` | its options |
|
|
1139
1165
|
| `isReactRouterRoute(route)` | whether this package declared a route, for `matchesSpec`'s `exclude` |
|
|
1140
1166
|
|
|
@@ -1142,8 +1168,8 @@ From `@alxia/react-router/vite`:
|
|
|
1142
1168
|
|
|
1143
1169
|
| export | |
|
|
1144
1170
|
| --- | --- |
|
|
1145
|
-
| `alxia(options?)` | the Vite plugin, for `react-router dev`, `react-router build` and `vite preview`, building the server for Bun. `entry` is the server file: `app/server.ts` by default, or the default server when there is none. `worker` is the service worker built after `react-router build`: `app/service-worker.ts` by default when it exists, a file, `AlxiaWorkerOptions`, or `false` |
|
|
1146
|
-
| `AlxiaOptions`, `AlxiaWorkerOptions` | its options,
|
|
1171
|
+
| `alxia(options?)` | the Vite plugin, for `react-router dev`, `react-router build` and `vite preview`, building the server for Bun. `entry` is the server file: `app/server.ts` by default, or the default server when there is none. `worker` is the service worker built after `react-router build`: `app/service-worker.ts` by default when it exists, a file, `AlxiaWorkerOptions`, or `false`. `precompress` writes the `.br` and `.gz` copies of the client build: on by default, `false`, or `PrecompressOptions` (`minSize`) |
|
|
1172
|
+
| `AlxiaOptions`, `AlxiaWorkerOptions`, `PrecompressOptions` | its options, the worker's (`buildWorker()`'s but `root`, `client` and `file`, which is optional) |
|
|
1147
1173
|
|
|
1148
1174
|
From `@alxia/react-router/pwa`:
|
|
1149
1175
|
|
|
@@ -1306,6 +1332,12 @@ From `@alxia/react-router/lists` (`react` and `react-router` are its only import
|
|
|
1306
1332
|
| `usePagedRows(firstPage, rowsOf, { cursorParam?, nextOf? }?)`, `PagedRows`, `PagedRowsOptions` | `{ rows, next, loading, error, loadMore }`: appends the pages the same route answers to `?<cursorParam>=<next>` (default `after`, `nextOf` default `page.next`) through `useFetcher`; starts over when `firstPage` is another object; a failure keeps the rows and sets `error` (an answer that is not a page), and data that is not a page is ignored |
|
|
1307
1333
|
| `orFailed(after, run)`, `FAILED`, `isFailedPage(value)`, `FailedPage` | the loader half of `usePagedRows`: `run()`'s answer; an error is rethrown when `after` is empty, and with an `after` it answers `FAILED` (`{ failed: true }`, typed `Promise<T \| FailedPage>`), except a 3xx `Response`, which is rethrown. `isFailedPage` narrows an answer |
|
|
1308
1334
|
|
|
1335
|
+
From `@alxia/react-router/link` (`react` and `react-router` are its only imports; it renders on the server):
|
|
1336
|
+
|
|
1337
|
+
| export | |
|
|
1338
|
+
| --- | --- |
|
|
1339
|
+
| `RouterLink`, `RouterLinkProps` | React Router's `Link` as a UI library's link component: takes `href` (or `to`), spreads `className`, `children`, `ref` and every anchor prop onto the `<a>`, keeps `Link`'s own props (`replace`, `prefetch`, `reloadDocument`, ...) |
|
|
1340
|
+
|
|
1309
1341
|
From `@alxia/react-router/subscription` (no import, no peer):
|
|
1310
1342
|
|
|
1311
1343
|
| export | |
|
package/dist/assets.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ interface Serving {
|
|
|
7
7
|
file(path: string, file: string, options: object): unknown;
|
|
8
8
|
}
|
|
9
9
|
/** Declares the client build's routes on `app`. */
|
|
10
|
-
export declare function serveClient(app: Serving, client: string
|
|
10
|
+
export declare function serveClient(app: Serving, client: string, options?: {
|
|
11
|
+
readonly precompressed?: boolean;
|
|
12
|
+
}): void;
|
|
11
13
|
export {};
|
|
12
14
|
//# sourceMappingURL=assets.d.ts.map
|
package/dist/assets.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../src/assets.ts"],"names":[],"mappings":"AAQA,mDAAmD;AACnD,eAAO,MAAM,SAAS,wCAAwC,CAAC;AAC/D,6EAA6E;AAC7E,eAAO,MAAM,OAAO,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../src/assets.ts"],"names":[],"mappings":"AAQA,mDAAmD;AACnD,eAAO,MAAM,SAAS,wCAAwC,CAAC;AAC/D,6EAA6E;AAC7E,eAAO,MAAM,OAAO,yBAAyB,CAAC;AAK9C,UAAU,OAAO;IAChB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/D,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3D;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAC1B,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAO,GAChD,IAAI,CAyBN"}
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,9 @@ import { readdirSync, statSync } from "node:fs";
|
|
|
18
18
|
import { join } from "node:path";
|
|
19
19
|
var IMMUTABLE = "public, max-age=31536000, immutable";
|
|
20
20
|
var AN_HOUR = "public, max-age=3600";
|
|
21
|
-
|
|
21
|
+
var CODINGS = ["br", "gzip"];
|
|
22
|
+
function serveClient(app, client, options = {}) {
|
|
23
|
+
const precompressed = options.precompressed === false ? {} : { precompressed: CODINGS };
|
|
22
24
|
if (!isDirectory(client)) {
|
|
23
25
|
throw new TypeError(`reactRouter(): client is ${client}, which is not a directory. Pass the client build, build/client by default.`);
|
|
24
26
|
}
|
|
@@ -30,9 +32,9 @@ function serveClient(app, client) {
|
|
|
30
32
|
const route = new URL(`/${name}`, "http://localhost").pathname;
|
|
31
33
|
try {
|
|
32
34
|
if (isDirectory(path))
|
|
33
|
-
app.static(route, path, { cacheControl });
|
|
35
|
+
app.static(route, path, { cacheControl, ...precompressed });
|
|
34
36
|
else
|
|
35
|
-
app.file(route, path, { cacheControl });
|
|
37
|
+
app.file(route, path, { cacheControl, ...precompressed });
|
|
36
38
|
} catch (error) {
|
|
37
39
|
throw new TypeError(`reactRouter(): ${path} cannot be served at a path of its own name; rename it. ${error.message}`);
|
|
38
40
|
}
|
|
@@ -66,7 +68,9 @@ function reactRouter(app, options) {
|
|
|
66
68
|
const routes = asRoutes(app);
|
|
67
69
|
declaring(app, () => {
|
|
68
70
|
if (options.client !== undefined && mode === "production") {
|
|
69
|
-
serveClient(routes, pathOf(options.client)
|
|
71
|
+
serveClient(routes, pathOf(options.client), {
|
|
72
|
+
precompressed: options.precompressed ?? true
|
|
73
|
+
});
|
|
70
74
|
}
|
|
71
75
|
for (const method of METHODS)
|
|
72
76
|
routes[method]("/*", handler);
|
|
@@ -79,8 +83,8 @@ function routerRequest(ctx) {
|
|
|
79
83
|
const request = href === ctx.url.href ? ctx.request : new Request(href, ctx.request);
|
|
80
84
|
return head ? new Request(request, { method: "GET" }) : request;
|
|
81
85
|
}
|
|
82
|
-
function declareClient(app, client) {
|
|
83
|
-
declaring(app, () => serveClient(asRoutes(app), pathOf(client)));
|
|
86
|
+
function declareClient(app, client, precompressed = true) {
|
|
87
|
+
declaring(app, () => serveClient(asRoutes(app), pathOf(client), { precompressed }));
|
|
84
88
|
}
|
|
85
89
|
function declaring(app, declare) {
|
|
86
90
|
const before = new Set(app.routes);
|
|
@@ -124,7 +128,7 @@ function createServer(options = {}) {
|
|
|
124
128
|
});
|
|
125
129
|
const before = options.beforeAll?.(fresh) ?? fresh;
|
|
126
130
|
if (client !== undefined && mode === "production") {
|
|
127
|
-
declareClient(before, client);
|
|
131
|
+
declareClient(before, client, options.precompressed ?? true);
|
|
128
132
|
}
|
|
129
133
|
const app = options.configure?.(before) ?? before;
|
|
130
134
|
const getLoadContext = options.getLoadContext;
|
|
@@ -172,5 +176,5 @@ export {
|
|
|
172
176
|
withAlxia
|
|
173
177
|
};
|
|
174
178
|
|
|
175
|
-
//# debugId=
|
|
179
|
+
//# debugId=6C7DF5EFFD100B0D64756E2164756E21
|
|
176
180
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/react-router.ts", "../src/assets.ts", "../src/server.ts", "../src/with-alxia.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { fileURLToPath } from 'node:url';\nimport {\n\ttype Alxia,\n\ttype AnyAlxia,\n\ttype BaseContext,\n\ttype MaybePromise,\n\toriginalUrl,\n\ttype RouteDefinition,\n\ttype StatusCode,\n} from '@alxia/core';\nimport {\n\tcreateRequestHandler,\n\ttype RequestHandler,\n\tRouterContextProvider,\n\ttype ServerBuild,\n} from 'react-router';\nimport { serveClient } from './assets';\nimport { alxiaContext } from './context';\n\nexport interface ReactRouterOptions<Ctx> {\n\t/**\n\t * React Router's server build: the module itself, or a function that\n\t * returns it — `() => import('virtual:react-router/server-build')` in a\n\t * server entry Vite builds, `() => import('./build/server/index.js')`\n\t * beside a build. A function is called on every request in\n\t * `development`, so an edit is picked up, and once in `production`.\n\t */\n\treadonly build: ServerBuild | (() => MaybePromise<ServerBuild>);\n\t/** React Router's server mode: `production` by default. */\n\treadonly mode?: 'development' | 'production';\n\t/**\n\t * Sets the app's own keys on React Router's context provider, from the\n\t * context alxia's middlewares built. `ctx` is typed by the app at the point of\n\t * `app.plugin`: reading what nothing before it adds is a compile error.\n\t * `alxiaContext` is always set, whether or not this is given.\n\t */\n\treadonly getLoadContext?: (\n\t\tctx: BaseContext & Ctx,\n\t\tcontext: RouterContextProvider,\n\t) => MaybePromise<void>;\n\t/**\n\t * The client build's folder, `build/client`: a path or a `file:` URL.\n\t * Its `assets/` is served immutable, and every other top-level file or\n\t * folder — the copies of `public/` — with an hour's cache, before the\n\t * catch-all. Ignored in `development`, where Vite serves them.\n\t */\n\treadonly client?: string | URL;\n}\n\n/** The methods the catch-all takes. A `HEAD` reaches its `GET`. */\nconst METHODS = ['get', 'post', 'put', 'patch', 'delete'] as const;\n\n/** The handlers `reactRouter()` declared: the catch-all's and the client build's. */\nconst declared = new WeakSet<RouteDefinition['handler']>();\n\n/**\n * Whether `reactRouter()` declared this route: the catch-all, or one of the\n * client build's files. For `@alxia/openapi`'s `matchesSpec`, whose\n * `exclude` leaves them out, so the app's routes are checked against the\n * operations of its OpenAPI document and its pages are not.\n *\n * ```ts\n * matchesSpec(app, operations, { exclude: isReactRouterRoute });\n * ```\n */\nexport function isReactRouterRoute(route: RouteDefinition): boolean {\n\treturn declared.has(route.handler);\n}\n\n/**\n * A React Router framework app, server rendered on `app`: `GET`, `POST`,\n * `PUT`, `PATCH` and `DELETE` at `/*`, behind every middleware declared on `app`\n * before it. Each loader, action and middleware reads what those added\n * through `alxiaOf<App>(context)`. The app's own routes — an `/api`\n * — answer their paths, declared before it or after; the client build's\n * files are served when `client` is given.\n *\n * ```ts\n * const app = base.plugin((app) =>\n * reactRouter(app, { build: () => import('./build/server/index.js'), client: 'build/client' }),\n * );\n * ```\n */\nexport function reactRouter<Ctx extends object, Prefix extends string>(\n\tapp: Alxia<Ctx, Prefix>,\n\toptions: ReactRouterOptions<Ctx>,\n): Alxia<Ctx, Prefix> {\n\tconst mode = options.mode ?? 'production';\n\tconst handle = requestHandler(options.build, mode);\n\tconst getLoadContext = options.getLoadContext;\n\tconst handler = async (ctx: BaseContext & Ctx) => {\n\t\tconst context = new RouterContextProvider();\n\t\tcontext.set(alxiaContext, ctx);\n\t\tawait getLoadContext?.(ctx, context);\n\t\tconst response = await handle(routerRequest(ctx), context);\n\t\treturn ctx.reply(\n\t\t\tresponse.status as StatusCode,\n\t\t\tresponse.body ?? undefined,\n\t\t\t{ headers: response.headers },\n\t\t);\n\t};\n\n\tconst routes = asRoutes(app);\n\tdeclaring(app, () => {\n\t\tif (options.client !== undefined && mode === 'production') {\n\t\t\tserveClient(routes, pathOf(options.client));\n\t\t}\n\t\tfor (const method of METHODS) routes[method]('/*', handler);\n\t});\n\treturn app;\n}\n\n/**\n * The request React Router reads: at the URL the client asked for, which\n * `originalUrl` reads behind the app's trusted proxies (`alxia({ proxy })`),\n * so `request.url` in a loader names the public scheme and host; and a\n * `HEAD` as its `GET`, since React Router answers a `HEAD` with no headers\n * at all, and the core drops the body.\n */\nfunction routerRequest(ctx: BaseContext): Request {\n\tconst href = originalUrl(ctx).href;\n\tconst head = ctx.request.method === 'HEAD';\n\tconst request =\n\t\thref === ctx.url.href ? ctx.request : new Request(href, ctx.request);\n\treturn head ? new Request(request, { method: 'GET' }) : request;\n}\n\n/**\n * Declares the client build's files on `app`, marked for\n * `isReactRouterRoute`: what `reactRouter()` does with `client`, apart, so\n * that `createServer()` serves them before the middlewares of `configure`.\n */\nexport function declareClient(
|
|
6
|
-
"/**\n * The client build's files, served before the catch-all: the hashed\n * `assets/` immutable, every other top-level file or folder — what React\n * Router copied from `public/` — with an hour's cache.\n */\nimport { readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/** A hashed asset never changes under its name. */\nexport const IMMUTABLE = 'public, max-age=31536000, immutable';\n/** A public file keeps its name across builds: revalidated after an hour. */\nexport const AN_HOUR = 'public, max-age=3600';\n\ninterface Serving {\n\tstatic(path: string, source: string, options: object): unknown;\n\tfile(path: string, file: string, options: object): unknown;\n}\n\n/** Declares the client build's routes on `app`. */\nexport function serveClient(
|
|
7
|
-
"/**\n * `createServer()`: the alxia server of a React Router app, as\n * `@alxia/react-router/vite` builds it. The plugin hands it React Router's\n * build, the mode and the client folder; the app's own `app/server.ts`\n * customises the rest, or is not written at all.\n */\nimport {\n\ttype Alxia,\n\ttype AnyAlxia,\n\talxia,\n\ttype ContextOf,\n\ttype Empty,\n\ttype ListenInfo,\n\ttype ListenOptions,\n\ttype MaybePromise,\n\ttype ProxyTrust,\n} from '@alxia/core';\nimport type { RouterContextProvider, ServerBuild } from 'react-router';\nimport { declareClient, reactRouter } from './react-router';\n\n/** An app as `alxia()` makes it: what `beforeAll`, or `configure`, receives. */\nexport type FreshApp = Alxia<Empty, ''>;\n\n/**\n * What the Vite plugin hands the server, and a test passes to `create`:\n * React Router's server build, its mode, and the client build's folder.\n */\nexport interface ServerWiring {\n\t/**\n\t * React Router's server build, or a function that returns it: called on\n\t * every request in `development`, once in `production`.\n\t */\n\treadonly build: ServerBuild | (() => MaybePromise<ServerBuild>);\n\t/** `development` under `react-router dev`, `production` in a build, and by default. */\n\treadonly mode?: 'development' | 'production';\n\t/** The client build's folder, a path or a `file:` URL: served in `production`. */\n\treadonly client?: string | URL | undefined;\n}\n\nexport interface ServerOptions<Before extends AnyAlxia, App extends AnyAlxia> {\n\t/**\n\t * Runs first, on a new app: what is declared here runs before the\n\t * client's files too — a guard, a rate limit, a logger that should see\n\t * every request. Returns the app, so its types flow to `configure`.\n\t */\n\treadonly beforeAll?: (app: FreshApp) => Before;\n\t/**\n\t * The app the pages run behind: its middlewares, its plugins, its `/api`.\n\t * Declared after the client's files and before the catch-all. Returns\n\t * the app: what it builds is what the loaders read through `alxiaOf`.\n\t */\n\treadonly configure?: (app: Before) => App;\n\t/**\n\t * Sets the app's own keys on React Router's context provider, `ctx`\n\t * typed by `configure`'s app. `alxiaContext` is always set.\n\t */\n\treadonly getLoadContext?: (\n\t\tctx: ContextOf<App>,\n\t\tcontext: RouterContextProvider,\n\t) => MaybePromise<void>;\n\t/**\n\t * The proxies in front of the app, `trustProxy({ trusted })` from\n\t * `@alxia/core`: `alxia({ proxy })`'s option, so `ctx.ip` is the\n\t * client's and React Router's `request.url` the URL it asked for.\n\t */\n\treadonly proxy?: ProxyTrust;\n\t/** Overrides the plugin's server build: rarely wanted. */\n\treadonly build?: ServerWiring['build'];\n\t/** Overrides the plugin's mode, `development` in dev and `production` in a build. */\n\treadonly mode?: 'development' | 'production';\n\t/**\n\t * Overrides the plugin's client folder, `build/client` beside the built\n\t * server. `false` serves none of it: declare the files yourself, in\n\t * `beforeAll` or `configure`.\n\t */\n\treadonly client?: string | URL | false;\n\t/**\n\t * `listen`'s options for `bun build/server/index.js` — `shutdownTimeout`,\n\t * `signals` among them; a `port` or `hostname` here wins over `PORT` (3000)\n\t * and `HOST` (`0.0.0.0`) from the environment.\n\t */\n\treadonly listen?: ListenOptions;\n\t/**\n\t * Called once the built server listens and its `SIGINT` and `SIGTERM` handlers are in place.\n\t * Prints `alxia listening on <url>` by default, and in dev the route\n\t * table (`alxia({ dev })`). An `onListen` in `listen` wins over it.\n\t */\n\treadonly onListen?: (server: Bun.Server<unknown>) => void;\n}\n\n/**\n * The server `createServer()` describes, made into an app by the Vite\n * plugin, by a test, or by a server file of your own.\n */\nexport interface ReactRouterServer<App extends AnyAlxia> {\n\t/**\n\t * The app, serving React Router's build: `build/server/index.js`'s\n\t * default export. A test drives it with `app.request`.\n\t *\n\t * ```ts\n\t * const app = server.create({ build: await import('./build/server/index.js') });\n\t * ```\n\t */\n\tcreate(wiring: ServerWiring): App;\n\t/**\n\t * Listens with `app`, on `listen`, `PORT` and `HOST`, and shuts it down\n\t * gracefully on `SIGINT` or `SIGTERM`, as `@alxia/core`'s `listen` does:\n\t * the requests in flight finish within `shutdownTimeout`, its `onStop`\n\t * hooks run, and the process exits. What `bun build/server/index.js` runs.\n\t */\n\tstart(app: App): Bun.Server<unknown>;\n}\n\n/**\n * The alxia server of a React Router app, for `app/server.ts`. Every option\n * is optional: the Vite plugin wires React Router's build, the mode and the\n * client folder, and without the file uses `createServer()` as it is.\n *\n * ```ts\n * const server = createServer({\n * configure: (app) => app.use(logger()).get('/api/health', ({ reply }) => reply.ok({ ok: true })),\n * });\n * export default server;\n * ```\n *\n * The request runs through `beforeAll`, the client's files, `configure`,\n * then the pages.\n */\nexport function createServer<\n\tBefore extends AnyAlxia = FreshApp,\n\tApp extends AnyAlxia = Before,\n>(options: ServerOptions<Before, App> = {}): ReactRouterServer<App> {\n\treturn {\n\t\tcreate(wiring) {\n\t\t\tconst mode = options.mode ?? wiring.mode ?? 'production';\n\t\t\tconst client =\n\t\t\t\toptions.client === false\n\t\t\t\t\t? undefined\n\t\t\t\t\t: (options.client ?? wiring.client);\n\t\t\t// The app helps the developer in React Router's dev alone: a production\n\t\t\t// build is never in dev, whatever NODE_ENV says.\n\t\t\tconst fresh = alxia({\n\t\t\t\tdev: mode === 'development',\n\t\t\t\t...(options.proxy === undefined ? {} : { proxy: options.proxy }),\n\t\t\t});\n\t\t\t// Without beforeAll or configure, Before and App are their defaults,\n\t\t\t// the app passed through: a type argument given by hand is believed.\n\t\t\tconst before = (options.beforeAll?.(fresh) ?? fresh) as Before;\n\t\t\tif (client !== undefined && mode === 'production') {\n\t\t\t\tdeclareClient(before, client);\n\t\t\t}\n\t\t\tconst app = (options.configure?.(before) ?? before) as App;\n\t\t\tconst getLoadContext = options.getLoadContext;\n\t\t\treactRouter(app, {\n\t\t\t\tbuild: options.build ?? wiring.build,\n\t\t\t\tmode,\n\t\t\t\t...(getLoadContext === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tgetLoadContext: (ctx, context) =>\n\t\t\t\t\t\t\t\tgetLoadContext(ctx as ContextOf<App>, context),\n\t\t\t\t\t\t}),\n\t\t\t});\n\t\t\treturn app;\n\t\t},\n\t\tstart(app) {\n\t\t\tconst own = options.listen?.onListen;\n\t\t\t// `listen` shuts the app down on SIGINT and SIGTERM — readiness 503,\n\t\t\t// the requests in flight drained, the onStop hooks, then the exit —\n\t\t\t// with its handlers in place before it tells onListen: a supervisor\n\t\t\t// may signal as soon as it reads that the server listens.\n\t\t\treturn app.listen({\n\t\t\t\tport: Number(process.env['PORT'] || 3000),\n\t\t\t\thostname: process.env['HOST'] || '0.0.0.0',\n\t\t\t\t...options.listen,\n\t\t\t\tonListen: (info) => {\n\t\t\t\t\tif (own !== undefined) own(info);\n\t\t\t\t\telse if (options.onListen !== undefined) {\n\t\t\t\t\t\toptions.onListen(info.server);\n\t\t\t\t\t} else announce(info);\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t};\n}\n\n/** In dev, the route table `listen` prints; else one line. */\nfunction announce({ dev, table, url }: ListenInfo): void {\n\tconsole.log(dev ? table : `alxia listening on ${url}`);\n}\n",
|
|
5
|
+
"import { fileURLToPath } from 'node:url';\nimport {\n\ttype Alxia,\n\ttype AnyAlxia,\n\ttype BaseContext,\n\ttype MaybePromise,\n\toriginalUrl,\n\ttype RouteDefinition,\n\ttype StatusCode,\n} from '@alxia/core';\nimport {\n\tcreateRequestHandler,\n\ttype RequestHandler,\n\tRouterContextProvider,\n\ttype ServerBuild,\n} from 'react-router';\nimport { serveClient } from './assets';\nimport { alxiaContext } from './context';\n\nexport interface ReactRouterOptions<Ctx> {\n\t/**\n\t * React Router's server build: the module itself, or a function that\n\t * returns it — `() => import('virtual:react-router/server-build')` in a\n\t * server entry Vite builds, `() => import('./build/server/index.js')`\n\t * beside a build. A function is called on every request in\n\t * `development`, so an edit is picked up, and once in `production`.\n\t */\n\treadonly build: ServerBuild | (() => MaybePromise<ServerBuild>);\n\t/** React Router's server mode: `production` by default. */\n\treadonly mode?: 'development' | 'production';\n\t/**\n\t * Sets the app's own keys on React Router's context provider, from the\n\t * context alxia's middlewares built. `ctx` is typed by the app at the point of\n\t * `app.plugin`: reading what nothing before it adds is a compile error.\n\t * `alxiaContext` is always set, whether or not this is given.\n\t */\n\treadonly getLoadContext?: (\n\t\tctx: BaseContext & Ctx,\n\t\tcontext: RouterContextProvider,\n\t) => MaybePromise<void>;\n\t/**\n\t * The client build's folder, `build/client`: a path or a `file:` URL.\n\t * Its `assets/` is served immutable, and every other top-level file or\n\t * folder — the copies of `public/` — with an hour's cache, before the\n\t * catch-all. Ignored in `development`, where Vite serves them.\n\t */\n\treadonly client?: string | URL;\n\t/**\n\t * Serves the `.br` and `.gz` copies `alxia()` writes beside the client\n\t * build's files to a browser that accepts them, with `Vary:\n\t * Accept-Encoding`: `true` by default. `false` serves the files as they\n\t * are.\n\t */\n\treadonly precompressed?: boolean;\n}\n\n/** The methods the catch-all takes. A `HEAD` reaches its `GET`. */\nconst METHODS = ['get', 'post', 'put', 'patch', 'delete'] as const;\n\n/** The handlers `reactRouter()` declared: the catch-all's and the client build's. */\nconst declared = new WeakSet<RouteDefinition['handler']>();\n\n/**\n * Whether `reactRouter()` declared this route: the catch-all, or one of the\n * client build's files. For `@alxia/openapi`'s `matchesSpec`, whose\n * `exclude` leaves them out, so the app's routes are checked against the\n * operations of its OpenAPI document and its pages are not.\n *\n * ```ts\n * matchesSpec(app, operations, { exclude: isReactRouterRoute });\n * ```\n */\nexport function isReactRouterRoute(route: RouteDefinition): boolean {\n\treturn declared.has(route.handler);\n}\n\n/**\n * A React Router framework app, server rendered on `app`: `GET`, `POST`,\n * `PUT`, `PATCH` and `DELETE` at `/*`, behind every middleware declared on `app`\n * before it. Each loader, action and middleware reads what those added\n * through `alxiaOf<App>(context)`. The app's own routes — an `/api`\n * — answer their paths, declared before it or after; the client build's\n * files are served when `client` is given.\n *\n * ```ts\n * const app = base.plugin((app) =>\n * reactRouter(app, { build: () => import('./build/server/index.js'), client: 'build/client' }),\n * );\n * ```\n */\nexport function reactRouter<Ctx extends object, Prefix extends string>(\n\tapp: Alxia<Ctx, Prefix>,\n\toptions: ReactRouterOptions<Ctx>,\n): Alxia<Ctx, Prefix> {\n\tconst mode = options.mode ?? 'production';\n\tconst handle = requestHandler(options.build, mode);\n\tconst getLoadContext = options.getLoadContext;\n\tconst handler = async (ctx: BaseContext & Ctx) => {\n\t\tconst context = new RouterContextProvider();\n\t\tcontext.set(alxiaContext, ctx);\n\t\tawait getLoadContext?.(ctx, context);\n\t\tconst response = await handle(routerRequest(ctx), context);\n\t\treturn ctx.reply(\n\t\t\tresponse.status as StatusCode,\n\t\t\tresponse.body ?? undefined,\n\t\t\t{ headers: response.headers },\n\t\t);\n\t};\n\n\tconst routes = asRoutes(app);\n\tdeclaring(app, () => {\n\t\tif (options.client !== undefined && mode === 'production') {\n\t\t\tserveClient(routes, pathOf(options.client), {\n\t\t\t\tprecompressed: options.precompressed ?? true,\n\t\t\t});\n\t\t}\n\t\tfor (const method of METHODS) routes[method]('/*', handler);\n\t});\n\treturn app;\n}\n\n/**\n * The request React Router reads: at the URL the client asked for, which\n * `originalUrl` reads behind the app's trusted proxies (`alxia({ proxy })`),\n * so `request.url` in a loader names the public scheme and host; and a\n * `HEAD` as its `GET`, since React Router answers a `HEAD` with no headers\n * at all, and the core drops the body.\n */\nfunction routerRequest(ctx: BaseContext): Request {\n\tconst href = originalUrl(ctx).href;\n\tconst head = ctx.request.method === 'HEAD';\n\tconst request =\n\t\thref === ctx.url.href ? ctx.request : new Request(href, ctx.request);\n\treturn head ? new Request(request, { method: 'GET' }) : request;\n}\n\n/**\n * Declares the client build's files on `app`, marked for\n * `isReactRouterRoute`: what `reactRouter()` does with `client`, apart, so\n * that `createServer()` serves them before the middlewares of `configure`.\n */\nexport function declareClient(\n\tapp: AnyAlxia,\n\tclient: string | URL,\n\tprecompressed = true,\n): void {\n\tdeclaring(app, () =>\n\t\tserveClient(asRoutes(app), pathOf(client), { precompressed }),\n\t);\n}\n\n/** Runs `declare`, and marks every route it added to `app` as ours. */\nfunction declaring(app: AnyAlxia, declare: () => void): void {\n\tconst before = new Set(app.routes);\n\tdeclare();\n\tfor (const route of app.routes) {\n\t\tif (!before.has(route)) declared.add(route.handler);\n\t}\n}\n\n/** The app's route methods, untyped: the catch-all's handler is not one a route type admits. */\nfunction asRoutes(app: AnyAlxia) {\n\treturn app as unknown as {\n\t\tstatic(path: string, source: string, options: object): unknown;\n\t\tfile(path: string, file: string, options: object): unknown;\n\t} & Record<\n\t\t(typeof METHODS)[number],\n\t\t(path: string, handler: unknown) => unknown\n\t>;\n}\n\n/** A handler that resolves a function build once in production, on every request in development. */\nfunction requestHandler(\n\tbuild: ReactRouterOptions<never>['build'],\n\tmode: 'development' | 'production',\n): RequestHandler {\n\tif (typeof build !== 'function' || mode === 'development') {\n\t\treturn createRequestHandler(build, mode);\n\t}\n\tlet resolved: Promise<RequestHandler> | undefined;\n\treturn async (request, context) => {\n\t\tresolved ??= Promise.resolve(build()).then(\n\t\t\t(server) => createRequestHandler(server, mode),\n\t\t\t(error: unknown) => {\n\t\t\t\tresolved = undefined;\n\t\t\t\tthrow error;\n\t\t\t},\n\t\t);\n\t\treturn (await resolved)(request, context);\n\t};\n}\n\nfunction pathOf(client: string | URL): string {\n\treturn client instanceof URL ? fileURLToPath(client) : client;\n}\n",
|
|
6
|
+
"/**\n * The client build's files, served before the catch-all: the hashed\n * `assets/` immutable, every other top-level file or folder — what React\n * Router copied from `public/` — with an hour's cache.\n */\nimport { readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/** A hashed asset never changes under its name. */\nexport const IMMUTABLE = 'public, max-age=31536000, immutable';\n/** A public file keeps its name across builds: revalidated after an hour. */\nexport const AN_HOUR = 'public, max-age=3600';\n\n/** The copies the plugin writes, best first. */\nconst CODINGS = ['br', 'gzip'] as const;\n\ninterface Serving {\n\tstatic(path: string, source: string, options: object): unknown;\n\tfile(path: string, file: string, options: object): unknown;\n}\n\n/** Declares the client build's routes on `app`. */\nexport function serveClient(\n\tapp: Serving,\n\tclient: string,\n\toptions: { readonly precompressed?: boolean } = {},\n): void {\n\tconst precompressed =\n\t\toptions.precompressed === false ? {} : { precompressed: CODINGS };\n\tif (!isDirectory(client)) {\n\t\tthrow new TypeError(\n\t\t\t`reactRouter(): client is ${client}, which is not a directory. Pass the client build, build/client by default.`,\n\t\t);\n\t}\n\tfor (const name of readdirSync(client).sort()) {\n\t\tif (name.startsWith('.')) continue;\n\t\tconst path = join(client, name);\n\t\tconst cacheControl = name === 'assets' ? IMMUTABLE : AN_HOUR;\n\t\t// Declared as a request's URL carries the name: `my file.pdf` is\n\t\t// `/my%20file.pdf`, `café.png` is `/caf%C3%A9.png`.\n\t\tconst route = new URL(`/${name}`, 'http://localhost').pathname;\n\t\ttry {\n\t\t\tif (isDirectory(path))\n\t\t\t\tapp.static(route, path, { cacheControl, ...precompressed });\n\t\t\telse app.file(route, path, { cacheControl, ...precompressed });\n\t\t} catch (error) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`reactRouter(): ${path} cannot be served at a path of its own name; rename it. ${(error as Error).message}`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction isDirectory(path: string): boolean {\n\ttry {\n\t\treturn statSync(path).isDirectory();\n\t} catch {\n\t\treturn false;\n\t}\n}\n",
|
|
7
|
+
"/**\n * `createServer()`: the alxia server of a React Router app, as\n * `@alxia/react-router/vite` builds it. The plugin hands it React Router's\n * build, the mode and the client folder; the app's own `app/server.ts`\n * customises the rest, or is not written at all.\n */\nimport {\n\ttype Alxia,\n\ttype AnyAlxia,\n\talxia,\n\ttype ContextOf,\n\ttype Empty,\n\ttype ListenInfo,\n\ttype ListenOptions,\n\ttype MaybePromise,\n\ttype ProxyTrust,\n} from '@alxia/core';\nimport type { RouterContextProvider, ServerBuild } from 'react-router';\nimport { declareClient, reactRouter } from './react-router';\n\n/** An app as `alxia()` makes it: what `beforeAll`, or `configure`, receives. */\nexport type FreshApp = Alxia<Empty, ''>;\n\n/**\n * What the Vite plugin hands the server, and a test passes to `create`:\n * React Router's server build, its mode, and the client build's folder.\n */\nexport interface ServerWiring {\n\t/**\n\t * React Router's server build, or a function that returns it: called on\n\t * every request in `development`, once in `production`.\n\t */\n\treadonly build: ServerBuild | (() => MaybePromise<ServerBuild>);\n\t/** `development` under `react-router dev`, `production` in a build, and by default. */\n\treadonly mode?: 'development' | 'production';\n\t/** The client build's folder, a path or a `file:` URL: served in `production`. */\n\treadonly client?: string | URL | undefined;\n}\n\nexport interface ServerOptions<Before extends AnyAlxia, App extends AnyAlxia> {\n\t/**\n\t * Runs first, on a new app: what is declared here runs before the\n\t * client's files too — a guard, a rate limit, a logger that should see\n\t * every request. Returns the app, so its types flow to `configure`.\n\t */\n\treadonly beforeAll?: (app: FreshApp) => Before;\n\t/**\n\t * The app the pages run behind: its middlewares, its plugins, its `/api`.\n\t * Declared after the client's files and before the catch-all. Returns\n\t * the app: what it builds is what the loaders read through `alxiaOf`.\n\t */\n\treadonly configure?: (app: Before) => App;\n\t/**\n\t * Sets the app's own keys on React Router's context provider, `ctx`\n\t * typed by `configure`'s app. `alxiaContext` is always set.\n\t */\n\treadonly getLoadContext?: (\n\t\tctx: ContextOf<App>,\n\t\tcontext: RouterContextProvider,\n\t) => MaybePromise<void>;\n\t/**\n\t * The proxies in front of the app, `trustProxy({ trusted })` from\n\t * `@alxia/core`: `alxia({ proxy })`'s option, so `ctx.ip` is the\n\t * client's and React Router's `request.url` the URL it asked for.\n\t */\n\treadonly proxy?: ProxyTrust;\n\t/** Overrides the plugin's server build: rarely wanted. */\n\treadonly build?: ServerWiring['build'];\n\t/** Overrides the plugin's mode, `development` in dev and `production` in a build. */\n\treadonly mode?: 'development' | 'production';\n\t/**\n\t * Overrides the plugin's client folder, `build/client` beside the built\n\t * server. `false` serves none of it: declare the files yourself, in\n\t * `beforeAll` or `configure`.\n\t */\n\treadonly client?: string | URL | false;\n\t/**\n\t * Serves the client's `.br` and `.gz` copies, which `alxia()` writes at\n\t * build time, to a browser that accepts them: `true` by default.\n\t * `false` serves the files as they are.\n\t */\n\treadonly precompressed?: boolean;\n\t/**\n\t * `listen`'s options for `bun build/server/index.js` — `shutdownTimeout`,\n\t * `signals` among them; a `port` or `hostname` here wins over `PORT` (3000)\n\t * and `HOST` (`0.0.0.0`) from the environment.\n\t */\n\treadonly listen?: ListenOptions;\n\t/**\n\t * Called once the built server listens and its `SIGINT` and `SIGTERM` handlers are in place.\n\t * Prints `alxia listening on <url>` by default, and in dev the route\n\t * table (`alxia({ dev })`). An `onListen` in `listen` wins over it.\n\t */\n\treadonly onListen?: (server: Bun.Server<unknown>) => void;\n}\n\n/**\n * The server `createServer()` describes, made into an app by the Vite\n * plugin, by a test, or by a server file of your own.\n */\nexport interface ReactRouterServer<App extends AnyAlxia> {\n\t/**\n\t * The app, serving React Router's build: `build/server/index.js`'s\n\t * default export. A test drives it with `app.request`.\n\t *\n\t * ```ts\n\t * const app = server.create({ build: await import('./build/server/index.js') });\n\t * ```\n\t */\n\tcreate(wiring: ServerWiring): App;\n\t/**\n\t * Listens with `app`, on `listen`, `PORT` and `HOST`, and shuts it down\n\t * gracefully on `SIGINT` or `SIGTERM`, as `@alxia/core`'s `listen` does:\n\t * the requests in flight finish within `shutdownTimeout`, its `onStop`\n\t * hooks run, and the process exits. What `bun build/server/index.js` runs.\n\t */\n\tstart(app: App): Bun.Server<unknown>;\n}\n\n/**\n * The alxia server of a React Router app, for `app/server.ts`. Every option\n * is optional: the Vite plugin wires React Router's build, the mode and the\n * client folder, and without the file uses `createServer()` as it is.\n *\n * ```ts\n * const server = createServer({\n * configure: (app) => app.use(logger()).get('/api/health', ({ reply }) => reply.ok({ ok: true })),\n * });\n * export default server;\n * ```\n *\n * The request runs through `beforeAll`, the client's files, `configure`,\n * then the pages.\n */\nexport function createServer<\n\tBefore extends AnyAlxia = FreshApp,\n\tApp extends AnyAlxia = Before,\n>(options: ServerOptions<Before, App> = {}): ReactRouterServer<App> {\n\treturn {\n\t\tcreate(wiring) {\n\t\t\tconst mode = options.mode ?? wiring.mode ?? 'production';\n\t\t\tconst client =\n\t\t\t\toptions.client === false\n\t\t\t\t\t? undefined\n\t\t\t\t\t: (options.client ?? wiring.client);\n\t\t\t// The app helps the developer in React Router's dev alone: a production\n\t\t\t// build is never in dev, whatever NODE_ENV says.\n\t\t\tconst fresh = alxia({\n\t\t\t\tdev: mode === 'development',\n\t\t\t\t...(options.proxy === undefined ? {} : { proxy: options.proxy }),\n\t\t\t});\n\t\t\t// Without beforeAll or configure, Before and App are their defaults,\n\t\t\t// the app passed through: a type argument given by hand is believed.\n\t\t\tconst before = (options.beforeAll?.(fresh) ?? fresh) as Before;\n\t\t\tif (client !== undefined && mode === 'production') {\n\t\t\t\tdeclareClient(before, client, options.precompressed ?? true);\n\t\t\t}\n\t\t\tconst app = (options.configure?.(before) ?? before) as App;\n\t\t\tconst getLoadContext = options.getLoadContext;\n\t\t\treactRouter(app, {\n\t\t\t\tbuild: options.build ?? wiring.build,\n\t\t\t\tmode,\n\t\t\t\t...(getLoadContext === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tgetLoadContext: (ctx, context) =>\n\t\t\t\t\t\t\t\tgetLoadContext(ctx as ContextOf<App>, context),\n\t\t\t\t\t\t}),\n\t\t\t});\n\t\t\treturn app;\n\t\t},\n\t\tstart(app) {\n\t\t\tconst own = options.listen?.onListen;\n\t\t\t// `listen` shuts the app down on SIGINT and SIGTERM — readiness 503,\n\t\t\t// the requests in flight drained, the onStop hooks, then the exit —\n\t\t\t// with its handlers in place before it tells onListen: a supervisor\n\t\t\t// may signal as soon as it reads that the server listens.\n\t\t\treturn app.listen({\n\t\t\t\tport: Number(process.env['PORT'] || 3000),\n\t\t\t\thostname: process.env['HOST'] || '0.0.0.0',\n\t\t\t\t...options.listen,\n\t\t\t\tonListen: (info) => {\n\t\t\t\t\tif (own !== undefined) own(info);\n\t\t\t\t\telse if (options.onListen !== undefined) {\n\t\t\t\t\t\toptions.onListen(info.server);\n\t\t\t\t\t} else announce(info);\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t};\n}\n\n/** In dev, the route table `listen` prints; else one line. */\nfunction announce({ dev, table, url }: ListenInfo): void {\n\tconsole.log(dev ? table : `alxia listening on ${url}`);\n}\n",
|
|
8
8
|
"/**\n * `withAlxia(fn)`: a loader, an action or a middleware handed the alxia\n * context as `alxia`, typed even under the generated `Route.*Args`.\n */\nimport type { AnyAlxia } from '@alxia/core';\nimport {\n\ttype AlxiaContextOf,\n\talxiaOf,\n\ttype ProviderLike,\n\ttype RegisteredApp,\n} from './context';\nimport type { ReactRouterServer } from './server';\n\n/**\n * What `withAlxia` adds to React Router's arguments: `alxia`, what\n * `alxiaOf<App>(context)` returns. Typed by `Register` by default; name a\n * server, `AlxiaArgs<typeof server>`, as `alxiaOf<typeof server>` does.\n */\nexport interface AlxiaArgs<\n\tApp extends AnyAlxia | ReactRouterServer<AnyAlxia> = RegisteredApp,\n> {\n\treadonly alxia: AlxiaContextOf<App>;\n}\n\n/**\n * A loader, an action or a middleware given `alxia`, the alxia context, beside\n * React Router's arguments. Annotate the parameter as the generated arguments\n * and `AlxiaArgs`:\n *\n * ```ts\n * export const loader = withAlxia(({ alxia, params }: Route.LoaderArgs & AlxiaArgs) => {\n * return { name: alxia.user?.name ?? null, id: params.id };\n * });\n * ```\n *\n * It returns a function of React Router's arguments alone (`Args` without\n * `alxia`), with `fn`'s return type, so `useLoaderData<typeof loader>` and `Route.ComponentProps` read what\n * `fn` returns. A middleware's `next` is passed on. Throws `alxiaOf`'s error\n * on a request that did not come through `reactRouter()`.\n */\nexport function withAlxia<\n\t// `unknown`, not `AlxiaArgs<AnyAlxia>`, whose `alxia` is `any`: an `fn`\n\t// left unannotated reads nothing of it.\n\tArgs extends { readonly alxia: unknown; readonly context: ProviderLike },\n\tRest extends unknown[],\n\tResult,\n>(\n\tfn: (args: Args, ...rest: Rest) => Result,\n): (args: Omit<Args, 'alxia'>, ...rest: Rest) => Result {\n\treturn (args, ...rest) =>\n\t\tfn({ ...args, alxia: alxiaOf(args.context) } as unknown as Args, ...rest);\n}\n"
|
|
9
9
|
],
|
|
10
|
-
"mappings": ";;;;;;AAAA;AACA;AAAA;AAAA;AASA;AAAA;AAAA;AAAA;;;ACLA;AACA;AAGO,IAAM,YAAY;AAElB,IAAM,UAAU;
|
|
11
|
-
"debugId": "
|
|
10
|
+
"mappings": "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",
|
|
11
|
+
"debugId": "6C7DF5EFFD100B0D64756E2164756E21",
|
|
12
12
|
"names": []
|
|
13
13
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@alxia/react-router/link`: React Router's `Link` as the link component of
|
|
3
|
+
* a UI library. `react` and `react-router` are its only imports, and it
|
|
4
|
+
* renders on the server.
|
|
5
|
+
*/
|
|
6
|
+
export { RouterLink, type RouterLinkProps } from './router-link';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/link/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/link/router-link.ts
|
|
2
|
+
import { createElement } from "react";
|
|
3
|
+
import { Link } from "react-router";
|
|
4
|
+
function RouterLink({
|
|
5
|
+
href,
|
|
6
|
+
to,
|
|
7
|
+
...props
|
|
8
|
+
}) {
|
|
9
|
+
return createElement(Link, { ...props, to: href ?? to });
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
RouterLink
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
//# debugId=D9C7D4DF88CF5C0964756E2164756E21
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/link/router-link.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { createElement, type ReactElement, type RefAttributes } from 'react';\nimport { Link, type LinkProps, type To } from 'react-router';\n\n/**\n * The props of {@link RouterLink}: React Router's `Link` props, with the\n * destination given as `href` (what a design system's link component hands\n * over) or as `to` (React Router's own name), never both.\n */\nexport type RouterLinkProps = Omit<LinkProps, 'to'> &\n\tRefAttributes<HTMLAnchorElement> &\n\t({ href: To; to?: undefined } | { to: To; href?: undefined });\n\n/**\n * React Router's `Link` for a UI library that renders its links through a\n * component of its own (a `LinkComponentProvider`): it receives `href` and\n * spreads every other prop (`className`, `children`, `aria-*`, `ref`, ...)\n * onto the anchor. Navigation stays client-side and `<Link>`'s own props\n * (`prefetch`, `replace`, `reloadDocument`, ...) still apply.\n *\n * ```tsx\n * <LinkComponentProvider component={RouterLink}>...</LinkComponentProvider>\n * ```\n */\nexport function RouterLink({\n\thref,\n\tto,\n\t...props\n}: RouterLinkProps): ReactElement {\n\t// The union guarantees one of the two is set; TypeScript cannot see it\n\t// through the destructuring, hence the cast.\n\treturn createElement(Link, { ...props, to: (href ?? to) as To });\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AAAA;AACA;AAsBO,SAAS,UAAU;AAAA,EACzB;AAAA,EACA;AAAA,KACG;AAAA,GAC8B;AAAA,EAGjC,OAAO,cAAc,MAAM,KAAK,OAAO,IAAK,QAAQ,GAAU,CAAC;AAAA;",
|
|
8
|
+
"debugId": "D9C7D4DF88CF5C0964756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ReactElement, type RefAttributes } from 'react';
|
|
2
|
+
import { type LinkProps, type To } from 'react-router';
|
|
3
|
+
/**
|
|
4
|
+
* The props of {@link RouterLink}: React Router's `Link` props, with the
|
|
5
|
+
* destination given as `href` (what a design system's link component hands
|
|
6
|
+
* over) or as `to` (React Router's own name), never both.
|
|
7
|
+
*/
|
|
8
|
+
export type RouterLinkProps = Omit<LinkProps, 'to'> & RefAttributes<HTMLAnchorElement> & ({
|
|
9
|
+
href: To;
|
|
10
|
+
to?: undefined;
|
|
11
|
+
} | {
|
|
12
|
+
to: To;
|
|
13
|
+
href?: undefined;
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* React Router's `Link` for a UI library that renders its links through a
|
|
17
|
+
* component of its own (a `LinkComponentProvider`): it receives `href` and
|
|
18
|
+
* spreads every other prop (`className`, `children`, `aria-*`, `ref`, ...)
|
|
19
|
+
* onto the anchor. Navigation stays client-side and `<Link>`'s own props
|
|
20
|
+
* (`prefetch`, `replace`, `reloadDocument`, ...) still apply.
|
|
21
|
+
*
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <LinkComponentProvider component={RouterLink}>...</LinkComponentProvider>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function RouterLink({ href, to, ...props }: RouterLinkProps): ReactElement;
|
|
27
|
+
//# sourceMappingURL=router-link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-link.d.ts","sourceRoot":"","sources":["../../src/link/router-link.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAC7E,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,EAAE,EAAE,MAAM,cAAc,CAAC;AAE7D;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,GAClD,aAAa,CAAC,iBAAiB,CAAC,GAChC,CAAC;IAAE,IAAI,EAAE,EAAE,CAAC;IAAC,EAAE,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AAE/D;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,EAC1B,IAAI,EACJ,EAAE,EACF,GAAG,KAAK,EACR,EAAE,eAAe,GAAG,YAAY,CAIhC"}
|
package/dist/react-router.d.ts
CHANGED
|
@@ -25,6 +25,13 @@ export interface ReactRouterOptions<Ctx> {
|
|
|
25
25
|
* catch-all. Ignored in `development`, where Vite serves them.
|
|
26
26
|
*/
|
|
27
27
|
readonly client?: string | URL;
|
|
28
|
+
/**
|
|
29
|
+
* Serves the `.br` and `.gz` copies `alxia()` writes beside the client
|
|
30
|
+
* build's files to a browser that accepts them, with `Vary:
|
|
31
|
+
* Accept-Encoding`: `true` by default. `false` serves the files as they
|
|
32
|
+
* are.
|
|
33
|
+
*/
|
|
34
|
+
readonly precompressed?: boolean;
|
|
28
35
|
}
|
|
29
36
|
/**
|
|
30
37
|
* Whether `reactRouter()` declared this route: the catch-all, or one of the
|
|
@@ -57,5 +64,5 @@ export declare function reactRouter<Ctx extends object, Prefix extends string>(a
|
|
|
57
64
|
* `isReactRouterRoute`: what `reactRouter()` does with `client`, apart, so
|
|
58
65
|
* that `createServer()` serves them before the middlewares of `configure`.
|
|
59
66
|
*/
|
|
60
|
-
export declare function declareClient(app: AnyAlxia, client: string | URL): void;
|
|
67
|
+
export declare function declareClient(app: AnyAlxia, client: string | URL, precompressed?: boolean): void;
|
|
61
68
|
//# sourceMappingURL=react-router.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-router.d.ts","sourceRoot":"","sources":["../src/react-router.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,YAAY,EAEjB,KAAK,eAAe,EAEpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAGN,qBAAqB,EACrB,KAAK,WAAW,EAChB,MAAM,cAAc,CAAC;AAItB,MAAM,WAAW,kBAAkB,CAAC,GAAG;IACtC;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,CAAC,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;IAChE,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CACzB,GAAG,EAAE,WAAW,GAAG,GAAG,EACtB,OAAO,EAAE,qBAAqB,KAC1B,YAAY,CAAC,IAAI,CAAC,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"react-router.d.ts","sourceRoot":"","sources":["../src/react-router.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,YAAY,EAEjB,KAAK,eAAe,EAEpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAGN,qBAAqB,EACrB,KAAK,WAAW,EAChB,MAAM,cAAc,CAAC;AAItB,MAAM,WAAW,kBAAkB,CAAC,GAAG;IACtC;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,CAAC,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;IAChE,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CACzB,GAAG,EAAE,WAAW,GAAG,GAAG,EACtB,OAAO,EAAE,qBAAqB,KAC1B,YAAY,CAAC,IAAI,CAAC,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;CACjC;AAQD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAElE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,GAAG,SAAS,MAAM,EAAE,MAAM,SAAS,MAAM,EACpE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,EACvB,OAAO,EAAE,kBAAkB,CAAC,GAAG,CAAC,GAC9B,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CA0BpB;AAiBD;;;;GAIG;AACH,wBAAgB,aAAa,CAC5B,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,MAAM,GAAG,GAAG,EACpB,aAAa,UAAO,GAClB,IAAI,CAIN"}
|
package/dist/server.d.ts
CHANGED
|
@@ -57,6 +57,12 @@ export interface ServerOptions<Before extends AnyAlxia, App extends AnyAlxia> {
|
|
|
57
57
|
* `beforeAll` or `configure`.
|
|
58
58
|
*/
|
|
59
59
|
readonly client?: string | URL | false;
|
|
60
|
+
/**
|
|
61
|
+
* Serves the client's `.br` and `.gz` copies, which `alxia()` writes at
|
|
62
|
+
* build time, to a browser that accepts them: `true` by default.
|
|
63
|
+
* `false` serves the files as they are.
|
|
64
|
+
*/
|
|
65
|
+
readonly precompressed?: boolean;
|
|
60
66
|
/**
|
|
61
67
|
* `listen`'s options for `bun build/server/index.js` — `shutdownTimeout`,
|
|
62
68
|
* `signals` among them; a `port` or `hostname` here wins over `PORT` (3000)
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACN,KAAK,KAAK,EACV,KAAK,QAAQ,EAEb,KAAK,SAAS,EACd,KAAK,KAAK,EAEV,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGvE,gFAAgF;AAChF,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAExC;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,CAAC,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;IAChE,uFAAuF;IACvF,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IAC7C,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,QAAQ,EAAE,GAAG,SAAS,QAAQ;IAC3E;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,MAAM,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,GAAG,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CACzB,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,EACnB,OAAO,EAAE,qBAAqB,KAC1B,YAAY,CAAC,IAAI,CAAC,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IACvC,qFAAqF;IACrF,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;CAC1D;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAAC,GAAG,SAAS,QAAQ;IACtD;;;;;;;OAOG;IACH,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,GAAG,CAAC;IAClC;;;;;OAKG;IACH,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAC3B,MAAM,SAAS,QAAQ,GAAG,QAAQ,EAClC,GAAG,SAAS,QAAQ,GAAG,MAAM,EAC5B,OAAO,GAAE,aAAa,CAAC,MAAM,EAAE,GAAG,CAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAqDlE"}
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACN,KAAK,KAAK,EACV,KAAK,QAAQ,EAEb,KAAK,SAAS,EACd,KAAK,KAAK,EAEV,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGvE,gFAAgF;AAChF,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAExC;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,CAAC,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;IAChE,uFAAuF;IACvF,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IAC7C,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,QAAQ,EAAE,GAAG,SAAS,QAAQ;IAC3E;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,MAAM,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,GAAG,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CACzB,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,EACnB,OAAO,EAAE,qBAAqB,KAC1B,YAAY,CAAC,IAAI,CAAC,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IACvC,qFAAqF;IACrF,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;CAC1D;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAAC,GAAG,SAAS,QAAQ;IACtD;;;;;;;OAOG;IACH,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,GAAG,CAAC;IAClC;;;;;OAKG;IACH,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAC3B,MAAM,SAAS,QAAQ,GAAG,QAAQ,EAClC,GAAG,SAAS,QAAQ,GAAG,MAAM,EAC5B,OAAO,GAAE,aAAa,CAAC,MAAM,EAAE,GAAG,CAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAqDlE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface PrecompressOptions {
|
|
2
|
+
/** The smallest file, in bytes, that gets copies: 1024 by default. */
|
|
3
|
+
readonly minSize?: number;
|
|
4
|
+
}
|
|
5
|
+
export interface Precompressed {
|
|
6
|
+
/** The files that got copies. */
|
|
7
|
+
readonly files: number;
|
|
8
|
+
/** Their size before, and the size of their brotli copies. */
|
|
9
|
+
readonly bytes: number;
|
|
10
|
+
readonly brotliBytes: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Writes `<file>.br` and `<file>.gz` beside each compressible file of
|
|
14
|
+
* `client` of at least `minSize` bytes, whichever is smaller than the file
|
|
15
|
+
* itself. Brotli at its best quality: it runs once, at build time.
|
|
16
|
+
*/
|
|
17
|
+
export declare function precompressClient(client: string, options?: PrecompressOptions): Promise<Precompressed>;
|
|
18
|
+
//# sourceMappingURL=compress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../../src/vite/compress.ts"],"names":[],"mappings":"AAkCA,MAAM,WAAW,kBAAkB;IAClC,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC7B,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAUD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,kBAAuB,GAC9B,OAAO,CAAC,aAAa,CAAC,CAqCxB"}
|
package/dist/vite/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Plugin } from 'vite';
|
|
2
|
+
import { type PrecompressOptions } from './compress';
|
|
2
3
|
import { type AlxiaWorkerOptions } from './worker';
|
|
4
|
+
export type { PrecompressOptions } from './compress';
|
|
3
5
|
export type { AlxiaWorkerOptions } from './worker';
|
|
4
6
|
export interface AlxiaOptions {
|
|
5
7
|
/**
|
|
@@ -17,6 +19,14 @@ export interface AlxiaOptions {
|
|
|
17
19
|
* nothing without it; `false` builds none. Needs Bun.
|
|
18
20
|
*/
|
|
19
21
|
readonly worker?: false | string | AlxiaWorkerOptions;
|
|
22
|
+
/**
|
|
23
|
+
* Writes `.br` and `.gz` copies beside the client build's compressible
|
|
24
|
+
* files (JavaScript, CSS, HTML, SVG, JSON, text, WebAssembly, source
|
|
25
|
+
* maps, fonts) of at least `minSize` bytes (1024), after the service
|
|
26
|
+
* worker is built: the server sends them to a browser that accepts them.
|
|
27
|
+
* On by default; `false` writes none.
|
|
28
|
+
*/
|
|
29
|
+
readonly precompress?: false | PrecompressOptions;
|
|
20
30
|
}
|
|
21
31
|
/**
|
|
22
32
|
* The Vite plugin that makes alxia the server of a React Router app,
|
package/dist/vite/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vite/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAkB,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vite/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAkB,MAAM,MAAM,CAAC;AAEnD,OAAO,EAAE,KAAK,kBAAkB,EAAqB,MAAM,YAAY,CAAC;AAexE,OAAO,EAAE,KAAK,kBAAkB,EAAkB,MAAM,UAAU,CAAC;AAEnE,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEnD,MAAM,WAAW,YAAY;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,kBAAkB,CAAC;IACtD;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,KAAK,GAAG,kBAAkB,CAAC;CAClD;AAwBD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,MAAM,CAqFxD"}
|
package/dist/vite/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "../chunks/index-6jf7zpxz.js";
|
|
9
9
|
|
|
10
10
|
// src/vite/index.ts
|
|
11
|
-
import { relative as relative3 } from "node:path";
|
|
11
|
+
import { join as join4, relative as relative3 } from "node:path";
|
|
12
12
|
|
|
13
13
|
// src/vite/bun.ts
|
|
14
14
|
import { builtinModules } from "node:module";
|
|
@@ -58,9 +58,85 @@ function ssrEnvironment(options, command) {
|
|
|
58
58
|
return { ...added, resolve: { ...added.resolve, ...bundled.resolve } };
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// src/vite/compress.ts
|
|
62
|
+
import { readdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
63
|
+
import { extname, join } from "node:path";
|
|
64
|
+
import { promisify } from "node:util";
|
|
65
|
+
import { brotliCompress, constants, gzip } from "node:zlib";
|
|
66
|
+
var brotli = promisify(brotliCompress);
|
|
67
|
+
var deflate = promisify(gzip);
|
|
68
|
+
var COMPRESSIBLE = new Set([
|
|
69
|
+
".js",
|
|
70
|
+
".mjs",
|
|
71
|
+
".cjs",
|
|
72
|
+
".css",
|
|
73
|
+
".html",
|
|
74
|
+
".htm",
|
|
75
|
+
".svg",
|
|
76
|
+
".json",
|
|
77
|
+
".map",
|
|
78
|
+
".txt",
|
|
79
|
+
".xml",
|
|
80
|
+
".webmanifest",
|
|
81
|
+
".wasm",
|
|
82
|
+
".ico",
|
|
83
|
+
".ttf",
|
|
84
|
+
".otf",
|
|
85
|
+
".eot"
|
|
86
|
+
]);
|
|
87
|
+
async function* walk(dir) {
|
|
88
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
89
|
+
const path = join(dir, entry.name);
|
|
90
|
+
if (entry.isDirectory())
|
|
91
|
+
yield* walk(path);
|
|
92
|
+
else if (entry.isFile())
|
|
93
|
+
yield path;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async function precompressClient(client, options = {}) {
|
|
97
|
+
const minSize = options.minSize ?? 1024;
|
|
98
|
+
let files = 0;
|
|
99
|
+
let bytes = 0;
|
|
100
|
+
let brotliBytes = 0;
|
|
101
|
+
for await (const path of walk(client)) {
|
|
102
|
+
if (!COMPRESSIBLE.has(extname(path).toLowerCase()))
|
|
103
|
+
continue;
|
|
104
|
+
const body = await readFile(path);
|
|
105
|
+
if (body.length < minSize)
|
|
106
|
+
continue;
|
|
107
|
+
const [br, gz] = await Promise.all([
|
|
108
|
+
brotli(body, {
|
|
109
|
+
params: {
|
|
110
|
+
[constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MAX_QUALITY,
|
|
111
|
+
[constants.BROTLI_PARAM_SIZE_HINT]: body.length
|
|
112
|
+
}
|
|
113
|
+
}),
|
|
114
|
+
deflate(body, { level: 9 })
|
|
115
|
+
]);
|
|
116
|
+
let written = false;
|
|
117
|
+
for (const [extension, copy] of [
|
|
118
|
+
["br", br],
|
|
119
|
+
["gz", gz]
|
|
120
|
+
]) {
|
|
121
|
+
if (copy.length < body.length) {
|
|
122
|
+
await writeFile(`${path}.${extension}`, copy);
|
|
123
|
+
written = true;
|
|
124
|
+
} else {
|
|
125
|
+
await rm(`${path}.${extension}`, { force: true });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!written)
|
|
129
|
+
continue;
|
|
130
|
+
files += 1;
|
|
131
|
+
bytes += body.length;
|
|
132
|
+
brotliBytes += Math.min(br.length, body.length);
|
|
133
|
+
}
|
|
134
|
+
return { files, bytes, brotliBytes };
|
|
135
|
+
}
|
|
136
|
+
|
|
61
137
|
// src/vite/config.ts
|
|
62
138
|
import { existsSync } from "node:fs";
|
|
63
|
-
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
139
|
+
import { dirname, isAbsolute, join as join2, relative, resolve } from "node:path";
|
|
64
140
|
var SERVER = "virtual:alxia-react-router/server";
|
|
65
141
|
var DEFAULT = `${SERVER}-default`;
|
|
66
142
|
function contextOf(config) {
|
|
@@ -81,17 +157,17 @@ function serverFile(entry, config) {
|
|
|
81
157
|
}
|
|
82
158
|
return file;
|
|
83
159
|
}
|
|
84
|
-
const file =
|
|
160
|
+
const file = join2(contextOf(config).appDirectory, "server.ts");
|
|
85
161
|
return existsSync(file) ? file : undefined;
|
|
86
162
|
}
|
|
87
163
|
function serverBuildPath(config) {
|
|
88
164
|
const rr = contextOf(config);
|
|
89
|
-
const outDir = resolve(config.root, config.environments["ssr"]?.build.outDir ??
|
|
90
|
-
return
|
|
165
|
+
const outDir = resolve(config.root, config.environments["ssr"]?.build.outDir ?? join2(rr.buildDirectory, "server"));
|
|
166
|
+
return join2(outDir, rr.serverBuildFile);
|
|
91
167
|
}
|
|
92
168
|
function clientPath(config) {
|
|
93
169
|
const built = dirname(serverBuildPath(config));
|
|
94
|
-
const path = relative(built,
|
|
170
|
+
const path = relative(built, join2(contextOf(config).buildDirectory, "client"));
|
|
95
171
|
return path.startsWith(".") ? path : `./${path}`;
|
|
96
172
|
}
|
|
97
173
|
function serverBuildOptions(rolldown) {
|
|
@@ -402,7 +478,7 @@ function requireBun(command, hint = `bun --bun ${command}`, onBun = globalThis.B
|
|
|
402
478
|
|
|
403
479
|
// src/vite/worker.ts
|
|
404
480
|
import { existsSync as existsSync3 } from "node:fs";
|
|
405
|
-
import { basename, isAbsolute as isAbsolute2, join as
|
|
481
|
+
import { basename, isAbsolute as isAbsolute2, join as join3, resolve as resolve2 } from "node:path";
|
|
406
482
|
function workerFile(option, config) {
|
|
407
483
|
if (option === false)
|
|
408
484
|
return;
|
|
@@ -414,7 +490,7 @@ function workerFile(option, config) {
|
|
|
414
490
|
}
|
|
415
491
|
return file;
|
|
416
492
|
}
|
|
417
|
-
const file =
|
|
493
|
+
const file = join3(contextOf(config).appDirectory, "service-worker.ts");
|
|
418
494
|
return existsSync3(file) ? file : undefined;
|
|
419
495
|
}
|
|
420
496
|
var MB = (bytes) => (bytes / 1024 / 1024).toFixed(2);
|
|
@@ -429,7 +505,7 @@ async function buildAppWorker(config, option) {
|
|
|
429
505
|
...rest,
|
|
430
506
|
file,
|
|
431
507
|
root: config.root,
|
|
432
|
-
client:
|
|
508
|
+
client: join3(contextOf(config).buildDirectory, "client")
|
|
433
509
|
}).catch((error) => {
|
|
434
510
|
throw new Error(`${NAME}: ${error.message}`, { cause: error });
|
|
435
511
|
});
|
|
@@ -500,8 +576,13 @@ function alxia(options = {}) {
|
|
|
500
576
|
buildApp: {
|
|
501
577
|
order: "post",
|
|
502
578
|
async handler() {
|
|
503
|
-
if (config
|
|
504
|
-
|
|
579
|
+
if (config === undefined)
|
|
580
|
+
return;
|
|
581
|
+
await buildAppWorker(config, options.worker);
|
|
582
|
+
if (!enabled || options.precompress === false)
|
|
583
|
+
return;
|
|
584
|
+
const done = await precompressClient(join4(contextOf(config).buildDirectory, "client"), options.precompress);
|
|
585
|
+
config.logger.info(`✓ ${done.files} client files precompressed (${(done.bytes / 1024).toFixed(0)} kB → ${(done.brotliBytes / 1024).toFixed(0)} kB brotli)`);
|
|
505
586
|
}
|
|
506
587
|
},
|
|
507
588
|
configureServer(server) {
|
|
@@ -522,5 +603,5 @@ export {
|
|
|
522
603
|
alxia
|
|
523
604
|
};
|
|
524
605
|
|
|
525
|
-
//# debugId=
|
|
606
|
+
//# debugId=3DE9F1517A9D4E4F64756E2164756E21
|
|
526
607
|
//# sourceMappingURL=index.js.map
|
package/dist/vite/index.js.map
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/vite/index.ts", "../src/vite/bun.ts", "../src/vite/bundle.ts", "../src/vite/config.ts", "../src/vite/node.ts", "../src/vite/socket.ts", "../src/vite/dev.ts", "../src/vite/inline.ts", "../src/vite/preview.ts", "../src/vite/runtime.ts", "../src/vite/worker.ts"],
|
|
3
|
+
"sources": ["../src/vite/index.ts", "../src/vite/bun.ts", "../src/vite/bundle.ts", "../src/vite/compress.ts", "../src/vite/config.ts", "../src/vite/node.ts", "../src/vite/socket.ts", "../src/vite/dev.ts", "../src/vite/inline.ts", "../src/vite/preview.ts", "../src/vite/runtime.ts", "../src/vite/worker.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * `@alxia/react-router/vite`: `alxia()`, the Vite plugin that makes alxia\n * the server of a React Router app, under `react-router dev` and in\n * `react-router build`, with or without an `app/server.ts`.\n */\nimport { relative } from 'node:path';\n// Types only: the plugin runs on whichever Vite the app has, never on a\n// copy of this package's own.\nimport type { Plugin, ResolvedConfig } from 'vite';\nimport { ssrEnvironment } from './bundle';\nimport {\n\tclientPath,\n\tcontextOf,\n\tDEFAULT,\n\tisChildCompiler,\n\tSERVER,\n\tserverBuildOptions,\n\tserverFile,\n} from './config';\nimport { serveDev } from './dev';\nimport { NAME, PASS_THROUGH, serverEntry } from './entry';\nimport { inlineAliases, inlinedFile } from './inline';\nimport { servePreview } from './preview';\nimport { requireBun } from './runtime';\nimport { type AlxiaWorkerOptions, buildAppWorker } from './worker';\n\nexport type { AlxiaWorkerOptions } from './worker';\n\nexport interface AlxiaOptions {\n\t/**\n\t * The server file, relative to Vite's root: a module whose default export\n\t * is `createServer()` from `@alxia/react-router`. By default `server.ts`\n\t * in React Router's app directory, `app/server.ts`, when it exists, and\n\t * otherwise `createServer()` with no options.\n\t */\n\treadonly entry?: string;\n\t/**\n\t * The service worker, bundled into `build/client/service-worker.js` after\n\t * `react-router build`, with its precache list: a file relative to Vite's\n\t * root, or options (`file`, `contract`, `offline`, `precacheAssets`,\n\t * `minify`). By default `app/service-worker.ts` when it exists, and\n\t * nothing without it; `false` builds none. Needs Bun.\n\t */\n\treadonly worker?: false | string | AlxiaWorkerOptions;\n}\n\nconst RESOLVED_SERVER = `\\0${SERVER}`;\nconst RESOLVED_DEFAULT = `\\0${DEFAULT}`;\n\n/**\n * Whether there is a server to be: not in the Vite server React Router\n * compiles route modules in, nor in a single-page app. Throws when the\n * server build would be split in several.\n */\nfunction servesApp(resolved: ResolvedConfig): boolean {\n\t// React Router compiles route modules in a Vite server of its own,\n\t// with every plugin but its own: there is nothing to serve there.\n\tif (isChildCompiler(resolved)) return false;\n\tconst rr = contextOf(resolved);\n\t// A single-page app has no server to be.\n\tif (rr.ssr && rr.serverBundles !== undefined) {\n\t\tthrow new Error(\n\t\t\t`${NAME}: serverBundles splits React Router's server build in several, and alxia serves one. Remove serverBundles from react-router.config.ts.`,\n\t\t);\n\t}\n\treturn rr.ssr;\n}\n\n/**\n * The Vite plugin that makes alxia the server of a React Router app,\n * anywhere in `plugins`:\n *\n * ```ts\n * export default defineConfig({ plugins: [alxia(), reactRouter()] });\n * ```\n *\n * - **`react-router dev`**: every request Vite does not answer itself —\n * pages, data, `/api` — goes to the server, loaded through Vite's SSR\n * runner. HMR, an edit to the server, the app's own context keys and\n * its WebSocket routes work, with no restart.\n * - **`react-router build`**: `build/server/index.js` is the server, with\n * React Router's build inside it. `bun build/server/index.js` listens on\n * `PORT` (3000) and `HOST` (`0.0.0.0`); importing it starts nothing.\n * - **`vite preview`**: every request goes to that built server, as it\n * would answer it; so does React Router's prerendering.\n * - **Built for Bun**: the `ssr` environment resolves packages with the\n * `bun` export condition, leaves `bun` and `bun:*` external, and targets\n * `esnext` unless the app set a target. What the app set is kept.\n * - **Self-contained**: `react-router build` bundles every package into\n * `build/server/index.js` (`ssr.noExternal: true`), so `build/` runs with\n * no `node_modules`. `ssr.external` keeps the packages it names external,\n * and `ssr.external: true` all of them.\n *\n * The server is `app/server.ts`'s default export, `createServer()` from\n * `@alxia/react-router`, or without that file `createServer()` as it is.\n */\nexport function alxia(options: AlxiaOptions = {}): Plugin {\n\tlet config: ResolvedConfig | undefined;\n\tlet enabled = true;\n\n\treturn {\n\t\tname: NAME,\n\t\t// Before React Router's plugin, wherever it is listed: its config reads\n\t\t// the server build's input from this one's, and its dev middleware,\n\t\t// which would render the pages without alxia, comes after this one's.\n\t\tenforce: 'pre',\n\t\tconfig(_config, env) {\n\t\t\tif (env.command === 'serve') return inlineAliases();\n\t\t\tif (env.command !== 'build') return;\n\t\t\t// Vite 7's types know neither `rolldownVersion` nor `rolldownOptions`.\n\t\t\tconst meta = this.meta as { readonly rolldownVersion?: string };\n\t\t\tconst bundler = serverBuildOptions(meta.rolldownVersion !== undefined);\n\t\t\treturn { environments: { ssr: { build: bundler as never } } };\n\t\t},\n\t\tconfigEnvironment(name, options, env) {\n\t\t\t// After every config hook, React Router's included: the server\n\t\t\t// environment as the app and the plugins left it, built for Bun.\n\t\t\t// An app that chose `ssr.target: 'webworker'` keeps Vite's own.\n\t\t\tif (name !== 'ssr' || env.isSsrTargetWebworker === true) return;\n\t\t\treturn ssrEnvironment(options, env.command);\n\t\t},\n\t\tconfigResolved(resolved) {\n\t\t\tconfig = resolved;\n\t\t\tenabled = servesApp(resolved);\n\t\t},\n\t\tresolveId(id) {\n\t\t\tif (id === SERVER) return RESOLVED_SERVER;\n\t\t\tif (id === DEFAULT) return RESOLVED_DEFAULT;\n\t\t\t// An absolute path is never external: see inline.ts.\n\t\t\tif (this.environment?.name === 'ssr') return inlinedFile(id);\n\t\t\treturn undefined;\n\t\t},\n\t\tload(id) {\n\t\t\tif (id !== RESOLVED_SERVER && id !== RESOLVED_DEFAULT) return;\n\t\t\tif (config === undefined) return;\n\t\t\t// Disabled, a single-page app: React Router still builds its server\n\t\t\t// build, to render index.html, from this input.\n\t\t\tif (!enabled) return PASS_THROUGH;\n\t\t\tconst dev = config.command === 'serve';\n\t\t\tconst file =\n\t\t\t\tid === RESOLVED_DEFAULT ? undefined : serverFile(options.entry, config);\n\t\t\treturn serverEntry({\n\t\t\t\tfile,\n\t\t\t\tlabel: file === undefined ? '' : relative(config.root, file),\n\t\t\t\tdev,\n\t\t\t\tclient: dev ? undefined : clientPath(config),\n\t\t\t});\n\t\t},\n\t\tbuildApp: {\n\t\t\t// After React Router's builder: its client build, the one the worker reads.\n\t\t\torder: 'post',\n\t\t\tasync handler() {\n\t\t\t\tif (config
|
|
5
|
+
"/**\n * `@alxia/react-router/vite`: `alxia()`, the Vite plugin that makes alxia\n * the server of a React Router app, under `react-router dev` and in\n * `react-router build`, with or without an `app/server.ts`.\n */\nimport { join, relative } from 'node:path';\n// Types only: the plugin runs on whichever Vite the app has, never on a\n// copy of this package's own.\nimport type { Plugin, ResolvedConfig } from 'vite';\nimport { ssrEnvironment } from './bundle';\nimport { type PrecompressOptions, precompressClient } from './compress';\nimport {\n\tclientPath,\n\tcontextOf,\n\tDEFAULT,\n\tisChildCompiler,\n\tSERVER,\n\tserverBuildOptions,\n\tserverFile,\n} from './config';\nimport { serveDev } from './dev';\nimport { NAME, PASS_THROUGH, serverEntry } from './entry';\nimport { inlineAliases, inlinedFile } from './inline';\nimport { servePreview } from './preview';\nimport { requireBun } from './runtime';\nimport { type AlxiaWorkerOptions, buildAppWorker } from './worker';\n\nexport type { PrecompressOptions } from './compress';\nexport type { AlxiaWorkerOptions } from './worker';\n\nexport interface AlxiaOptions {\n\t/**\n\t * The server file, relative to Vite's root: a module whose default export\n\t * is `createServer()` from `@alxia/react-router`. By default `server.ts`\n\t * in React Router's app directory, `app/server.ts`, when it exists, and\n\t * otherwise `createServer()` with no options.\n\t */\n\treadonly entry?: string;\n\t/**\n\t * The service worker, bundled into `build/client/service-worker.js` after\n\t * `react-router build`, with its precache list: a file relative to Vite's\n\t * root, or options (`file`, `contract`, `offline`, `precacheAssets`,\n\t * `minify`). By default `app/service-worker.ts` when it exists, and\n\t * nothing without it; `false` builds none. Needs Bun.\n\t */\n\treadonly worker?: false | string | AlxiaWorkerOptions;\n\t/**\n\t * Writes `.br` and `.gz` copies beside the client build's compressible\n\t * files (JavaScript, CSS, HTML, SVG, JSON, text, WebAssembly, source\n\t * maps, fonts) of at least `minSize` bytes (1024), after the service\n\t * worker is built: the server sends them to a browser that accepts them.\n\t * On by default; `false` writes none.\n\t */\n\treadonly precompress?: false | PrecompressOptions;\n}\n\nconst RESOLVED_SERVER = `\\0${SERVER}`;\nconst RESOLVED_DEFAULT = `\\0${DEFAULT}`;\n\n/**\n * Whether there is a server to be: not in the Vite server React Router\n * compiles route modules in, nor in a single-page app. Throws when the\n * server build would be split in several.\n */\nfunction servesApp(resolved: ResolvedConfig): boolean {\n\t// React Router compiles route modules in a Vite server of its own,\n\t// with every plugin but its own: there is nothing to serve there.\n\tif (isChildCompiler(resolved)) return false;\n\tconst rr = contextOf(resolved);\n\t// A single-page app has no server to be.\n\tif (rr.ssr && rr.serverBundles !== undefined) {\n\t\tthrow new Error(\n\t\t\t`${NAME}: serverBundles splits React Router's server build in several, and alxia serves one. Remove serverBundles from react-router.config.ts.`,\n\t\t);\n\t}\n\treturn rr.ssr;\n}\n\n/**\n * The Vite plugin that makes alxia the server of a React Router app,\n * anywhere in `plugins`:\n *\n * ```ts\n * export default defineConfig({ plugins: [alxia(), reactRouter()] });\n * ```\n *\n * - **`react-router dev`**: every request Vite does not answer itself —\n * pages, data, `/api` — goes to the server, loaded through Vite's SSR\n * runner. HMR, an edit to the server, the app's own context keys and\n * its WebSocket routes work, with no restart.\n * - **`react-router build`**: `build/server/index.js` is the server, with\n * React Router's build inside it. `bun build/server/index.js` listens on\n * `PORT` (3000) and `HOST` (`0.0.0.0`); importing it starts nothing.\n * - **`vite preview`**: every request goes to that built server, as it\n * would answer it; so does React Router's prerendering.\n * - **Built for Bun**: the `ssr` environment resolves packages with the\n * `bun` export condition, leaves `bun` and `bun:*` external, and targets\n * `esnext` unless the app set a target. What the app set is kept.\n * - **Self-contained**: `react-router build` bundles every package into\n * `build/server/index.js` (`ssr.noExternal: true`), so `build/` runs with\n * no `node_modules`. `ssr.external` keeps the packages it names external,\n * and `ssr.external: true` all of them.\n *\n * The server is `app/server.ts`'s default export, `createServer()` from\n * `@alxia/react-router`, or without that file `createServer()` as it is.\n */\nexport function alxia(options: AlxiaOptions = {}): Plugin {\n\tlet config: ResolvedConfig | undefined;\n\tlet enabled = true;\n\n\treturn {\n\t\tname: NAME,\n\t\t// Before React Router's plugin, wherever it is listed: its config reads\n\t\t// the server build's input from this one's, and its dev middleware,\n\t\t// which would render the pages without alxia, comes after this one's.\n\t\tenforce: 'pre',\n\t\tconfig(_config, env) {\n\t\t\tif (env.command === 'serve') return inlineAliases();\n\t\t\tif (env.command !== 'build') return;\n\t\t\t// Vite 7's types know neither `rolldownVersion` nor `rolldownOptions`.\n\t\t\tconst meta = this.meta as { readonly rolldownVersion?: string };\n\t\t\tconst bundler = serverBuildOptions(meta.rolldownVersion !== undefined);\n\t\t\treturn { environments: { ssr: { build: bundler as never } } };\n\t\t},\n\t\tconfigEnvironment(name, options, env) {\n\t\t\t// After every config hook, React Router's included: the server\n\t\t\t// environment as the app and the plugins left it, built for Bun.\n\t\t\t// An app that chose `ssr.target: 'webworker'` keeps Vite's own.\n\t\t\tif (name !== 'ssr' || env.isSsrTargetWebworker === true) return;\n\t\t\treturn ssrEnvironment(options, env.command);\n\t\t},\n\t\tconfigResolved(resolved) {\n\t\t\tconfig = resolved;\n\t\t\tenabled = servesApp(resolved);\n\t\t},\n\t\tresolveId(id) {\n\t\t\tif (id === SERVER) return RESOLVED_SERVER;\n\t\t\tif (id === DEFAULT) return RESOLVED_DEFAULT;\n\t\t\t// An absolute path is never external: see inline.ts.\n\t\t\tif (this.environment?.name === 'ssr') return inlinedFile(id);\n\t\t\treturn undefined;\n\t\t},\n\t\tload(id) {\n\t\t\tif (id !== RESOLVED_SERVER && id !== RESOLVED_DEFAULT) return;\n\t\t\tif (config === undefined) return;\n\t\t\t// Disabled, a single-page app: React Router still builds its server\n\t\t\t// build, to render index.html, from this input.\n\t\t\tif (!enabled) return PASS_THROUGH;\n\t\t\tconst dev = config.command === 'serve';\n\t\t\tconst file =\n\t\t\t\tid === RESOLVED_DEFAULT ? undefined : serverFile(options.entry, config);\n\t\t\treturn serverEntry({\n\t\t\t\tfile,\n\t\t\t\tlabel: file === undefined ? '' : relative(config.root, file),\n\t\t\t\tdev,\n\t\t\t\tclient: dev ? undefined : clientPath(config),\n\t\t\t});\n\t\t},\n\t\tbuildApp: {\n\t\t\t// After React Router's builder: its client build, the one the worker reads.\n\t\t\torder: 'post',\n\t\t\tasync handler() {\n\t\t\t\tif (config === undefined) return;\n\t\t\t\tawait buildAppWorker(config, options.worker);\n\t\t\t\tif (!enabled || options.precompress === false) return;\n\t\t\t\tconst done = await precompressClient(\n\t\t\t\t\tjoin(contextOf(config).buildDirectory, 'client'),\n\t\t\t\t\toptions.precompress,\n\t\t\t\t);\n\t\t\t\tconfig.logger.info(\n\t\t\t\t\t`✓ ${done.files} client files precompressed (${(done.bytes / 1024).toFixed(0)} kB → ${(done.brotliBytes / 1024).toFixed(0)} kB brotli)`,\n\t\t\t\t);\n\t\t\t},\n\t\t},\n\t\tconfigureServer(server) {\n\t\t\tif (!enabled) return;\n\t\t\trequireBun('react-router dev');\n\t\t\treturn serveDev(server, options.entry);\n\t\t},\n\t\tconfigurePreviewServer(server) {\n\t\t\tif (!enabled) return;\n\t\t\t// React Router prerenders through a preview server of its own,\n\t\t\t// resolved as `serve` too: the message cannot tell the two apart.\n\t\t\trequireBun(\n\t\t\t\t'vite preview, or a react-router build that prerenders,',\n\t\t\t\t'bun --bun vite preview or bun --bun react-router build',\n\t\t\t);\n\t\t\t// Before Vite's own files: the built server answers every request.\n\t\t\tservePreview(server);\n\t\t},\n\t};\n}\n",
|
|
6
6
|
"/**\n * The server build, for Bun: what the plugin adds to Vite's `ssr`\n * environment so that `build/server/index.js` is built for the runtime\n * that runs it, and so is the module the dev server loads.\n */\nimport { builtinModules } from 'node:module';\nimport type { EnvironmentOptions } from 'vite';\n\n/** The export condition Bun resolves a package by, and the plugin adds. */\nconst BUN_CONDITION = 'bun';\n\n/**\n * Vite's own builtins for a server environment (its `nodeLikeBuiltins`),\n * which it uses when the config names none: Node's modules, `node:*` and\n * `bun:*`. Bare `bun` is among Node's modules only when Vite runs on Bun.\n */\nconst VITE_BUILTINS: readonly (string | RegExp)[] = [\n\t...builtinModules.filter((id) => !id.includes(':')),\n\t/^node:/,\n\t/^bun:/,\n];\n\n/**\n * Vite's default conditions for a server environment, and for its\n * externals, which it uses when the config names none. React Router's\n * plugin always names them; these are for a config where nothing did.\n */\nconst VITE_CONDITIONS = ['module', 'node', 'development|production'];\nconst VITE_EXTERNAL_CONDITIONS = ['node', 'module-sync'];\n\n/** Bun's own modules, which no bundler should try to resolve: `bun` and `bun:*`. */\nconst BUN_BUILTINS: readonly (string | RegExp)[] = [BUN_CONDITION, /^bun:/];\n\n/**\n * What to merge into `present` so that it holds `wanted`: Vite replaces its\n * default with any value set, so an unset option gets the default too.\n * Strings compare by value, patterns by source.\n */\nfunction adding<T extends string | RegExp>(\n\tpresent: readonly T[] | undefined,\n\tfallback: readonly T[],\n\twanted: readonly T[],\n): T[] {\n\tconst list = present ?? fallback;\n\tconst has = (item: T) =>\n\t\tlist.some((other) =>\n\t\t\ttypeof item === 'string'\n\t\t\t\t? other === item\n\t\t\t\t: other instanceof RegExp && other.source === item.source,\n\t\t);\n\treturn [\n\t\t...(present === undefined ? fallback : []),\n\t\t...wanted.filter((item) => !has(item)),\n\t];\n}\n\n/**\n * What the plugin adds to the `ssr` environment, given its options as the\n * config and every plugin's `config` hook left them. Vite merges the\n * result into them, concatenating arrays, so what the app set is kept:\n *\n * - `resolve.conditions` and `resolve.externalConditions` gain `bun`, so a\n * package that exports a `bun` variant is bundled, and checked, as Bun\n * would load it. Which variant wins stays the package's own order.\n * - `resolve.builtins` gains `bun` and `bun:*`: left external, whichever\n * runtime runs Vite. Vite's own builtins are kept when the app names none.\n * - `build.target` is `esnext`, Bun's, unless the app set one, at the top\n * level or on the environment.\n *\n * `ssr.target` stays `node`: Bun runs Node's modules, and `webworker`\n * would bundle every dependency with the browser's conditions. An app that\n * sets `webworker` itself gets none of this: the plugin leaves that\n * environment to Vite's own defaults.\n */\nexport function bunEnvironment(\n\toptions: EnvironmentOptions,\n): EnvironmentOptions {\n\tconst resolve = options.resolve ?? {};\n\tconst added: EnvironmentOptions = {\n\t\tresolve: {\n\t\t\tconditions: adding(resolve.conditions, VITE_CONDITIONS, [BUN_CONDITION]),\n\t\t\texternalConditions: adding(\n\t\t\t\tresolve.externalConditions,\n\t\t\t\tVITE_EXTERNAL_CONDITIONS,\n\t\t\t\t[BUN_CONDITION],\n\t\t\t),\n\t\t\tbuiltins: adding(resolve.builtins, VITE_BUILTINS, BUN_BUILTINS),\n\t\t},\n\t};\n\tif (options.build?.target === undefined) {\n\t\tadded.build = { target: 'esnext' };\n\t}\n\treturn added;\n}\n",
|
|
7
7
|
"/**\n * The server build, self-contained: every dependency bundled into\n * `build/server/index.js`, so that running it needs `build/` and Bun, and\n * no `node_modules`. A Docker image's final stage copies `build/` alone.\n */\nimport type { EnvironmentOptions } from 'vite';\nimport { bunEnvironment } from './bun';\n\n/**\n * What the plugin adds to the `ssr` environment under `react-router build`,\n * given its options as the config and the plugins left them:\n * `resolve.noExternal: true`, every package bundled. Never in dev, where\n * Vite's SSR runner loads the packages from `node_modules`.\n *\n * What the app set wins:\n *\n * - `ssr.external: ['sharp']`, or the same on `environments.ssr.resolve`,\n * keeps those packages external, imported from `node_modules` at\n * runtime: Vite reads `external` before `noExternal`. Bun's own modules,\n * `bun` and `bun:*`, and Node's are builtins, external whatever this says.\n * - `ssr.external: true` keeps every package external, Vite's own default:\n * the plugin adds nothing then.\n * - `ssr.noExternal`, a list, is a subset of everything: it changes nothing.\n *\n * React Router's own plugin reads `noExternal: true` and adds no externals\n * of its own; it runs after this one, which is `enforce: 'pre'`.\n */\nexport function bundledEnvironment(\n\toptions: EnvironmentOptions,\n): EnvironmentOptions | undefined {\n\tif (options.resolve?.external === true) return undefined;\n\treturn { resolve: { noExternal: true } };\n}\n\n/**\n * Everything the plugin adds to the `ssr` environment: built for Bun under\n * either command, and self-contained under `build` alone. In dev, Vite's\n * SSR runner loads the packages from `node_modules`.\n */\nexport function ssrEnvironment(\n\toptions: EnvironmentOptions,\n\tcommand: 'build' | 'serve',\n): EnvironmentOptions {\n\tconst added = bunEnvironment(options);\n\tconst bundled = command === 'build' ? bundledEnvironment(options) : undefined;\n\tif (bundled === undefined) return added;\n\treturn { ...added, resolve: { ...added.resolve, ...bundled.resolve } };\n}\n",
|
|
8
|
+
"/**\n * The client build's compressed copies: `app.js.br` and `app.js.gz` beside\n * every compressible file, which `app.static(…, { precompressed })` serves\n * to a browser that accepts them, so the server never compresses on a request.\n */\nimport { readdir, readFile, rm, writeFile } from 'node:fs/promises';\nimport { extname, join } from 'node:path';\nimport { promisify } from 'node:util';\nimport { brotliCompress, constants, gzip } from 'node:zlib';\n\nconst brotli = promisify(brotliCompress);\nconst deflate = promisify(gzip);\n\n/** What compresses well: text, and the formats built on it. */\nconst COMPRESSIBLE = new Set([\n\t'.js',\n\t'.mjs',\n\t'.cjs',\n\t'.css',\n\t'.html',\n\t'.htm',\n\t'.svg',\n\t'.json',\n\t'.map',\n\t'.txt',\n\t'.xml',\n\t'.webmanifest',\n\t'.wasm',\n\t'.ico',\n\t'.ttf',\n\t'.otf',\n\t'.eot',\n]);\n\nexport interface PrecompressOptions {\n\t/** The smallest file, in bytes, that gets copies: 1024 by default. */\n\treadonly minSize?: number;\n}\n\nexport interface Precompressed {\n\t/** The files that got copies. */\n\treadonly files: number;\n\t/** Their size before, and the size of their brotli copies. */\n\treadonly bytes: number;\n\treadonly brotliBytes: number;\n}\n\nasync function* walk(dir: string): AsyncGenerator<string> {\n\tfor (const entry of await readdir(dir, { withFileTypes: true })) {\n\t\tconst path = join(dir, entry.name);\n\t\tif (entry.isDirectory()) yield* walk(path);\n\t\telse if (entry.isFile()) yield path;\n\t}\n}\n\n/**\n * Writes `<file>.br` and `<file>.gz` beside each compressible file of\n * `client` of at least `minSize` bytes, whichever is smaller than the file\n * itself. Brotli at its best quality: it runs once, at build time.\n */\nexport async function precompressClient(\n\tclient: string,\n\toptions: PrecompressOptions = {},\n): Promise<Precompressed> {\n\tconst minSize = options.minSize ?? 1024;\n\tlet files = 0;\n\tlet bytes = 0;\n\tlet brotliBytes = 0;\n\tfor await (const path of walk(client)) {\n\t\tif (!COMPRESSIBLE.has(extname(path).toLowerCase())) continue;\n\t\tconst body = await readFile(path);\n\t\tif (body.length < minSize) continue;\n\t\tconst [br, gz] = await Promise.all([\n\t\t\tbrotli(body, {\n\t\t\t\tparams: {\n\t\t\t\t\t[constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MAX_QUALITY,\n\t\t\t\t\t[constants.BROTLI_PARAM_SIZE_HINT]: body.length,\n\t\t\t\t},\n\t\t\t}),\n\t\t\tdeflate(body, { level: 9 }),\n\t\t]);\n\t\tlet written = false;\n\t\tfor (const [extension, copy] of [\n\t\t\t['br', br],\n\t\t\t['gz', gz],\n\t\t] as const) {\n\t\t\tif (copy.length < body.length) {\n\t\t\t\tawait writeFile(`${path}.${extension}`, copy);\n\t\t\t\twritten = true;\n\t\t\t} else {\n\t\t\t\t// A copy left by an earlier build would be stale.\n\t\t\t\tawait rm(`${path}.${extension}`, { force: true });\n\t\t\t}\n\t\t}\n\t\tif (!written) continue;\n\t\tfiles += 1;\n\t\tbytes += body.length;\n\t\tbrotliBytes += Math.min(br.length, body.length);\n\t}\n\treturn { files, bytes, brotliBytes };\n}\n",
|
|
8
9
|
"/**\n * What the plugin reads of Vite's and React Router's config: the server\n * file, the client folder, and the server build's bundler options.\n */\nimport { existsSync } from 'node:fs';\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path';\nimport type { ResolvedConfig } from 'vite';\nimport { NAME } from './entry';\n\n/** The server build's input, and in dev the module the requests go to. */\nexport const SERVER = 'virtual:alxia-react-router/server';\n/** The same, when there is no server file: `createServer()` as it is. */\nexport const DEFAULT = `${SERVER}-default`;\n\n/** What the plugin reads of React Router's own config. */\nexport interface ReactRouterConfig {\n\treadonly appDirectory: string;\n\treadonly buildDirectory: string;\n\treadonly serverBuildFile: string;\n\treadonly ssr: boolean;\n\treadonly serverBundles?: unknown;\n}\n\n/** React Router's config, which its plugin puts on Vite's. */\nexport function contextOf(config: object): ReactRouterConfig {\n\tconst context = (\n\t\tconfig as {\n\t\t\treadonly __reactRouterPluginContext?: {\n\t\t\t\treadonly reactRouterConfig: ReactRouterConfig;\n\t\t\t};\n\t\t}\n\t).__reactRouterPluginContext;\n\tif (context === undefined) {\n\t\tthrow new Error(\n\t\t\t`${NAME}: React Router's Vite plugin is not in this config. Add reactRouter() from @react-router/dev/vite beside alxia() in vite.config.ts.`,\n\t\t);\n\t}\n\treturn context.reactRouterConfig;\n}\n\n/** React Router's child compiler: a Vite server without its plugin, cached apart. */\nexport function isChildCompiler(config: ResolvedConfig): boolean {\n\treturn (\n\t\t(config as { readonly __reactRouterPluginContext?: unknown })\n\t\t\t.__reactRouterPluginContext === undefined &&\n\t\tconfig.cacheDir.endsWith('.vite-child-compiler')\n\t);\n}\n\n/**\n * The server file: `entry`, which must exist, or `app/server.ts` when it\n * does, or `undefined` for the default server.\n */\nexport function serverFile(\n\tentry: string | undefined,\n\tconfig: ResolvedConfig,\n): string | undefined {\n\tif (entry !== undefined) {\n\t\tconst file = isAbsolute(entry) ? entry : resolve(config.root, entry);\n\t\tif (!existsSync(file)) {\n\t\t\tthrow new Error(\n\t\t\t\t`${NAME}: the entry ${entry} does not exist. Create it, or leave entry out to use app/server.ts, or the default server without it.`,\n\t\t\t);\n\t\t}\n\t\treturn file;\n\t}\n\tconst file = join(contextOf(config).appDirectory, 'server.ts');\n\treturn existsSync(file) ? file : undefined;\n}\n\n/** The built server, absolute: `build/server/index.js`. */\nexport function serverBuildPath(config: ResolvedConfig): string {\n\tconst rr = contextOf(config);\n\tconst outDir = resolve(\n\t\tconfig.root,\n\t\tconfig.environments['ssr']?.build.outDir ??\n\t\t\tjoin(rr.buildDirectory, 'server'),\n\t);\n\treturn join(outDir, rr.serverBuildFile);\n}\n\n/** `build/client`, relative to the built `build/server/index.js`. */\nexport function clientPath(config: ResolvedConfig): string {\n\tconst built = dirname(serverBuildPath(config));\n\tconst path = relative(\n\t\tbuilt,\n\t\tjoin(contextOf(config).buildDirectory, 'client'),\n\t);\n\treturn path.startsWith('.') ? path : `./${path}`;\n}\n\n/**\n * The ssr build's options: one file, `build/server/index.js`, the server\n * and React Router's build together. Rolldown, under Vite 8, names the\n * option otherwise.\n */\nexport function serverBuildOptions(rolldown: boolean): object {\n\treturn rolldown\n\t\t? {\n\t\t\t\trolldownOptions: {\n\t\t\t\t\tinput: SERVER,\n\t\t\t\t\toutput: { codeSplitting: false },\n\t\t\t\t},\n\t\t\t}\n\t\t: {\n\t\t\t\trollupOptions: {\n\t\t\t\t\tinput: SERVER,\n\t\t\t\t\toutput: { inlineDynamicImports: true },\n\t\t\t\t},\n\t\t\t};\n}\n",
|
|
9
10
|
"/**\n * The few lines between Vite's dev and preview servers, which speak\n * `node:http`, and an alxia app, which speaks `Request` and `Response`: no\n * dependency, Bun's own `node:http` and `node:stream` underneath.\n */\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { Readable } from 'node:stream';\n\n/** What Connect, Vite's middleware stack, adds to a request: the URL before any rewrite. */\ntype ConnectRequest = IncomingMessage & {\n\treadonly originalUrl?: string | undefined;\n};\n\n/** The `Request` a Node request stands for. Aborted when the client goes away. */\nexport function toRequest(req: ConnectRequest, res: ServerResponse): Request {\n\tconst secure = (req.socket as { encrypted?: boolean }).encrypted === true;\n\tconst url = new URL(\n\t\treq.originalUrl ?? req.url ?? '/',\n\t\t`${secure ? 'https' : 'http'}://${req.headers.host ?? 'localhost'}`,\n\t);\n\tconst headers = new Headers();\n\tconst raw = req.rawHeaders;\n\tfor (let i = 0; i + 1 < raw.length; i += 2) {\n\t\tconst name = raw[i] as string;\n\t\t// HTTP/2's pseudo-headers (`:path`, `:method`) are not headers.\n\t\tif (!name.startsWith(':')) headers.append(name, raw[i + 1] as string);\n\t}\n\tconst controller = new AbortController();\n\tres.once('close', () => {\n\t\tif (!res.writableFinished) controller.abort();\n\t});\n\tconst method = req.method ?? 'GET';\n\tconst init: RequestInit & { duplex?: 'half' } = {\n\t\tmethod,\n\t\theaders,\n\t\tsignal: controller.signal,\n\t};\n\tif (method !== 'GET' && method !== 'HEAD') {\n\t\tinit.body = Readable.toWeb(req) as unknown as ReadableStream<Uint8Array>;\n\t\tinit.duplex = 'half';\n\t}\n\treturn new Request(url, init);\n}\n\n/** Writes `response` to `res`, streaming its body chunk by chunk as it comes. */\nexport async function send(\n\tres: ServerResponse,\n\tresponse: Response,\n): Promise<void> {\n\tres.statusCode = response.status;\n\tif (response.statusText !== '') res.statusMessage = response.statusText;\n\tfor (const [name, value] of response.headers) {\n\t\tif (name !== 'set-cookie') res.setHeader(name, value);\n\t}\n\tconst cookies = response.headers.getSetCookie();\n\tif (cookies.length > 0) res.setHeader('set-cookie', cookies);\n\tif (response.body === null) {\n\t\tres.end();\n\t\treturn;\n\t}\n\tres.flushHeaders();\n\tconst reader = response.body.getReader();\n\tconst cancel = () => void reader.cancel().catch(() => {});\n\tres.once('close', cancel);\n\ttry {\n\t\tfor (;;) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tif (res.destroyed) return;\n\t\t\tif (!res.write(value)) {\n\t\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\t\tconst go = () => {\n\t\t\t\t\t\tres.off('drain', go);\n\t\t\t\t\t\tres.off('close', go);\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t};\n\t\t\t\t\tres.on('drain', go);\n\t\t\t\t\tres.on('close', go);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tres.end();\n\t} finally {\n\t\tres.off('close', cancel);\n\t}\n}\n",
|
|
10
11
|
"/**\n * Under `react-router dev` and `vite preview`: the app's WebSocket routes. Vite's server is a\n * `node:http` one, and an alxia socket is `Bun.serve`'s upgrade, so each\n * upgrade Vite leaves is relayed, bytes as they come, to a `Bun.serve` of\n * the app's own on a loopback port: its middlewares, its validation, its socket\n * handlers, exactly as `listen` runs them.\n */\nimport type { IncomingMessage } from 'node:http';\nimport { connect, type Socket } from 'node:net';\nimport type { DevApp } from './dev';\nimport { NAME } from './entry';\n\n/** The subprotocols of Vite's own socket, the HMR one and its ping: Vite answers them. */\nconst VITE = new Set(['vite-hmr', 'vite-ping']);\n\n/** Whether the upgrade asks for Vite's own socket. */\nexport function isVites(req: Pick<IncomingMessage, 'headers'>): boolean {\n\tconst protocols = req.headers['sec-websocket-protocol'];\n\tif (protocols === undefined) return false;\n\treturn protocols.split(',').some((protocol) => VITE.has(protocol.trim()));\n}\n\n/** One entry of Vite's `server.proxy`, as far as its sockets go. */\ntype ProxyEntry = string | { readonly ws?: boolean; readonly target?: unknown };\n\n/**\n * Whether Vite's `server.proxy` relays this upgrade itself: an entry whose\n * context matches the URL, as Vite matches it (`^…` a RegExp, otherwise a\n * prefix), and that proxies sockets (`ws: true`, or a `ws:`/`wss:` target).\n */\nexport function isProxied(\n\turl: string,\n\tproxy: Readonly<Record<string, ProxyEntry>> | undefined,\n): boolean {\n\tfor (const [context, entry] of Object.entries(proxy ?? {})) {\n\t\tconst matches =\n\t\t\t(context.startsWith('^') && new RegExp(context).test(url)) ||\n\t\t\turl.startsWith(context);\n\t\tif (!matches) continue;\n\t\tconst options = typeof entry === 'string' ? { target: entry } : entry;\n\t\tconst target = String(options.target ?? '');\n\t\tif (\n\t\t\toptions.ws === true ||\n\t\t\ttarget.startsWith('ws:') ||\n\t\t\ttarget.startsWith('wss:')\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/** The request line and headers of `req`, as they came: what the side server reads. */\nexport function head(\n\treq: Pick<IncomingMessage, 'method' | 'url' | 'rawHeaders'>,\n): string {\n\tconst lines = [`${req.method ?? 'GET'} ${req.url ?? '/'} HTTP/1.1`];\n\tconst raw = req.rawHeaders;\n\tfor (let i = 0; i + 1 < raw.length; i += 2) {\n\t\tlines.push(`${raw[i]}: ${raw[i + 1]}`);\n\t}\n\treturn `${lines.join('\\r\\n')}\\r\\n\\r\\n`;\n}\n\n/** The side servers: the current app's, and those an edit retired, until their sockets close. */\nexport interface Sides {\n\tcurrent:\n\t\t| { readonly app: DevApp; readonly side: Bun.Server<unknown> }\n\t\t| undefined;\n\treadonly retired: Set<Bun.Server<unknown>>;\n}\n\n/**\n * The side server of `app`, started on its first upgrade. A new app, an\n * edit's, retires the previous one: no new connection, and the sockets open\n * on it stay, with the handlers they opened with, until they close.\n */\nexport function sideFor(sides: Sides, app: DevApp): Bun.Server<unknown> {\n\tif (sides.current?.app === app) return sides.current.side;\n\tconst side = Bun.serve({\n\t\tport: 0,\n\t\thostname: '127.0.0.1',\n\t\tfetch: (request, bun) => app.fetch(request, bun),\n\t\twebsocket: app.websocket,\n\t} as Bun.Serve.Options<never>) as Bun.Server<unknown>;\n\tconst old = sides.current?.side;\n\tif (old !== undefined) {\n\t\tsides.retired.add(old);\n\t\tvoid old.stop().then(() => sides.retired.delete(old));\n\t}\n\tsides.current = { app, side };\n\treturn side;\n}\n\n/** Stops every side server, open sockets and all: Vite's server closed. */\nexport function closeAll(sides: Sides): void {\n\tfor (const side of [...sides.retired, sides.current?.side]) {\n\t\tvoid side?.stop(true);\n\t}\n\tsides.current = undefined;\n\tsides.retired.clear();\n}\n\n/** Relays the upgrade on `socket` to the side server on `port`, both ways. */\nfunction relay(\n\treq: IncomingMessage,\n\tsocket: Socket,\n\tbytes: Buffer,\n\tport: number,\n): void {\n\tconst upstream = connect(port, '127.0.0.1', () => {\n\t\tupstream.write(head(req));\n\t\tif (bytes.length > 0) upstream.write(bytes);\n\t\tupstream.pipe(socket);\n\t\tsocket.pipe(upstream);\n\t});\n\tupstream.on('error', () => socket.destroy());\n\tupstream.on('close', () => socket.destroy());\n\tsocket.on('close', () => upstream.destroy());\n}\n\n/** The side server of an app, which its sockets are open on: what `bridgeSockets` returns. */\nexport type SideOf = (app: DevApp) => Bun.Server<unknown> | undefined;\n\n/** What the relay listens to on Vite's HTTP server, HTTP/1 or HTTP/2 alike. */\ninterface Upgrades {\n\ton(\n\t\tevent: 'upgrade',\n\t\tlistener: (req: IncomingMessage, socket: Socket, bytes: Buffer) => void,\n\t): unknown;\n\tonce(event: 'close', listener: () => void): unknown;\n}\n\n/** What the relay needs of the server it listens on: Vite's dev server or its preview. */\nexport interface Bridge {\n\t/** Vite's `server.proxy` (or `preview.proxy`): the upgrades it relays are its own. */\n\treadonly proxy: Readonly<Record<string, ProxyEntry>> | undefined;\n\t/** The app, as it is now. */\n\treadonly load: () => Promise<DevApp>;\n\t/** Where an upgrade that failed is printed: Vite's logger. */\n\treadonly logger: { error(message: string): void };\n\t/** Maps an error's stack to the source, as Vite's `ssrFixStacktrace` does. */\n\treadonly fix?: (error: Error) => void;\n}\n\n/** An upgrade the app could not take: reported, and a 500 to the client. */\nfunction refuse(bridge: Bridge, socket: Socket, error: unknown): void {\n\tif (error instanceof Error) bridge.fix?.(error);\n\tbridge.logger.error(\n\t\t`${NAME}: a WebSocket upgrade failed: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`,\n\t);\n\tif (socket.writable) {\n\t\tsocket.end(\n\t\t\t'HTTP/1.1 500 Internal Server Error\\r\\nConnection: close\\r\\nContent-Length: 0\\r\\n\\r\\n',\n\t\t);\n\t}\n}\n\n/**\n * Relays the app's upgrades on Vite's HTTP server to a side server of the\n * app. Vite's own socket and the sockets its proxy relays are left to\n * Vite. Without an HTTP server (Vite's middleware mode), there is nothing\n * to listen on.\n *\n * Returns the side server of an app, for its HTTP requests' `ctx.server`:\n * the server its sockets are open on, so that a `publish` from a loader or\n * an action reaches them. `undefined` in middleware mode, and once Vite's\n * server closed.\n */\nexport function bridgeSockets(http: Upgrades | null, bridge: Bridge): SideOf {\n\tif (http === null) return () => undefined;\n\tconst sides: Sides = { current: undefined, retired: new Set() };\n\tlet closed = false;\n\thttp.on('upgrade', (req: IncomingMessage, socket: Socket, bytes: Buffer) => {\n\t\tif (isVites(req) || isProxied(req.url ?? '/', bridge.proxy)) return;\n\t\tsocket.on('error', () => socket.destroy());\n\t\tbridge\n\t\t\t.load()\n\t\t\t.then((app) => {\n\t\t\t\tif (socket.destroyed) return;\n\t\t\t\trelay(req, socket, bytes, sideFor(sides, app).port as number);\n\t\t\t})\n\t\t\t.catch((error: unknown) => refuse(bridge, socket, error));\n\t});\n\thttp.once('close', () => {\n\t\tclosed = true;\n\t\tcloseAll(sides);\n\t});\n\treturn (app) => (closed ? undefined : sideFor(sides, app));\n}\n",
|
|
@@ -14,7 +15,7 @@
|
|
|
14
15
|
"import { NAME } from './entry';\n\n/**\n * Refuses, with what to do, a dev or preview server running on Node. The\n * React Router CLI's `#!/usr/bin/env node` runs it on Node whenever a node\n * is installed, even from `bun run dev`, and alxia's server then fails on\n * its first request with `ReferenceError: Bun is not defined`.\n */\nexport function requireBun(\n\tcommand: string,\n\thint = `bun --bun ${command}`,\n\tonBun = (globalThis as { Bun?: unknown }).Bun !== undefined,\n\treason = \"and alxia's server runs on Bun\",\n): void {\n\tif (onBun) return;\n\tthrow new Error(\n\t\t`${NAME}: ${command} is running on Node, ${reason}. Add a bunfig.toml beside package.json with \"[run]\" and \"bun = true\", so bun run starts it on Bun, or run it as ${hint}.`,\n\t);\n}\n",
|
|
15
16
|
"/**\n * The service worker, built by `alxia()` once React Router has built the\n * client: `app/service-worker.ts` is the opt-in, as `app/server.ts` is.\n */\nimport { existsSync } from 'node:fs';\nimport { basename, isAbsolute, join, resolve } from 'node:path';\nimport type { ResolvedConfig } from 'vite';\nimport { type BuildWorkerOptions, buildWorker } from '../pwa/build';\nimport { contextOf } from './config';\nimport { NAME } from './entry';\nimport type { AlxiaOptions } from './index';\nimport { requireBun } from './runtime';\n\n/** `buildWorker()`'s options but where: the plugin knows the root, the client build and, by default, the file. */\nexport type AlxiaWorkerOptions = Omit<\n\tBuildWorkerOptions,\n\t'root' | 'client' | 'file'\n> & { readonly file?: string };\n\n/**\n * The worker's source, absolute, or `undefined` when there is none to\n * build: `worker: false`, or no `app/service-worker.ts` and no named file.\n * Throws when a named file does not exist.\n */\nexport function workerFile(\n\toption: AlxiaOptions['worker'],\n\tconfig: ResolvedConfig,\n): string | undefined {\n\tif (option === false) return undefined;\n\tconst named = typeof option === 'string' ? option : option?.file;\n\tif (named !== undefined) {\n\t\tconst file = isAbsolute(named) ? named : resolve(config.root, named);\n\t\tif (!existsSync(file)) {\n\t\t\tthrow new Error(\n\t\t\t\t`${NAME}: the worker ${named} does not exist. Create it, or leave worker out to build app/service-worker.ts when it exists.`,\n\t\t\t);\n\t\t}\n\t\treturn file;\n\t}\n\tconst file = join(contextOf(config).appDirectory, 'service-worker.ts');\n\treturn existsSync(file) ? file : undefined;\n}\n\nconst MB = (bytes: number) => (bytes / 1024 / 1024).toFixed(2);\nconst KB = (bytes: number) => (bytes / 1024).toFixed(1);\n\n/** Builds the worker into `build/client`, if the app has one. */\nexport async function buildAppWorker(\n\tconfig: ResolvedConfig,\n\toption: AlxiaOptions['worker'],\n): Promise<void> {\n\tconst file = workerFile(option, config);\n\tif (file === undefined) return;\n\trequireBun(\n\t\t'react-router build with a service worker',\n\t\t'bun --bun react-router build',\n\t\tundefined,\n\t\t'and the worker is bundled by Bun.build',\n\t);\n\tconst rest = typeof option === 'object' ? option : {};\n\tconst built = await buildWorker({\n\t\t...rest,\n\t\tfile,\n\t\troot: config.root,\n\t\tclient: join(contextOf(config).buildDirectory, 'client'),\n\t}).catch((error: unknown) => {\n\t\tthrow new Error(`${NAME}: ${(error as Error).message}`, { cause: error });\n\t});\n\tconfig.logger.info(\n\t\t`✓ ${basename(built.file)}: ${built.precache.length} files precached (${MB(built.precacheBytes)} MB), worker ${KB(built.bytes)} kB`,\n\t);\n}\n"
|
|
16
17
|
],
|
|
17
|
-
"mappings": "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",
|
|
18
|
-
"debugId": "
|
|
18
|
+
"mappings": "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",
|
|
19
|
+
"debugId": "3DE9F1517A9D4E4F64756E2164756E21",
|
|
19
20
|
"names": []
|
|
20
21
|
}
|
package/docs/README.md
CHANGED
|
@@ -20,6 +20,7 @@ installable and usable offline, wording an API's refusals, the BFF session, a Gr
|
|
|
20
20
|
| [Installable and offline](guide/pwa.md) | making the app installable and usable offline: the subpaths of `@alxia/react-router/pwa`, the service worker (`startWorker`, `/pwa/worker`), its build by `alxia()` or `buildWorker` (`/pwa/build`), its contract and cache names, which requests the worker caches and which responses it stores, the precache list read from a build, or clearing the caches at sign-out |
|
|
21
21
|
| [An API's refusals](guide/errors.md) | wording a GraphQL API's refusals for the pages: recognising an `ApiError`, the request id, the page a request is for, the catalogue store, the form checks in the API's words, the provider, and the loaders, the error page and the actions that answer with it, the JSON actions with their CSRF check and fetcher hook, calling the API from a loader (`apiCallFailure`), and keeping the catalogue fresh (`@alxia/react-router/errors`) |
|
|
22
22
|
| [A BFF session](guide/session.md) | redirecting after sign-in to a page of the site and nowhere else, the sign-in pages' paths, the session's cookies, the sign-in flow (where an answer lands, a refused code, the viewer, sign-out; `@alxia/react-router/session`), the pages a mail's link opens (a magic link, a password reset: `authLinks`), the page's hooks (sign-out, a mail link's parameter, a one-code field; `@alxia/react-router/session/react`), and the step-up's state and the props it gives the UI (`@alxia/react-router/session/model`) |
|
|
23
|
+
| [Links through React Router](guide/link.md) | `RouterLink`, React Router's `Link` as the link component of a UI library that hands `href` and spreads anchor props; `@alxia/react-router/link` |
|
|
23
24
|
| [Lists whose state is the URL](guide/lists.md) | a search and filters in the address bar that drop the cursor (`useSearchChange`), a skeleton while the same page reloads (`useSameRouteLoading`), and a load-more button that appends pages by cursor and keeps the rows when one fails (`usePagedRows`); `@alxia/react-router/lists` |
|
|
24
25
|
| [Subscriptions for a BFF](guide/subscriptions.md) | showing a GraphQL subscription in the browser without giving it the API's token or a way to write a document: a resource route with a map of operation names to the server's documents, the same-site check, the bearer from the session, extra upstream headers, a heartbeat, abort propagation, size limits and a 429 passed through with `retryAfter` (`@alxia/react-router/subscription`) |
|
|
25
26
|
| [Troubleshooting](troubleshooting.md) | something went wrong and you have the message, or a page streams, hydrates or reads its context unlike you expected |
|
|
@@ -176,3 +176,25 @@ Dotfiles are skipped. In dev, Vite serves them.
|
|
|
176
176
|
A folder that is not one, or a file whose name no route can carry, is
|
|
177
177
|
refused when the server starts: see
|
|
178
178
|
[the troubleshooting entries](../troubleshooting.md#typeerror-reactrouter-client-is--which-is-not-a-directory-).
|
|
179
|
+
|
|
180
|
+
### Compressed
|
|
181
|
+
|
|
182
|
+
`react-router build` writes a `.br` and a `.gz` copy beside each
|
|
183
|
+
compressible file of `build/client` (JavaScript, CSS, HTML, SVG, JSON,
|
|
184
|
+
text, XML, WebAssembly, source maps, fonts) of at least 1 kB, and the
|
|
185
|
+
server sends the copy a browser's `Accept-Encoding` asks for, with
|
|
186
|
+
`Content-Encoding`, `Vary: Accept-Encoding` and the same `Cache-Control`.
|
|
187
|
+
The files are read from disk as they are, never compressed on a request.
|
|
188
|
+
Files at the top of `build/client`, such as a large `sprite.svg`, get it
|
|
189
|
+
too. A file with no copy, or a client that accepts none, gets the file.
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
// vite.config.ts: the threshold, or no copies at all
|
|
193
|
+
alxia({ precompress: { minSize: 4096 } });
|
|
194
|
+
alxia({ precompress: false });
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
// app/server.ts: serve the files as they are, such as behind a proxy that compresses
|
|
199
|
+
export default createServer({ precompressed: false });
|
|
200
|
+
```
|
|
@@ -113,6 +113,7 @@ Every option is optional:
|
|
|
113
113
|
| `beforeAll(app)` | runs first, on a new app. What it declares applies to the client's files too: a rate limit, a guard on everything, a logger that should see every asset. It returns the app, which `configure` then receives |
|
|
114
114
|
| `getLoadContext(ctx, context)` | sets the app's own keys on React Router's provider, `ctx` typed by `configure`'s app |
|
|
115
115
|
| `build`, `mode`, `client` | override what the plugin wires; see [Escape hatches](#escape-hatches) |
|
|
116
|
+
| `precompressed` | `false` serves the client's files as they are, without their `.br` and `.gz` copies; see [Compressed](beside-the-pages.md#compressed) |
|
|
116
117
|
| `listen` | `listen`'s options for `bun build/server/index.js`: `port`, `hostname`, `idleTimeout`, `maxRequestBodySize`, `tls`, `onListen`. A `port` or `hostname` given here wins over `PORT` and `HOST`; an `onListen` here, told `@alxia/core`'s `ListenInfo` — `url`, `routes`, `table`, `dev` — wins over the option below |
|
|
117
118
|
| `onListen(server)` | called once the built server listens and its `SIGINT` and `SIGTERM` handlers are in place, in place of the `alxia listening on …` line (and, in dev, of the route table); a signal sent from then on runs the `onStop` hooks |
|
|
118
119
|
|
|
@@ -282,6 +283,7 @@ bun run build && bun server.ts
|
|
|
282
283
|
| `mode` | React Router's server mode, `production` by default |
|
|
283
284
|
| `getLoadContext(ctx, context)` | as `createServer`'s |
|
|
284
285
|
| `client` | the client build's folder, a path or a `file:` URL, served before the catch-all in `production` |
|
|
286
|
+
| `precompressed` | `true` by default: serves the client's `.br` and `.gz` copies to a browser that accepts them; `false` serves the files as they are |
|
|
285
287
|
|
|
286
288
|
`reactRouter()` goes through `app.plugin`, as `@alxia/graphql`'s `graphql(app, …)`
|
|
287
289
|
does: that is how it knows the app's context type. A `HEAD` is handed to
|
|
@@ -77,6 +77,12 @@ service worker when the app has an `app/service-worker.ts` (`worker: false`
|
|
|
77
77
|
turns it off): `build/client/service-worker.js`, with the precache list read
|
|
78
78
|
from the client build ([the PWA guide](pwa.md#zero-config-alxia-builds-it)).
|
|
79
79
|
|
|
80
|
+
Then it writes the compressed copies of the client build, `.br` and `.gz`
|
|
81
|
+
beside each compressible file, which the server serves to a browser that
|
|
82
|
+
accepts them ([the client's files](beside-the-pages.md#compressed)).
|
|
83
|
+
`precompress: false` turns it off, `precompress: { minSize }` moves the 1 kB
|
|
84
|
+
threshold.
|
|
85
|
+
|
|
80
86
|
React Router's `serverBundles` split the server build in several, and
|
|
81
87
|
alxia serves one: the plugin refuses them. With `ssr: false`, a
|
|
82
88
|
single-page app, the plugin does nothing but build the service worker (when
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Links through React Router
|
|
2
|
+
|
|
3
|
+
A UI library that renders its links through a component of its own (a
|
|
4
|
+
`LinkComponentProvider`) hands that component an `href` and spreads every other
|
|
5
|
+
prop onto the anchor. React Router's `Link` takes `to`, so an app adapts it.
|
|
6
|
+
`@alxia/react-router/link` exports that adapter. `react` and `react-router` are
|
|
7
|
+
its only imports, and it renders on the server.
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
// app/root.tsx
|
|
11
|
+
import { RouterLink } from '@alxia/react-router/link';
|
|
12
|
+
|
|
13
|
+
export default function App() {
|
|
14
|
+
return (
|
|
15
|
+
<LinkComponentProvider component={RouterLink}>
|
|
16
|
+
<Outlet />
|
|
17
|
+
</LinkComponentProvider>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## What it does
|
|
23
|
+
|
|
24
|
+
- `href` (or `to`, React Router's own name, never both) is the destination: a
|
|
25
|
+
string or a `To` object.
|
|
26
|
+
- An external target (`https://…`, `mailto:`, `//host`) renders a plain anchor with that `href`; React Router's `Link` already handles it.
|
|
27
|
+
- `className`, `children`, `ref`, `aria-*`, `target` and every other anchor prop
|
|
28
|
+
reach the `<a>`.
|
|
29
|
+
- `Link`'s own props (`replace`, `prefetch`, `reloadDocument`, `state`, ...) still
|
|
30
|
+
apply, so a link can opt out of client-side navigation.
|
|
31
|
+
|
|
32
|
+
`RouterLinkProps` is the type of its props, for a wrapper of your own.
|
package/docs/roadmap.md
CHANGED
|
@@ -7,6 +7,12 @@ number on it. Every release, with each change it made, is in
|
|
|
7
7
|
|
|
8
8
|
## Now
|
|
9
9
|
|
|
10
|
+
- **The client build, served compressed.** `react-router build` writes `.br`
|
|
11
|
+
and `.gz` copies beside the compressible files of `build/client`, and the
|
|
12
|
+
server sends the one a browser accepts, with `Vary: Accept-Encoding` and
|
|
13
|
+
the same cache headers. See [the client's
|
|
14
|
+
files](guide/beside-the-pages.md#compressed).
|
|
15
|
+
|
|
10
16
|
- **`@alxia/react-router/session/react`: the page's hooks around the session
|
|
11
17
|
flows.** `useSignOut`, `useLinkParam` (a mail link's parameter, read once and optionally dropped
|
|
12
18
|
from the address bar, or with `live: true` following the URL) and `useCodeField` /
|
package/docs/troubleshooting.md
CHANGED
|
@@ -25,6 +25,7 @@ a loader, a message React Router or the browser prints, or an error from
|
|
|
25
25
|
- [``You made a POST request to "/" but did not provide an `action` for route "root", so there is no way to handle the request.``](#you-made-a-post-request-to--but-did-not-provide-an-action-for-route-root-so-there-is-no-way-to-handle-the-request)
|
|
26
26
|
- [`TypeError: reactRouter(): client is …, which is not a directory. …`](#typeerror-reactrouter-client-is--which-is-not-a-directory-)
|
|
27
27
|
- [`TypeError: reactRouter(): … cannot be served at a path of its own name; rename it. …`](#typeerror-reactrouter--cannot-be-served-at-a-path-of-its-own-name-rename-it-)
|
|
28
|
+
- [The client's files are served uncompressed](#the-clients-files-are-served-uncompressed)
|
|
28
29
|
- [`Refused to execute inline script because it violates the following Content Security Policy directive: "default-src 'none'"`](#refused-to-execute-inline-script-because-it-violates-the-following-content-security-policy-directive-default-src-none)
|
|
29
30
|
- [`Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' 'nonce-…'"`](#refused-to-execute-inline-script-because-it-violates-the-following-content-security-policy-directive-script-src-self-nonce-)
|
|
30
31
|
- [`A tree hydrated but some attributes of the server rendered HTML didn't match the client properties`](#a-tree-hydrated-but-some-attributes-of-the-server-rendered-html-didnt-match-the-client-properties)
|
|
@@ -565,6 +566,31 @@ export async function loader({ request }: Route.LoaderArgs) {
|
|
|
565
566
|
|
|
566
567
|
The rows stay, `error` is `true`, and `loadMore` retries.
|
|
567
568
|
|
|
569
|
+
### The client's files are served uncompressed
|
|
570
|
+
|
|
571
|
+
A response for a script, a stylesheet or an SVG has no `Content-Encoding`,
|
|
572
|
+
though the request sent `Accept-Encoding: br, gzip`.
|
|
573
|
+
|
|
574
|
+
**When:** the server answers from `build/client`, and no `.br` or `.gz`
|
|
575
|
+
sits beside the file.
|
|
576
|
+
|
|
577
|
+
**Why:** the server never compresses on a request: it serves the copies
|
|
578
|
+
`react-router build` writes. They are missing when `alxia({ precompress:
|
|
579
|
+
false })` is set, when the build did not go through `alxia()` (a
|
|
580
|
+
`build/client` copied from a build before the option, or made by another
|
|
581
|
+
tool), when the file is under 1 kB or not compressible (an image, say), or
|
|
582
|
+
when `createServer({ precompressed: false })` is set. A compressed copy that
|
|
583
|
+
is not smaller than the file is not written.
|
|
584
|
+
|
|
585
|
+
A single-page app (`ssr: false` in `react-router.config.ts`) has no alxia server: the plugin builds the service worker only and writes no copies, so whatever serves `build/client` has to compress it.
|
|
586
|
+
|
|
587
|
+
**Fix:** build with the plugin, and check the copies exist:
|
|
588
|
+
|
|
589
|
+
```sh
|
|
590
|
+
bun run build && ls build/client/assets | grep -E '\.(br|gz)$'
|
|
591
|
+
curl -sI -H 'Accept-Encoding: br' http://localhost:3000/assets/entry.js | grep -i content-encoding
|
|
592
|
+
```
|
|
593
|
+
|
|
568
594
|
### `Refused to execute inline script because it violates the following Content Security Policy directive: "default-src 'none'"`
|
|
569
595
|
|
|
570
596
|
The browser's console prints it; the page renders on the server, then
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alxia/react-router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "alxia as the server of a React Router framework app: server rendering behind the app's hooks, loaders reading its typed context, the client's assets served; the code with no UI an installable app shares (`/pwa`), its hooks (`/pwa/react`), `noCache` for the worker's script (`/pwa/server`), the service worker on Workbox (`/pwa/worker`) and its build (`/pwa/build`), an API's refusals worded for the page (`/errors`), the BFF session: cookies, sign-in, step-up and mail links (`/session`), its page hooks (`/session/react`) and what it shares with the page (`/session/model`), a GraphQL subscription relayed to the browser over SSE (`/subscription`), the page's CSP nonce and inline boot scripts (`/document`) and a streaming `entry.server` (`/entry`)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -87,6 +87,11 @@
|
|
|
87
87
|
"import": "./dist/lists/index.js",
|
|
88
88
|
"default": "./dist/lists/index.js"
|
|
89
89
|
},
|
|
90
|
+
"./link": {
|
|
91
|
+
"types": "./dist/link/index.d.ts",
|
|
92
|
+
"import": "./dist/link/index.js",
|
|
93
|
+
"default": "./dist/link/index.js"
|
|
94
|
+
},
|
|
90
95
|
"./subscription": {
|
|
91
96
|
"types": "./dist/subscription/index.d.ts",
|
|
92
97
|
"import": "./dist/subscription/index.js",
|
|
@@ -121,6 +126,7 @@
|
|
|
121
126
|
"src/session/react/index.ts",
|
|
122
127
|
"src/subscription/index.ts",
|
|
123
128
|
"src/lists/index.ts",
|
|
129
|
+
"src/link/index.ts",
|
|
124
130
|
"src/document/index.ts",
|
|
125
131
|
"src/entry/index.ts",
|
|
126
132
|
"src/pwa/worker/index.ts",
|
|
@@ -129,10 +135,10 @@
|
|
|
129
135
|
]
|
|
130
136
|
},
|
|
131
137
|
"devDependencies": {
|
|
132
|
-
"@alxia/compress": "^0.3.
|
|
133
|
-
"@alxia/core": "^0.
|
|
134
|
-
"@alxia/openapi": "^0.6.
|
|
135
|
-
"@nxgt/graphql-client": "^0.
|
|
138
|
+
"@alxia/compress": "^0.3.12",
|
|
139
|
+
"@alxia/core": "^0.17.0",
|
|
140
|
+
"@alxia/openapi": "^0.6.12",
|
|
141
|
+
"@nxgt/graphql-client": "^0.5.0",
|
|
136
142
|
"@nxgt/janus": "^0.29.0",
|
|
137
143
|
"@react-router/dev": "^8.5.0",
|
|
138
144
|
"@types/bun": "^1.4.4",
|
|
@@ -155,7 +161,7 @@
|
|
|
155
161
|
"zod": "^4.2.0"
|
|
156
162
|
},
|
|
157
163
|
"peerDependencies": {
|
|
158
|
-
"@alxia/core": "^0.
|
|
164
|
+
"@alxia/core": "^0.17.0",
|
|
159
165
|
"isbot": "^5.0.0",
|
|
160
166
|
"react": "^19.0.0",
|
|
161
167
|
"react-dom": "^19.0.0",
|