@alxia/react-router 0.7.5 → 0.8.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 +92 -14
- package/dist/context.d.ts +32 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -5
- package/dist/index.js.map +7 -6
- package/dist/nonce.d.ts +2 -2
- package/dist/nonce.d.ts.map +1 -1
- package/dist/vite/dev.d.ts +6 -1
- package/dist/vite/dev.d.ts.map +1 -1
- package/dist/vite/index.js +17 -9
- package/dist/vite/index.js.map +5 -5
- package/dist/vite/preview.d.ts.map +1 -1
- package/dist/vite/socket.d.ts +8 -1
- package/dist/vite/socket.d.ts.map +1 -1
- package/dist/with-alxia.d.ts +36 -0
- package/dist/with-alxia.d.ts.map +1 -0
- package/docs/guide.md +136 -6
- package/docs/roadmap.md +40 -17
- package/docs/troubleshooting.md +89 -16
- package/package.json +3 -3
package/docs/troubleshooting.md
CHANGED
|
@@ -10,6 +10,7 @@ a loader, a message React Router or the browser prints, or an error from
|
|
|
10
10
|
- [`alxia-react-router: … is running on Node, and alxia's server runs on Bun. …`](#alxia-react-router--is-running-on-node-and-alxias-server-runs-on-bun-)
|
|
11
11
|
- [`ReferenceError: Bun is not defined`](#referenceerror-bun-is-not-defined)
|
|
12
12
|
- [`alxiaOf(): this request has no alxia context. …`](#alxiaof-this-request-has-no-alxia-context-)
|
|
13
|
+
- [`TypeError: undefined is not an object (evaluating 'context.alxia.user')`](#typeerror-undefined-is-not-an-object-evaluating-contextalxiauser)
|
|
13
14
|
- [`Error: No value found for context`](#error-no-value-found-for-context)
|
|
14
15
|
- [`alxia-react-router: … must export createServer() from @alxia/react-router as its default export: …`](#alxia-react-router--must-export-createserver-from-alxiareact-router-as-its-default-export-)
|
|
15
16
|
- [`alxia-react-router: the entry … does not exist. …`](#alxia-react-router-the-entry--does-not-exist-)
|
|
@@ -40,6 +41,7 @@ a loader, a message React Router or the browser prints, or an error from
|
|
|
40
41
|
|
|
41
42
|
**Types**
|
|
42
43
|
|
|
44
|
+
- [`Property 'alxia' does not exist on type 'Readonly<RouterContextProvider>'`](#property-alxia-does-not-exist-on-type-readonlyroutercontextprovider)
|
|
43
45
|
- [`Property '…' does not exist on type 'BaseContext & …'`](#property--does-not-exist-on-type-basecontext--)
|
|
44
46
|
- [`Type '…' does not satisfy the constraint 'AnyAlxia | ReactRouterServer<AnyAlxia>'`](#type--does-not-satisfy-the-constraint-anyalxia--reactrouterserveranyalxia)
|
|
45
47
|
- [`Type '(app: …) => void' is not assignable to type '(app: …) => AnyAlxia'`](#type-app---void-is-not-assignable-to-type-app---anyalxia)
|
|
@@ -57,7 +59,7 @@ a loader, a message React Router or the browser prints, or an error from
|
|
|
57
59
|
- [The logger times a streamed page at a few milliseconds](#the-logger-times-a-streamed-page-at-a-few-milliseconds)
|
|
58
60
|
- [A page, or a missing path, answers 401 behind a guard](#a-page-or-a-missing-path-answers-401-behind-a-guard)
|
|
59
61
|
- [The logger, CORS or secure headers miss the client's files](#the-logger-cors-or-secure-headers-miss-the-clients-files)
|
|
60
|
-
- [`
|
|
62
|
+
- [A `page()` is not served under `react-router dev`](#a-page-is-not-served-under-react-router-dev)
|
|
61
63
|
- [A `publish` under `react-router dev` misses the sockets opened before an edit](#a-publish-under-react-router-dev-misses-the-sockets-opened-before-an-edit)
|
|
62
64
|
- [The build has a package's Node variant, not its `bun` one](#the-build-has-a-packages-node-variant-not-its-bun-one)
|
|
63
65
|
- [`request.url` in a loader is `http://` and the internal host behind a proxy](#requesturl-in-a-loader-is-http-and-the-internal-host-behind-a-proxy)
|
|
@@ -109,7 +111,11 @@ with [the entry above](#alxia-react-router--is-running-on-node-and-alxias-server
|
|
|
109
111
|
Error: alxiaOf(): this request has no alxia context. Serve the React Router app through alxia: add alxia() from @alxia/react-router/vite to vite.config.ts's plugins, or, with a server of your own, serve the build through reactRouter() from @alxia/react-router.
|
|
110
112
|
```
|
|
111
113
|
|
|
112
|
-
**When:** a loader calls `alxiaOf
|
|
114
|
+
**When:** a loader calls `alxiaOf`, or reads `context.alxia`, and
|
|
115
|
+
`alxiaContext` was not set. `context.alxia` throws the same error: it reads
|
|
116
|
+
that key. With two copies of `@alxia/react-router` in one process (the
|
|
117
|
+
third case below), the getter is the copy loaded last, which reads its own
|
|
118
|
+
key: one copy is the fix for both.
|
|
113
119
|
|
|
114
120
|
**Why:** one of three:
|
|
115
121
|
|
|
@@ -154,6 +160,34 @@ context.set(alxiaContext, { user: { name: 'Ada' } });
|
|
|
154
160
|
await loader({ context, request: new Request('http://localhost/'), params: {} } as never);
|
|
155
161
|
```
|
|
156
162
|
|
|
163
|
+
### `TypeError: undefined is not an object (evaluating 'context.alxia.user')`
|
|
164
|
+
|
|
165
|
+
**When:** a unit test calls a loader that reads `context.alxia` with a
|
|
166
|
+
`new RouterContextProvider()`, and nothing in the test imports
|
|
167
|
+
`@alxia/react-router`; destructured, `const { user } = context.alxia` fails
|
|
168
|
+
with `TypeError: Cannot destructure property 'user' from null or undefined
|
|
169
|
+
value`. A `clientLoader` or a `clientAction` reading it fails the same way
|
|
170
|
+
in the browser.
|
|
171
|
+
|
|
172
|
+
**Why:** `context.alxia` is a getter `@alxia/react-router` defines on React
|
|
173
|
+
Router's provider when it is first imported. The loader's module need not
|
|
174
|
+
import it, and the browser never loads it: the alxia context is the
|
|
175
|
+
server's.
|
|
176
|
+
|
|
177
|
+
**Fix:** in the test, set the key the getter reads, imported from
|
|
178
|
+
`@alxia/react-router`, which installs the getter:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { alxiaContext } from '@alxia/react-router';
|
|
182
|
+
import { RouterContextProvider } from 'react-router';
|
|
183
|
+
|
|
184
|
+
const context = new RouterContextProvider();
|
|
185
|
+
context.set(alxiaContext, { user: { name: 'Ada' }, server: undefined });
|
|
186
|
+
await loader({ context, request: new Request('http://localhost/'), params: {} } as never);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
On the client, read the data the server's loader returned instead.
|
|
190
|
+
|
|
157
191
|
### `Error: No value found for context`
|
|
158
192
|
|
|
159
193
|
**When:** a loader, action or middleware calls `context.get(key)` with a
|
|
@@ -738,6 +772,42 @@ put the final stage back on `oven/bun:1`
|
|
|
738
772
|
|
|
739
773
|
## Types
|
|
740
774
|
|
|
775
|
+
### `Property 'alxia' does not exist on type 'Readonly<RouterContextProvider>'`
|
|
776
|
+
|
|
777
|
+
```text
|
|
778
|
+
app/routes/home.tsx: error TS2339: Property 'alxia' does not exist on type 'Readonly<RouterContextProvider>'.
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
**When:** a loader or an action typed with the generated `Route.LoaderArgs`
|
|
782
|
+
or `Route.ActionArgs` reads `context.alxia`. At runtime it is there; only
|
|
783
|
+
`tsc` refuses it.
|
|
784
|
+
|
|
785
|
+
**Why:** this package augments `RouterContextProvider` as `react-router`
|
|
786
|
+
exports it, whose types are `dist/production`'s. The generated `+types`
|
|
787
|
+
files read their argument types from `react-router/internal`, whose types,
|
|
788
|
+
in react-router 8.4, point at `dist/development`: a second declaration of
|
|
789
|
+
the class, which no exported path reaches, so no augmentation can add
|
|
790
|
+
`alxia` to it.
|
|
791
|
+
|
|
792
|
+
**Fix:** wrap the loader in `withAlxia`, which hands it `alxia` typed the
|
|
793
|
+
same way, and keeps the generated `loaderData`:
|
|
794
|
+
|
|
795
|
+
```ts
|
|
796
|
+
import { type AlxiaArgs, withAlxia } from '@alxia/react-router';
|
|
797
|
+
import type { Route } from './+types/home';
|
|
798
|
+
|
|
799
|
+
export const loader = withAlxia(({ alxia }: Route.LoaderArgs & AlxiaArgs) => {
|
|
800
|
+
return { name: alxia.user?.name ?? null };
|
|
801
|
+
});
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
Or read `alxiaOf(context)` inside the plain function.
|
|
805
|
+
|
|
806
|
+
Or type the arguments with `LoaderFunctionArgs` from `react-router`, which
|
|
807
|
+
sees `context.alxia`, at the cost of the generated `params`. Typing it under
|
|
808
|
+
`Route.LoaderArgs` waits on react-router pointing both entries at the same
|
|
809
|
+
declarations.
|
|
810
|
+
|
|
741
811
|
### `Property '…' does not exist on type 'BaseContext & …'`
|
|
742
812
|
|
|
743
813
|
```text
|
|
@@ -1034,22 +1104,25 @@ createServer({
|
|
|
1034
1104
|
});
|
|
1035
1105
|
```
|
|
1036
1106
|
|
|
1037
|
-
### `
|
|
1107
|
+
### A `page()` is not served under `react-router dev`
|
|
1038
1108
|
|
|
1039
|
-
|
|
1040
|
-
under `react-router dev` or `vite preview`; the same
|
|
1041
|
-
`bun build/server/index.js`.
|
|
1109
|
+
The app declares a `page()`, or reads `ctx.server.url`, `requestIP` or
|
|
1110
|
+
`timeout`, or `ctx.ip`, under `react-router dev` or `vite preview`; the same
|
|
1111
|
+
code works from `bun build/server/index.js`.
|
|
1042
1112
|
|
|
1043
1113
|
**Why:** under `@alxia/react-router/vite`, Vite owns the dev server, and
|
|
1044
|
-
the preview server under `vite preview
|
|
1045
|
-
|
|
1046
|
-
`
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1114
|
+
the preview server under `vite preview`: a `node:http` server, not a
|
|
1115
|
+
`Bun.Server`. An HTTP request reaches the app through
|
|
1116
|
+
`app.fetch(request, side)`, where `side` is the loopback `Bun.serve` the
|
|
1117
|
+
plugin relays the app's sockets to. So `ctx.server` is that side server: its
|
|
1118
|
+
`publish` reaches the app's sockets, but its `url` is the loopback port's,
|
|
1119
|
+
and its `requestIP` and `timeout` know nothing of a request Vite took, so
|
|
1120
|
+
the default `ctx.ip` is `undefined`. A `page()` (Bun's HTML bundle) is not
|
|
1121
|
+
served: Vite answers the HTML
|
|
1122
|
+
([The server](guide.md#the-server-server)).
|
|
1123
|
+
|
|
1124
|
+
**Fix:** read `ctx.server` as optional, which also covers `app.request` in
|
|
1125
|
+
a test, and take nothing from its `url` or `requestIP` in dev:
|
|
1053
1126
|
|
|
1054
1127
|
```ts
|
|
1055
1128
|
// app/server.ts
|
|
@@ -1072,7 +1145,7 @@ Two clients in one room; after an edit to `app/server.ts`, a message one
|
|
|
1072
1145
|
sends no longer reaches the other.
|
|
1073
1146
|
|
|
1074
1147
|
**Why:** an edit to the server makes a new app, and the plugin starts a
|
|
1075
|
-
new `Bun.serve` for it on the next upgrade, so that new connections use
|
|
1148
|
+
new `Bun.serve` for it on the next upgrade or request, so that new connections use
|
|
1076
1149
|
the new handlers. A socket opened before the edit stays on the previous
|
|
1077
1150
|
server, with the handlers it opened with, and a topic is one server's.
|
|
1078
1151
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alxia/react-router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@alxia/compress": "^0.3.9",
|
|
55
|
-
"@alxia/core": "^0.14.
|
|
55
|
+
"@alxia/core": "^0.14.2",
|
|
56
56
|
"@alxia/openapi": "^0.6.8",
|
|
57
57
|
"@react-router/dev": "^8.4.0",
|
|
58
58
|
"@types/bun": "^1.4.2",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"vite": "^7.0.0"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
68
|
-
"@alxia/core": "^0.14.
|
|
68
|
+
"@alxia/core": "^0.14.2",
|
|
69
69
|
"react-router": "^8.0.0",
|
|
70
70
|
"typescript": "^6.0.3 || ^7.0.0",
|
|
71
71
|
"vite": "^7.0.0 || ^8.0.0"
|