waku 0.16.0 → 0.17.1

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.
Files changed (110) hide show
  1. package/README.md +299 -0
  2. package/dist/cjs/cli.js +75 -331
  3. package/dist/cjs/client.js +67 -348
  4. package/dist/cjs/config.js +0 -9
  5. package/dist/cjs/lib/builder.js +339 -1013
  6. package/dist/cjs/lib/config.js +76 -243
  7. package/dist/cjs/lib/middleware/rsc/ssr.js +346 -0
  8. package/dist/cjs/lib/middleware/rsc/utils.js +40 -74
  9. package/dist/cjs/lib/middleware/rsc/worker-api.js +90 -375
  10. package/dist/cjs/lib/middleware/rsc/worker-impl.js +362 -1109
  11. package/dist/cjs/lib/middleware/rsc.js +198 -252
  12. package/dist/cjs/lib/vite-plugin/nonjs-resolve-plugin.js +19 -230
  13. package/dist/cjs/lib/vite-plugin/patch-react-refresh.js +33 -0
  14. package/dist/cjs/lib/vite-plugin/rsc-analyze-plugin.js +81 -35
  15. package/dist/cjs/lib/vite-plugin/rsc-delegate-plugin.js +31 -46
  16. package/dist/cjs/lib/vite-plugin/rsc-hmr-plugin.js +29 -176
  17. package/dist/cjs/lib/vite-plugin/rsc-index-plugin.js +22 -178
  18. package/dist/cjs/lib/vite-plugin/rsc-reload-plugin.js +30 -204
  19. package/dist/cjs/lib/vite-plugin/rsc-transform-plugin.js +57 -337
  20. package/dist/cjs/main.js +6 -180
  21. package/dist/cjs/node-loader.js +12 -210
  22. package/dist/cjs/router/client.js +89 -181
  23. package/dist/cjs/router/common.js +37 -121
  24. package/dist/cjs/router/server.js +81 -436
  25. package/dist/cjs/server.js +14 -30
  26. package/dist/cli.js +70 -310
  27. package/dist/client.d.ts +6 -2
  28. package/dist/client.js +65 -349
  29. package/dist/config.d.ts +13 -18
  30. package/dist/config.js +1 -3
  31. package/dist/lib/builder.d.ts +3 -1
  32. package/dist/lib/builder.js +339 -1013
  33. package/dist/lib/config.d.ts +14 -57
  34. package/dist/lib/config.js +41 -249
  35. package/dist/lib/middleware/rsc/ssr.d.ts +6 -0
  36. package/dist/lib/middleware/rsc/ssr.js +280 -0
  37. package/dist/lib/middleware/rsc/utils.d.ts +2 -3
  38. package/dist/lib/middleware/rsc/utils.js +34 -72
  39. package/dist/lib/middleware/rsc/worker-api.d.ts +29 -30
  40. package/dist/lib/middleware/rsc/worker-api.js +89 -371
  41. package/dist/lib/middleware/rsc/worker-impl.js +322 -1110
  42. package/dist/lib/middleware/rsc.d.ts +3 -2
  43. package/dist/lib/middleware/rsc.js +156 -256
  44. package/dist/lib/vite-plugin/nonjs-resolve-plugin.d.ts +1 -1
  45. package/dist/lib/vite-plugin/nonjs-resolve-plugin.js +19 -230
  46. package/dist/lib/vite-plugin/patch-react-refresh.d.ts +2 -0
  47. package/dist/lib/vite-plugin/patch-react-refresh.js +23 -0
  48. package/dist/lib/vite-plugin/rsc-analyze-plugin.d.ts +2 -2
  49. package/dist/lib/vite-plugin/rsc-analyze-plugin.js +78 -34
  50. package/dist/lib/vite-plugin/rsc-delegate-plugin.d.ts +1 -1
  51. package/dist/lib/vite-plugin/rsc-delegate-plugin.js +28 -45
  52. package/dist/lib/vite-plugin/rsc-hmr-plugin.d.ts +1 -1
  53. package/dist/lib/vite-plugin/rsc-hmr-plugin.js +29 -176
  54. package/dist/lib/vite-plugin/rsc-index-plugin.d.ts +1 -1
  55. package/dist/lib/vite-plugin/rsc-index-plugin.js +22 -178
  56. package/dist/lib/vite-plugin/rsc-reload-plugin.d.ts +2 -2
  57. package/dist/lib/vite-plugin/rsc-reload-plugin.js +27 -203
  58. package/dist/lib/vite-plugin/rsc-transform-plugin.d.ts +1 -1
  59. package/dist/lib/vite-plugin/rsc-transform-plugin.js +53 -335
  60. package/dist/main.d.ts +4 -5
  61. package/dist/main.js +3 -169
  62. package/dist/node-loader.d.ts +3 -1
  63. package/dist/node-loader.js +12 -210
  64. package/dist/router/client.d.ts +10 -5
  65. package/dist/router/client.js +89 -179
  66. package/dist/router/common.d.ts +0 -8
  67. package/dist/router/common.js +37 -121
  68. package/dist/router/server.d.ts +2 -4
  69. package/dist/router/server.js +75 -427
  70. package/dist/server.d.ts +6 -22
  71. package/dist/server.js +14 -26
  72. package/package.json +22 -10
  73. package/src/cli.ts +39 -68
  74. package/src/client.ts +30 -23
  75. package/src/config.ts +13 -29
  76. package/src/lib/builder.ts +186 -198
  77. package/src/lib/config.ts +32 -42
  78. package/src/lib/middleware/rsc/ssr.ts +359 -0
  79. package/src/lib/middleware/rsc/utils.ts +22 -32
  80. package/src/lib/middleware/rsc/worker-api.ts +89 -102
  81. package/src/lib/middleware/rsc/worker-impl.ts +182 -172
  82. package/src/lib/middleware/rsc.ts +172 -31
  83. package/src/lib/vite-plugin/nonjs-resolve-plugin.ts +5 -5
  84. package/src/lib/vite-plugin/patch-react-refresh.ts +26 -0
  85. package/src/lib/vite-plugin/rsc-analyze-plugin.ts +80 -14
  86. package/src/lib/vite-plugin/rsc-delegate-plugin.ts +14 -14
  87. package/src/lib/vite-plugin/rsc-hmr-plugin.ts +7 -7
  88. package/src/lib/vite-plugin/rsc-index-plugin.ts +9 -9
  89. package/src/lib/vite-plugin/rsc-reload-plugin.ts +13 -13
  90. package/src/lib/vite-plugin/rsc-transform-plugin.ts +10 -10
  91. package/src/main.ts +3 -8
  92. package/src/node-loader.ts +8 -6
  93. package/src/router/client.ts +30 -34
  94. package/src/router/common.ts +18 -28
  95. package/src/router/server.ts +28 -60
  96. package/src/server.ts +9 -32
  97. package/src/types.d.ts +5 -5
  98. package/dist/.tsbuildinfo +0 -1
  99. package/dist/cjs/lib/middleware/devServer.js +0 -288
  100. package/dist/cjs/lib/middleware/ssr/utils.js +0 -150
  101. package/dist/cjs/lib/middleware/ssr.js +0 -454
  102. package/dist/lib/middleware/devServer.d.ts +0 -5
  103. package/dist/lib/middleware/devServer.js +0 -273
  104. package/dist/lib/middleware/ssr/utils.d.ts +0 -2
  105. package/dist/lib/middleware/ssr/utils.js +0 -135
  106. package/dist/lib/middleware/ssr.d.ts +0 -7
  107. package/dist/lib/middleware/ssr.js +0 -441
  108. package/src/lib/middleware/devServer.ts +0 -58
  109. package/src/lib/middleware/ssr/utils.ts +0 -88
  110. package/src/lib/middleware/ssr.ts +0 -126
package/README.md ADDED
@@ -0,0 +1,299 @@
1
+ # Waku
2
+
3
+ ⛩️ The minimal React framework
4
+
5
+ [![CI](https://img.shields.io/github/actions/workflow/status/dai-shi/waku/ci.yml?branch=main)](https://github.com/dai-shi/waku/actions?query=workflow%3ACI)
6
+ [![npm](https://img.shields.io/npm/v/waku)](https://www.npmjs.com/package/waku)
7
+ [![discord](https://img.shields.io/discord/627656437971288081)](https://discord.gg/MrQdmzd)
8
+
9
+ <!-- [![size](https://img.shields.io/bundlephobia/minzip/waku)](https://bundlephobia.com/result?p=waku) -->
10
+
11
+ ## Project status
12
+
13
+ We are working toward v1-alpha: https://github.com/dai-shi/waku/issues/24
14
+
15
+ Feel free to try it _seriously_ with non-production projects and give us feedback.
16
+
17
+ Playground: https://codesandbox.io/p/sandbox/waku-example-counter-mdc1yb
18
+
19
+ ## Introduction
20
+
21
+ Waku is a React framework that supports React Server Components
22
+ (RSCs), a new feature that will be available in a future version of
23
+ React. RSCs allow developers to render UI components on the server,
24
+ improving performance and enabling server-side features. To use RSCs,
25
+ a framework is necessary for bundling, optionally server, router and
26
+ so on.
27
+
28
+ Waku takes a minimalistic approach, providing a minimal API that
29
+ allows for multiple feature implementations and encourages growth in
30
+ the ecosystem. For example, the minimal API is not tied to a specific
31
+ router. This flexibility makes it easier to build new features.
32
+
33
+ Waku uses Vite internally, and while it is still a work in progress,
34
+ it will eventually support all of Vite's features. It can even
35
+ work as a replacement for Vite + React client components. While using
36
+ RSCs is optional, it is highly recommended for improved user and
37
+ developer experiences.
38
+
39
+ ## Why develop a React framework?
40
+
41
+ We believe that React Server Components (RSCs) are the future of React.
42
+ The challenge is that we can't utilize RSCs with the React library alone.
43
+ Instead, they require a React framework for bundling, at the very least.
44
+
45
+ Currently, only a few React frameworks support RSCs, and
46
+ they often come with more features than RSCs.
47
+ It would be nice to have a minimal framework that implements RSCs,
48
+ which should help learning how RSCs work.
49
+
50
+ Learning is the start, but it's not what we aim at.
51
+ Our assumption is that RSC best practices are still to explore.
52
+ The minimal implementation should clarify the fundamentals of RSCs
53
+ and enable the creation of additional features.
54
+ Our goal is to establish an ecosystem that covers a broader range of use cases.
55
+
56
+ ## How to create a new project
57
+
58
+ To start a new Waku project, you can use any of the following
59
+ commands, depending on your preferred package manager:
60
+
61
+ ```bash
62
+ npm create waku@latest
63
+ ```
64
+
65
+ ```bash
66
+ yarn create waku
67
+ ```
68
+
69
+ ```bash
70
+ pnpm create waku
71
+ ```
72
+
73
+ These commands will create an example app that you can use as a
74
+ starting point for your project.
75
+
76
+ Minimum requirement: Node.js 18
77
+
78
+ ## Practices
79
+
80
+ ### Minimal
81
+
82
+ #### Server API
83
+
84
+ To use React Server Components in Waku, you need to create an
85
+ `entries.ts` file in the project root directory with a
86
+ `renderEntries` function that returns a server component module.
87
+ Here's an example:
88
+
89
+ ```tsx
90
+ import { lazy } from 'react';
91
+ import { defineEntries } from 'waku/server';
92
+
93
+ const App = lazy(() => import('./components/App.js'));
94
+
95
+ export default defineEntries(
96
+ // renderEntries
97
+ async (input) => {
98
+ return {
99
+ App: <App name={input || 'Waku'} />,
100
+ };
101
+ },
102
+ );
103
+ ```
104
+
105
+ The `id` parameter is the ID of the React Server Component
106
+ that you want to load on the server. You specify the RSC ID from the
107
+ client.
108
+
109
+ #### Client API
110
+
111
+ To render a React Server Component on the client, you can use the
112
+ `Root` and `Slot` components from `waku/client` with the RSC
113
+ ID to create a wrapper component. Here's an example:
114
+
115
+ ```tsx
116
+ import { createRoot } from 'react-dom/client';
117
+ import { Root, Slot } from 'waku/client';
118
+
119
+ const rootElement = (
120
+ <StrictMode>
121
+ <Root>
122
+ <Slot id="App" />
123
+ </Root>
124
+ </StrictMode>
125
+ );
126
+
127
+ createRoot(document.getElementById('root')!).render(rootElement);
128
+ ```
129
+
130
+ The `initialInput` prop can be passed to the `Root` Component,
131
+ overriding the default input which is `""`.
132
+ You can also re-render a React Server Component with new input.
133
+ Here's an example just to illustrate the idea:
134
+
135
+ ```tsx
136
+ import { useRefetch } from 'waku/client';
137
+
138
+ const Component = () => {
139
+ const refetch = useRefetch();
140
+ const handleClick = () => {
141
+ refetch('...');
142
+ };
143
+ // ...
144
+ };
145
+ ```
146
+
147
+ #### Additional Server API
148
+
149
+ In addition to the `renderEntries` function, you can also
150
+ optionally specify `getBuildConfig` function in
151
+ `entries.ts`. Here's an example:
152
+
153
+ ```tsx
154
+ import { defineEntries } from 'waku/server';
155
+
156
+ export default defineEntries(
157
+ // renderEntries
158
+ async (input) => {
159
+ return {
160
+ App: <App name={input || 'Waku'} />,
161
+ };
162
+ },
163
+ // getBuildConfig
164
+ async () => {
165
+ return {
166
+ '/': {
167
+ entries: [['']],
168
+ },
169
+ };
170
+ },
171
+ );
172
+ ```
173
+
174
+ The `getBuildConfig` function is used for build-time
175
+ optimization. It renders React Server Components during the build
176
+ process to produce the output that will be sent to the client. Note
177
+ that rendering here means to produce RSC payload not HTML content.
178
+
179
+ #### How to try it
180
+
181
+ If you create a project with something like
182
+ `npm create waku@latest`, it will create the minimal
183
+ example app.
184
+
185
+ ### Router
186
+
187
+ Waku provides a router built on top of the minimal API, and it serves
188
+ as a reference implementation.
189
+
190
+ #### Client API
191
+
192
+ To use the router, it is required to use the `Router`
193
+ component instead of using `Root` and `Slot` directly.
194
+ The following code demonstrates how to use
195
+ the `Router` component as the root component:
196
+
197
+ ```tsx
198
+ import { createRoot } from 'react-dom/client';
199
+ import { Router } from 'waku/router/client';
200
+
201
+ const root = createRoot(document.getElementById('root')!);
202
+
203
+ root.render(<Router />);
204
+ ```
205
+
206
+ The `Router` component internally uses `Root` and `Slot`
207
+ and handles nested routes.
208
+
209
+ #### Server API
210
+
211
+ In `entries.ts`, we use `defineRouter` to export
212
+ `getEntry` and `getBuildConfig` at once.
213
+ Here's a simple example code without builder:
214
+
215
+ ```tsx
216
+ import { defineRouter } from 'waku/router/server';
217
+
218
+ export default defineRouter((id) => {
219
+ switch (id) {
220
+ case 'index/page':
221
+ return import('./routes/index.tsx');
222
+ case 'foo/page':
223
+ return import('./routes/foo.tsx');
224
+ default:
225
+ throw new Error('no such route');
226
+ }
227
+ });
228
+ ```
229
+
230
+ The implementation of the `defineRouter` is config-based.
231
+ However, it isn't too difficult to make a file-based router.
232
+ Here's a file-based example code with builder:
233
+
234
+ ```tsx
235
+ import url from 'node:url';
236
+ import path from 'node:path';
237
+ import { glob } from 'glob';
238
+ import { defineRouter } from 'waku/router/server';
239
+
240
+ const routesDir = path.join(
241
+ path.dirname(url.fileURLToPath(import.meta.url)),
242
+ 'routes',
243
+ );
244
+
245
+ export default defineRouter(
246
+ // getComponent (id is '**/layout' or '**/page')
247
+ async (id) => {
248
+ const files = await glob(${'`'}$\{id}.{tsx,js}${'`'}, { cwd: routesDir });
249
+ if (files.length === 0) {
250
+ return null;
251
+ }
252
+ const items = id.split('/');
253
+ switch (items.length) {
254
+ case 1:
255
+ return import(${'`'}./routes/$\{items[0]}.tsx${'`'});
256
+ case 2:
257
+ return import(${'`'}./routes/$\{items[0]}/$\{items[1]}.tsx${'`'});
258
+ case 3:
259
+ return import(${'`'}./routes/$\{items[0]}/$\{items[1]}/$\{items[2]}.tsx${'`'});
260
+ default:
261
+ throw new Error('too deep route');
262
+ }
263
+ },
264
+ // getPathsForBuild
265
+ async () => {
266
+ const files = await glob('**/page.{tsx,js}', { cwd: routesDir });
267
+ return files.map(
268
+ (file) => '/' + file.slice(0, Math.max(0, file.lastIndexOf('/'))),
269
+ );
270
+ },
271
+ );
272
+ ```
273
+
274
+ Due to the limitation of bundler, we cannot automatically allow
275
+ infinite depth of routes.
276
+
277
+ #### How to try it
278
+
279
+ You can try an example app in the repository by cloning it and running
280
+ the following commands:
281
+
282
+ ```bash
283
+ git clone https://github.com/dai-shi/waku.git
284
+ cd waku
285
+ npm install
286
+ npm run examples:dev:07_router
287
+ ```
288
+
289
+ Alternatively, you could create a project with something like
290
+ `npm create waku@latest` and copy files from the example
291
+ folder in the repository.
292
+
293
+ ## Tweets
294
+
295
+ <https://github.com/dai-shi/waku/discussions/150>
296
+
297
+ ## Diagrams
298
+
299
+ <https://github.com/dai-shi/waku/discussions/151>