@webtypen/webframez-react 0.0.1 → 0.0.3
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 +276 -52
- package/bin/webframez-react.mjs +309 -0
- package/defaults/tsconfig.server.example.json +46 -0
- package/defaults/tsconfig.server.json +64 -0
- package/defaults/webpack.client.cjs +64 -0
- package/defaults/webpack.server.cjs +40 -0
- package/dist/client.cjs +1 -1
- package/dist/client.js +1 -1
- package/dist/http.cjs +50 -11
- package/dist/http.d.ts +18 -7
- package/dist/http.js +50 -11
- package/dist/index.cjs +50 -11
- package/dist/index.d.ts +2 -5
- package/dist/index.js +50 -11
- package/dist/router.cjs +30 -10
- package/dist/router.js +30 -10
- package/dist/types.d.ts +25 -8
- package/dist/webframez-core.cjs +50 -11
- package/dist/webframez-core.d.ts +32 -8
- package/dist/webframez-core.js +50 -11
- package/package.json +13 -3
package/README.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
# webframez-react
|
|
1
|
+
# @webtypen/webframez-react
|
|
2
2
|
|
|
3
3
|
React Server Components (RSC) extension for `@webtypen/webframez-core`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`@webtypen/webframez-react` provides:
|
|
6
6
|
- seamless `webframez-core` integration via `initWebframezReact(Route)`
|
|
7
7
|
- file-based routing for `pages/**/index.tsx`
|
|
8
8
|
- layout/error handling with `RouteChildren`
|
|
9
9
|
- client-side navigation (`Link`, `Redirect`, `useRouter`) and cookies (`useCookie`)
|
|
10
10
|
- server-rendered initial HTML plus RSC streaming
|
|
11
|
+
- a small CLI for the standard server/client build pipeline
|
|
11
12
|
|
|
12
13
|
## Requirements
|
|
13
14
|
|
|
@@ -19,29 +20,269 @@ React Server Components (RSC) extension for `@webtypen/webframez-core`.
|
|
|
19
20
|
|
|
20
21
|
```bash
|
|
21
22
|
npm i @webtypen/webframez-react @webtypen/webframez-core react react-dom react-server-dom-webpack
|
|
23
|
+
npm i -D typescript webpack webpack-cli ts-loader
|
|
22
24
|
```
|
|
23
25
|
|
|
24
26
|
## Quick Start with webframez-core
|
|
25
27
|
|
|
26
28
|
```ts
|
|
27
|
-
// server.ts
|
|
28
|
-
import
|
|
29
|
-
import {
|
|
29
|
+
// src/server.ts
|
|
30
|
+
import path from "node:path";
|
|
31
|
+
import { BaseKernelWeb, Route, WebApplication } from "@webtypen/webframez-core";
|
|
32
|
+
import { initWebframezReact } from "@webtypen/webframez-react";
|
|
33
|
+
|
|
34
|
+
class Kernel extends BaseKernelWeb {
|
|
35
|
+
static controller = {};
|
|
36
|
+
static middleware = {};
|
|
37
|
+
}
|
|
30
38
|
|
|
31
|
-
initWebframezReact(Route);
|
|
39
|
+
const ReactRoute = initWebframezReact(Route);
|
|
32
40
|
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
const app = new WebApplication();
|
|
42
|
+
app.boot({
|
|
43
|
+
kernel: Kernel,
|
|
44
|
+
routesFunction: () => {
|
|
45
|
+
ReactRoute.renderReact("/react", {
|
|
46
|
+
distRootDir: path.resolve(process.cwd(), "dist"),
|
|
47
|
+
});
|
|
48
|
+
},
|
|
35
49
|
});
|
|
36
|
-
|
|
37
|
-
WebApplication.boot();
|
|
38
50
|
```
|
|
39
51
|
|
|
40
52
|
Notes:
|
|
41
53
|
- `"/react"` is automatically registered as a catch-all route (`/react/*`).
|
|
42
|
-
- `basePath`, `assetsPrefix`, `rscPath`, and `clientScriptUrl` are derived automatically from the mount path.
|
|
54
|
+
- `basePath`, `assetsPrefix`, `rscPath`, and `clientScriptUrl` are derived automatically from the mount path unless you override them.
|
|
55
|
+
- `initWebframezReact(Route)` returns the extended route facade, which gives you reliable editor autocompletion for `renderReact(...)` even in monorepos or symlinked development setups.
|
|
56
|
+
- The package also ships module augmentation for `Route.renderReact(...)`, but using the returned `ReactRoute` variable is the most robust TypeScript setup.
|
|
43
57
|
|
|
44
|
-
##
|
|
58
|
+
## `Route.renderReact()`
|
|
59
|
+
|
|
60
|
+
Signature:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
Route.renderReact(path, options)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Example:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
Route.renderReact("/app", {
|
|
70
|
+
distRootDir: path.resolve(process.cwd(), "dist"),
|
|
71
|
+
method: "GET",
|
|
72
|
+
routeOptions: {
|
|
73
|
+
middleware: ["auth"],
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Options
|
|
79
|
+
|
|
80
|
+
`distRootDir`
|
|
81
|
+
- Required.
|
|
82
|
+
- Directory containing the built client assets and generated manifests.
|
|
83
|
+
|
|
84
|
+
`pagesDir`
|
|
85
|
+
- Optional.
|
|
86
|
+
- Directory containing the compiled `pages/**` output.
|
|
87
|
+
- Default: `${distRootDir}/pages`
|
|
88
|
+
|
|
89
|
+
`manifestPath`
|
|
90
|
+
- Optional.
|
|
91
|
+
- Path to the React client manifest.
|
|
92
|
+
- Default: `${distRootDir}/react-client-manifest.json`
|
|
93
|
+
|
|
94
|
+
`assetsPrefix`
|
|
95
|
+
- Optional.
|
|
96
|
+
- Public URL prefix used to serve built client assets.
|
|
97
|
+
- Auto-derived from `path`.
|
|
98
|
+
- Example for `"/react"`: `/react/assets/`
|
|
99
|
+
|
|
100
|
+
`rscPath`
|
|
101
|
+
- Optional.
|
|
102
|
+
- Public URL for the RSC endpoint.
|
|
103
|
+
- Auto-derived from `path`.
|
|
104
|
+
- Example for `"/react"`: `/react/rsc`
|
|
105
|
+
|
|
106
|
+
`clientScriptUrl`
|
|
107
|
+
- Optional.
|
|
108
|
+
- Public URL of the browser client entry bundle.
|
|
109
|
+
- Auto-derived from `path`.
|
|
110
|
+
- Example for `"/react"`: `/react/assets/client.js`
|
|
111
|
+
|
|
112
|
+
`basePath`
|
|
113
|
+
- Optional.
|
|
114
|
+
- Basename mounted in front of all file-router paths.
|
|
115
|
+
- Auto-derived from `path` when `path !== "/"`.
|
|
116
|
+
|
|
117
|
+
`liveReloadPath`
|
|
118
|
+
- Optional.
|
|
119
|
+
- Enables dev live reload on a custom path or disables it explicitly with `false`.
|
|
120
|
+
- Automatically disabled in production mode.
|
|
121
|
+
|
|
122
|
+
`method`
|
|
123
|
+
- Optional.
|
|
124
|
+
- HTTP method or methods used to register the route.
|
|
125
|
+
- Supported values: `"GET" | "POST" | "PUT" | "DELETE"`
|
|
126
|
+
- Default: `"GET"`
|
|
127
|
+
|
|
128
|
+
`routeOptions`
|
|
129
|
+
- Optional.
|
|
130
|
+
- Additional route options forwarded to `webframez-core`.
|
|
131
|
+
- Typical use case: middleware.
|
|
132
|
+
|
|
133
|
+
## Recommended Project Structure
|
|
134
|
+
|
|
135
|
+
```txt
|
|
136
|
+
pages/
|
|
137
|
+
layout.tsx
|
|
138
|
+
errors.tsx
|
|
139
|
+
index.tsx
|
|
140
|
+
about/index.tsx
|
|
141
|
+
src/
|
|
142
|
+
server.ts
|
|
143
|
+
client.tsx
|
|
144
|
+
components/
|
|
145
|
+
dist/
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## `tsconfig.server.json`
|
|
149
|
+
|
|
150
|
+
Compared to a standard `@webtypen/webframez-core` project, the server TypeScript config usually needs a few changes:
|
|
151
|
+
|
|
152
|
+
- enable JSX via `"jsx": "react-jsx"`
|
|
153
|
+
- include `pages/**/*.tsx`
|
|
154
|
+
- include `src/components/**/*.tsx`
|
|
155
|
+
- include your server entry (`src/server.ts` or `src/server.tsx`)
|
|
156
|
+
- exclude the browser client entry (`src/client.tsx` by default)
|
|
157
|
+
- add `paths` mappings for the `@webtypen/webframez-react` package and its subpaths
|
|
158
|
+
|
|
159
|
+
When you use the CLI (`webframez-react build:server` / `watch:server`), it generates a temporary `.webframez-react.tsconfig.server.json` that extends your project `tsconfig.server.json`. That means:
|
|
160
|
+
|
|
161
|
+
- your own `tsconfig.server.json` stays the source of truth
|
|
162
|
+
- the CLI only injects the resolved server entry and the standard RSC include/exclude rules
|
|
163
|
+
- you only need to customize the base config when your project structure differs from the defaults
|
|
164
|
+
|
|
165
|
+
A good starting point is the shipped default config:
|
|
166
|
+
|
|
167
|
+
- `@webtypen/webframez-react/defaults/tsconfig.server`
|
|
168
|
+
- `@webtypen/webframez-react/defaults/tsconfig.server.example`
|
|
169
|
+
|
|
170
|
+
Example:
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"compilerOptions": {
|
|
175
|
+
"target": "ES2020",
|
|
176
|
+
"module": "CommonJS",
|
|
177
|
+
"moduleResolution": "Node",
|
|
178
|
+
"baseUrl": ".",
|
|
179
|
+
"paths": {
|
|
180
|
+
"@webtypen/webframez-react": [
|
|
181
|
+
"./node_modules/@webtypen/webframez-react/dist/index.d.ts"
|
|
182
|
+
],
|
|
183
|
+
"@webtypen/webframez-react/types": [
|
|
184
|
+
"./node_modules/@webtypen/webframez-react/dist/types.d.ts"
|
|
185
|
+
],
|
|
186
|
+
"@webtypen/webframez-react/router": [
|
|
187
|
+
"./node_modules/@webtypen/webframez-react/dist/router.d.ts"
|
|
188
|
+
],
|
|
189
|
+
"@webtypen/webframez-react/client": [
|
|
190
|
+
"./node_modules/@webtypen/webframez-react/dist/client.d.ts"
|
|
191
|
+
],
|
|
192
|
+
"@webtypen/webframez-react/navigation": [
|
|
193
|
+
"./node_modules/@webtypen/webframez-react/dist/navigation.d.ts"
|
|
194
|
+
],
|
|
195
|
+
"@webtypen/webframez-react/webframez-core": [
|
|
196
|
+
"./node_modules/@webtypen/webframez-react/dist/webframez-core.d.ts"
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
"jsx": "react-jsx",
|
|
200
|
+
"strict": true,
|
|
201
|
+
"esModuleInterop": true,
|
|
202
|
+
"skipLibCheck": true,
|
|
203
|
+
"outDir": "dist",
|
|
204
|
+
"rootDir": "."
|
|
205
|
+
},
|
|
206
|
+
"include": [
|
|
207
|
+
"src/server.ts",
|
|
208
|
+
"src/server.tsx",
|
|
209
|
+
"src/components/**/*.tsx",
|
|
210
|
+
"pages/**/*.tsx",
|
|
211
|
+
"src/types.d.ts"
|
|
212
|
+
],
|
|
213
|
+
"exclude": [
|
|
214
|
+
"src/client.tsx",
|
|
215
|
+
"dist",
|
|
216
|
+
"node_modules"
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## `package.json` Scripts
|
|
222
|
+
|
|
223
|
+
Recommended scripts:
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"scripts": {
|
|
228
|
+
"build:server": "webframez-react build:server",
|
|
229
|
+
"build:client": "webframez-react build:client",
|
|
230
|
+
"build": "npm run build:server && npm run build:client",
|
|
231
|
+
"start": "node --conditions react-server start-server.cjs",
|
|
232
|
+
"watch:server": "webframez-react watch:server",
|
|
233
|
+
"watch:client": "webframez-react watch:client",
|
|
234
|
+
"serve:watch": "node --watch --conditions react-server start-server.cjs",
|
|
235
|
+
"watch": "sh -c 'npm run watch:server & npm run watch:client & npm run serve:watch & wait'",
|
|
236
|
+
"dev": "sh -c 'npm run watch:server & npm run watch:client & npm run serve:watch & wait'"
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Notes:
|
|
242
|
+
- `build` compiles the server output (`pages`, `server.ts`) and the browser client bundle (`client.tsx` + RSC manifests).
|
|
243
|
+
- `start` runs the built app in React Server mode.
|
|
244
|
+
- `watch` / `dev` keep TypeScript and webpack in watch mode and restart Node automatically when server output changes.
|
|
245
|
+
|
|
246
|
+
## CLI Config and Custom Entry Paths
|
|
247
|
+
|
|
248
|
+
The CLI first checks project override files and then falls back to the package defaults:
|
|
249
|
+
|
|
250
|
+
- `tsconfig.server.json`
|
|
251
|
+
- `webpack.client.cjs`
|
|
252
|
+
- `webpack.server.cjs`
|
|
253
|
+
|
|
254
|
+
If you do not want to create your own webpack config just to move `client.tsx` or `server.ts`, you can use a small project config file:
|
|
255
|
+
|
|
256
|
+
```js
|
|
257
|
+
// webframez-react.config.mjs
|
|
258
|
+
export default {
|
|
259
|
+
clientEntryPath: "src/app/client.tsx",
|
|
260
|
+
serverEntryPath: "src/app/server.tsx",
|
|
261
|
+
};
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Supported file names:
|
|
265
|
+
- `webframez-react.config.mjs`
|
|
266
|
+
- `webframez-react.config.cjs`
|
|
267
|
+
- `webframez-react.config.js`
|
|
268
|
+
- `webframez-react.config.json`
|
|
269
|
+
|
|
270
|
+
You can also override the entry paths per command:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
webframez-react build:client --client-entry=src/app/client.tsx
|
|
274
|
+
webframez-react build:server --server-entry=src/app/server.tsx
|
|
275
|
+
webframez-react watch:client --client-entry=src/app/client.tsx
|
|
276
|
+
webframez-react watch:server --server-entry=src/app/server.tsx
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Notes:
|
|
280
|
+
- The default client entry is `src/client.tsx`.
|
|
281
|
+
- The default server entry is `src/server.ts`, with automatic fallback to `src/server.tsx` if present.
|
|
282
|
+
- `build:server:webpack` and `watch:server:webpack` also respect `serverEntryPath`.
|
|
283
|
+
- `build:server` and `watch:server` generate a temporary `.webframez-react.tsconfig.server.json` so custom server entry paths also work with the TypeScript compiler.
|
|
284
|
+
|
|
285
|
+
## File-Based Routing
|
|
45
286
|
|
|
46
287
|
Example:
|
|
47
288
|
|
|
@@ -60,7 +301,7 @@ pages/
|
|
|
60
301
|
"use server";
|
|
61
302
|
|
|
62
303
|
import React from "react";
|
|
63
|
-
import { RouteChildren } from "webframez-react/router";
|
|
304
|
+
import { RouteChildren } from "@webtypen/webframez-react/router";
|
|
64
305
|
|
|
65
306
|
export default function Layout() {
|
|
66
307
|
return (
|
|
@@ -81,7 +322,7 @@ Every server page gets `abort()` via `RouteContext`.
|
|
|
81
322
|
```tsx
|
|
82
323
|
"use server";
|
|
83
324
|
|
|
84
|
-
import type { PageProps } from "webframez-react/types";
|
|
325
|
+
import type { PageProps } from "@webtypen/webframez-react/types";
|
|
85
326
|
|
|
86
327
|
export default function AccountPage({ params, abort }: PageProps) {
|
|
87
328
|
if (params.username !== "jane") {
|
|
@@ -98,7 +339,7 @@ export default function AccountPage({ params, abort }: PageProps) {
|
|
|
98
339
|
|
|
99
340
|
Behavior:
|
|
100
341
|
- default without options: `404` + `"Page not found"`
|
|
101
|
-
- rendered through `pages/errors.tsx`
|
|
342
|
+
- rendered through `pages/errors.tsx`
|
|
102
343
|
- `pathname` is provided automatically by context
|
|
103
344
|
- optional `payload` is forwarded to `errors.tsx`
|
|
104
345
|
|
|
@@ -106,7 +347,7 @@ Behavior:
|
|
|
106
347
|
|
|
107
348
|
```tsx
|
|
108
349
|
// src/client.tsx
|
|
109
|
-
import { mountWebframezClient } from "webframez-react/client";
|
|
350
|
+
import { mountWebframezClient } from "@webtypen/webframez-react/client";
|
|
110
351
|
|
|
111
352
|
mountWebframezClient();
|
|
112
353
|
```
|
|
@@ -126,7 +367,7 @@ mountWebframezClient({
|
|
|
126
367
|
"use client";
|
|
127
368
|
|
|
128
369
|
import React from "react";
|
|
129
|
-
import { Link, Redirect } from "webframez-react/navigation";
|
|
370
|
+
import { Link, Redirect } from "@webtypen/webframez-react/navigation";
|
|
130
371
|
|
|
131
372
|
export function Nav() {
|
|
132
373
|
return (
|
|
@@ -146,7 +387,7 @@ export function Guard({ loggedIn }: { loggedIn: boolean }) {
|
|
|
146
387
|
}
|
|
147
388
|
```
|
|
148
389
|
|
|
149
|
-
|
|
390
|
+
Notes:
|
|
150
391
|
- `Link` and `Redirect` automatically use the basename from `Route.renderReact()`.
|
|
151
392
|
- You can override it per usage via `basename`.
|
|
152
393
|
|
|
@@ -156,7 +397,7 @@ Note:
|
|
|
156
397
|
"use client";
|
|
157
398
|
|
|
158
399
|
import React from "react";
|
|
159
|
-
import { useCookie, useRouter } from "webframez-react/client";
|
|
400
|
+
import { useCookie, useRouter } from "@webtypen/webframez-react/client";
|
|
160
401
|
|
|
161
402
|
export default function LoginAction() {
|
|
162
403
|
const cookie = useCookie();
|
|
@@ -177,50 +418,33 @@ export default function LoginAction() {
|
|
|
177
418
|
|
|
178
419
|
## Public Entrypoints
|
|
179
420
|
|
|
180
|
-
-
|
|
181
|
-
- `
|
|
182
|
-
- `
|
|
421
|
+
- `@webtypen/webframez-react`
|
|
422
|
+
- `initWebframezReact`
|
|
423
|
+
- `createNodeRequestHandler`
|
|
424
|
+
- `createFileRouter`
|
|
425
|
+
- `createHTMLShell`
|
|
426
|
+
- `sendRSC`
|
|
427
|
+
- `createRSCHandler`
|
|
428
|
+
- `@webtypen/webframez-react/webframez-core`
|
|
183
429
|
- `initWebframezReact`
|
|
184
|
-
-
|
|
430
|
+
- `@webtypen/webframez-react/router`
|
|
185
431
|
- `RouteChildren`
|
|
186
|
-
-
|
|
432
|
+
- `@webtypen/webframez-react/client`
|
|
187
433
|
- `mountWebframezClient`, `useRouter`, `useCookie`
|
|
188
|
-
-
|
|
434
|
+
- `@webtypen/webframez-react/navigation`
|
|
189
435
|
- `Link`, `Redirect`
|
|
190
|
-
-
|
|
191
|
-
-
|
|
192
|
-
|
|
193
|
-
## package.json Scripts
|
|
194
|
-
|
|
195
|
-
Example scripts for a `webframez-react` app:
|
|
196
|
-
|
|
197
|
-
```json
|
|
198
|
-
{
|
|
199
|
-
"scripts": {
|
|
200
|
-
"build:server": "tsc -p tsconfig.server.json",
|
|
201
|
-
"build:client": "webpack --config webpack.client.cjs",
|
|
202
|
-
"build": "npm run build:server && npm run build:client",
|
|
203
|
-
"start": "node --conditions react-server start-server.cjs",
|
|
204
|
-
"watch:server": "tsc -p tsconfig.server.json --watch --preserveWatchOutput",
|
|
205
|
-
"watch:client": "webpack --config webpack.client.cjs --watch",
|
|
206
|
-
"serve:watch": "node --watch --conditions react-server start-server.cjs",
|
|
207
|
-
"dev": "sh -c 'npm run watch:server & npm run watch:client & npm run serve:watch & wait'"
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
```
|
|
436
|
+
- `@webtypen/webframez-react/types`
|
|
437
|
+
- `RouteContext`, `PageProps`, `ErrorPageProps`, `AbortRouteOptions`, ...
|
|
211
438
|
|
|
212
|
-
|
|
213
|
-
- `build` compiles server output (`pages`, `server.ts`) and client output (`client.tsx` bundle + RSC manifests).
|
|
214
|
-
- `start` runs the built app in React Server mode.
|
|
215
|
-
- `dev` enables watch mode for TypeScript and webpack and restarts Node automatically on server output changes.
|
|
439
|
+
## Package Build
|
|
216
440
|
|
|
217
|
-
|
|
441
|
+
Build the package itself:
|
|
218
442
|
|
|
219
443
|
```bash
|
|
220
444
|
npm run build
|
|
221
445
|
```
|
|
222
446
|
|
|
223
|
-
Watch mode:
|
|
447
|
+
Watch mode for package development:
|
|
224
448
|
|
|
225
449
|
```bash
|
|
226
450
|
npm run build:watch
|