waku 0.19.1 → 0.19.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 +49 -6
- package/cli.js +4 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +23 -24
- package/dist/client.d.ts +1 -1
- package/dist/client.js +2 -2
- package/dist/config.d.ts +5 -0
- package/dist/lib/builder/build.d.ts +1 -1
- package/dist/lib/builder/build.js +172 -84
- package/dist/lib/builder/output-aws-lambda.d.ts +2 -0
- package/dist/lib/builder/output-aws-lambda.js +7 -0
- package/dist/lib/builder/output-cloudflare.js +3 -2
- package/dist/lib/builder/output-netlify.d.ts +2 -0
- package/dist/lib/builder/output-netlify.js +17 -0
- package/dist/lib/builder/output-vercel.d.ts +1 -1
- package/dist/lib/builder/output-vercel.js +6 -19
- package/dist/lib/builder/serve-aws-lambda.d.ts +1 -0
- package/dist/lib/builder/serve-aws-lambda.js +19 -0
- package/dist/lib/builder/serve-cloudflare.d.ts +1 -1
- package/dist/lib/builder/serve-cloudflare.js +6 -2
- package/dist/lib/builder/serve-deno.js +3 -3
- package/dist/lib/builder/serve-netlify.d.ts +3 -0
- package/dist/lib/builder/serve-netlify.js +14 -0
- package/dist/lib/builder/serve-vercel.js +11 -25
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.js +1 -0
- package/dist/lib/handlers/dev-worker-api.d.ts +4 -11
- package/dist/lib/handlers/dev-worker-api.js +3 -23
- package/dist/lib/handlers/dev-worker-impl.js +17 -24
- package/dist/lib/handlers/handler-dev.js +12 -13
- package/dist/lib/handlers/handler-prd.js +51 -52
- package/dist/lib/plugins/vite-plugin-rsc-delegate.d.ts +2 -2
- package/dist/lib/plugins/vite-plugin-rsc-delegate.js +58 -14
- package/dist/lib/plugins/vite-plugin-rsc-hmr.d.ts +19 -7
- package/dist/lib/plugins/vite-plugin-rsc-hmr.js +118 -51
- package/dist/lib/plugins/vite-plugin-rsc-serve.d.ts +1 -0
- package/dist/lib/plugins/vite-plugin-rsc-serve.js +10 -0
- package/dist/lib/plugins/vite-plugin-rsc-transform.d.ts +2 -0
- package/dist/lib/plugins/vite-plugin-rsc-transform.js +3 -0
- package/dist/lib/renderers/html-renderer.d.ts +0 -1
- package/dist/lib/renderers/html-renderer.js +1 -1
- package/dist/lib/renderers/rsc-renderer.d.ts +4 -2
- package/dist/lib/renderers/rsc-renderer.js +11 -14
- package/dist/lib/renderers/utils.d.ts +2 -0
- package/dist/lib/renderers/utils.js +11 -0
- package/dist/lib/utils/node-fs.d.ts +2 -0
- package/dist/lib/utils/node-fs.js +2 -0
- package/dist/lib/utils/path.d.ts +13 -0
- package/dist/lib/utils/path.js +66 -0
- package/dist/router/client.d.ts +1 -1
- package/dist/router/client.js +21 -5
- package/dist/router/server.d.ts +6 -2
- package/dist/router/server.js +79 -138
- package/dist/server.d.ts +4 -4
- package/package.json +21 -13
- package/src/cli.ts +23 -24
- package/src/client.ts +3 -3
- package/src/config.ts +5 -0
- package/src/lib/builder/build.ts +214 -97
- package/src/lib/builder/output-aws-lambda.ts +10 -0
- package/src/lib/builder/output-cloudflare.ts +3 -2
- package/src/lib/builder/output-netlify.ts +27 -0
- package/src/lib/builder/output-vercel.ts +6 -24
- package/src/lib/builder/serve-aws-lambda.ts +18 -0
- package/src/lib/builder/serve-cloudflare.ts +4 -1
- package/src/lib/builder/serve-deno.ts +1 -1
- package/src/lib/builder/serve-netlify.ts +14 -0
- package/src/lib/builder/serve-vercel.ts +8 -26
- package/src/lib/config.ts +1 -0
- package/src/lib/handlers/dev-worker-api.ts +6 -32
- package/src/lib/handlers/dev-worker-impl.ts +27 -20
- package/src/lib/handlers/handler-dev.ts +12 -15
- package/src/lib/handlers/handler-prd.ts +56 -55
- package/src/lib/middleware/hono-utils.ts +1 -1
- package/src/lib/plugins/vite-plugin-rsc-delegate.ts +54 -15
- package/src/lib/plugins/vite-plugin-rsc-hmr.ts +145 -57
- package/src/lib/plugins/vite-plugin-rsc-serve.ts +17 -0
- package/src/lib/plugins/vite-plugin-rsc-transform.ts +5 -0
- package/src/lib/renderers/html-renderer.ts +2 -2
- package/src/lib/renderers/rsc-renderer.ts +24 -28
- package/src/lib/renderers/utils.ts +13 -0
- package/src/lib/utils/node-fs.ts +6 -0
- package/src/lib/utils/path.ts +81 -0
- package/src/router/client.ts +29 -4
- package/src/router/server.ts +77 -146
- package/src/server.ts +5 -4
- package/dist/lib/plugins/vite-plugin-rsc-reload.d.ts +0 -2
- package/dist/lib/plugins/vite-plugin-rsc-reload.js +0 -43
- package/src/lib/plugins/vite-plugin-rsc-reload.ts +0 -51
package/README.md
CHANGED
|
@@ -27,17 +27,21 @@ Start a new Waku project with the `create` command for your preferred package ma
|
|
|
27
27
|
npm create waku@latest
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
**Node.js version requirement:** `^20.8.0 || ^18.16.0`
|
|
31
|
+
|
|
30
32
|
## Rendering
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
While there's a bit of a learning curve to modern React rendering, it introduces powerful new patterns of full-stack composability that are only possible with the advent of [server components](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md).
|
|
35
|
+
|
|
36
|
+
So please don't be intimidated by the `'use client'` directive! Once you get the hang of it, you'll appreciate how awesome it is to flexibly move server-client boundaries with a single line of code as your full-stack React codebase evolves over time. It's way simpler than maintaining separate codebases for your backend and frontend.
|
|
33
37
|
|
|
34
|
-
|
|
38
|
+
And please don't fret about client components! Even if you only lightly optimize towards server components, your client bundle size will be smaller than traditional React frameworks, which are always 100% client components.
|
|
35
39
|
|
|
36
|
-
Future versions of Waku may provide additional APIs to abstract
|
|
40
|
+
> Future versions of Waku may provide additional opt-in APIs to abstract some of the complexity away for an improved developer experience.
|
|
37
41
|
|
|
38
42
|
#### Server components
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
Server components can be made async and can securely perform server-side logic and data fetching. Feel free to access the local file-system and import heavy dependencies since they aren't included in the client bundle. They have no state, interactivity, or access to browser APIs since they run exclusively on the server.
|
|
41
45
|
|
|
42
46
|
```tsx
|
|
43
47
|
// server component
|
|
@@ -115,7 +119,17 @@ export const Providers = ({ children }) => {
|
|
|
115
119
|
|
|
116
120
|
#### Server-side rendering
|
|
117
121
|
|
|
118
|
-
Waku provides static prerendering (SSG) or server-side rendering (SSR) options for layouts and pages including
|
|
122
|
+
SSR is a distinct concept from RSC. Waku provides static prerendering (SSG) or server-side rendering (SSR) options for both layouts and pages including all of their server _and_ client components.
|
|
123
|
+
|
|
124
|
+
#### tl;dr:
|
|
125
|
+
|
|
126
|
+
Each layout and page in Waku is composed of a React component heirarchy.
|
|
127
|
+
|
|
128
|
+
It begins with a server component at the top of the tree. Then at points down the heirarchy, you'll eventually import a component that needs client component APIs. Mark this file with a `'use client'` directive at the top. When imported into a server component, it will create a server-client boundary. Below this point in the component heirarchy, all imported components are hydrated and will run in the browser as well.
|
|
129
|
+
|
|
130
|
+
Server components can still be rendered below this boundary, but only via composition (e.g., `children` props). They form [a new layer](https://github.com/reactwg/server-components/discussions/4) that run _before_ any client code.
|
|
131
|
+
|
|
132
|
+
Client components are still server-side rendered. SSR is seperate from RSC. See the [linked diagrams](https://github.com/reactwg/server-components/discussions/4) for a helpful visual.
|
|
119
133
|
|
|
120
134
|
#### Further reading
|
|
121
135
|
|
|
@@ -362,7 +376,7 @@ export const Providers = ({ children }) => {
|
|
|
362
376
|
|
|
363
377
|
#### Other layouts
|
|
364
378
|
|
|
365
|
-
Layouts are also helpful further down the tree. For example, you could add a layout at `path: '/blog` to add a sidebar to both the blog index and all blog article pages.
|
|
379
|
+
Layouts are also helpful further down the tree. For example, you could add a layout at `path: '/blog'` to add a sidebar to both the blog index and all blog article pages.
|
|
366
380
|
|
|
367
381
|
```tsx
|
|
368
382
|
// ./src/entries.tsx
|
|
@@ -635,6 +649,27 @@ Adding the `--with-vercel-static` flag to the build script will produce static s
|
|
|
635
649
|
}
|
|
636
650
|
```
|
|
637
651
|
|
|
652
|
+
### Netlify
|
|
653
|
+
|
|
654
|
+
Waku projects can be deployed to Netlify with the [Netlify CLI](https://docs.netlify.com/cli/get-started/).
|
|
655
|
+
|
|
656
|
+
```
|
|
657
|
+
npm run build -- --with-netlify
|
|
658
|
+
netlify deploy --dir=dist/public
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
#### Pure SSG
|
|
662
|
+
|
|
663
|
+
Adding the `--with-netlify-static` flag to the build script will produce static sites without Netlify functions.
|
|
664
|
+
|
|
665
|
+
```
|
|
666
|
+
{
|
|
667
|
+
"scripts": {
|
|
668
|
+
"build": "waku build --with-ssr --with-netlify-static"
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
```
|
|
672
|
+
|
|
638
673
|
### Cloudflare (experimental)
|
|
639
674
|
|
|
640
675
|
```
|
|
@@ -649,6 +684,14 @@ npm run build -- --with-deno
|
|
|
649
684
|
DENO_DEPLOY_TOKEN=... deployctl deploy --project=... --prod dist/serve.js --exclude node_modules
|
|
650
685
|
```
|
|
651
686
|
|
|
687
|
+
### AWS Lambda (experimental)
|
|
688
|
+
|
|
689
|
+
```
|
|
690
|
+
npm run build -- --with-aws-lambda
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
The handler entrypoint is `dist/serve.js` - see [Hono AWS Lambda Deploy Docs](https://hono.dev/getting-started/aws-lambda#_3-deploy)
|
|
694
|
+
|
|
652
695
|
## Community
|
|
653
696
|
|
|
654
697
|
Please join our friendly [GitHub discussions](https://github.com/dai-shi/waku/discussions) or [Discord server](https://discord.gg/MrQdmzd) to participate in the Waku community. Hope to see you there!
|
package/cli.js
ADDED
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
import path from 'node:path';
|
|
3
|
-
import { existsSync,
|
|
2
|
+
import { existsSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
4
3
|
import { pathToFileURL } from 'node:url';
|
|
5
4
|
import { parseArgs } from 'node:util';
|
|
6
5
|
import { createRequire } from 'node:module';
|
|
@@ -9,11 +8,18 @@ import { Hono } from 'hono';
|
|
|
9
8
|
import { serve } from '@hono/node-server';
|
|
10
9
|
import { serveStatic } from '@hono/node-server/serve-static';
|
|
11
10
|
import * as swc from '@swc/core';
|
|
11
|
+
import * as dotenv from 'dotenv';
|
|
12
12
|
import { resolveConfig } from './lib/config.js';
|
|
13
13
|
import { honoMiddleware as honoDevMiddleware } from './lib/middleware/hono-dev.js';
|
|
14
14
|
import { honoMiddleware as honoPrdMiddleware } from './lib/middleware/hono-prd.js';
|
|
15
15
|
import { build } from './lib/builder/build.js';
|
|
16
16
|
const require = createRequire(new URL('.', import.meta.url));
|
|
17
|
+
dotenv.config({
|
|
18
|
+
path: [
|
|
19
|
+
'.env.local',
|
|
20
|
+
'.env'
|
|
21
|
+
]
|
|
22
|
+
});
|
|
17
23
|
const { values, positionals } = parseArgs({
|
|
18
24
|
args: process.argv.slice(2),
|
|
19
25
|
allowPositionals: true,
|
|
@@ -33,6 +39,15 @@ const { values, positionals } = parseArgs({
|
|
|
33
39
|
'with-deno': {
|
|
34
40
|
type: 'boolean'
|
|
35
41
|
},
|
|
42
|
+
'with-netlify': {
|
|
43
|
+
type: 'boolean'
|
|
44
|
+
},
|
|
45
|
+
'with-netlify-static': {
|
|
46
|
+
type: 'boolean'
|
|
47
|
+
},
|
|
48
|
+
'with-aws-lambda': {
|
|
49
|
+
type: 'boolean'
|
|
50
|
+
},
|
|
36
51
|
version: {
|
|
37
52
|
type: 'boolean',
|
|
38
53
|
short: 'v'
|
|
@@ -43,7 +58,6 @@ const { values, positionals } = parseArgs({
|
|
|
43
58
|
}
|
|
44
59
|
}
|
|
45
60
|
});
|
|
46
|
-
loadEnv();
|
|
47
61
|
const config = await loadConfig();
|
|
48
62
|
const cmd = positionals[0];
|
|
49
63
|
if (values.version) {
|
|
@@ -92,22 +106,22 @@ async function runBuild(options) {
|
|
|
92
106
|
...options,
|
|
93
107
|
config,
|
|
94
108
|
env: process.env,
|
|
95
|
-
deploy: (values['with-vercel'] ?? !!process.env.VERCEL ? values['with-vercel-static'] ? 'vercel-static' : 'vercel-serverless' : undefined) || (values['with-cloudflare'] ? 'cloudflare' : undefined) || (values['with-deno'] ? 'deno' : undefined)
|
|
109
|
+
deploy: (values['with-vercel'] ?? !!process.env.VERCEL ? values['with-vercel-static'] ? 'vercel-static' : 'vercel-serverless' : undefined) || (values['with-cloudflare'] ? 'cloudflare' : undefined) || (values['with-deno'] ? 'deno' : undefined) || (values['with-netlify'] ?? !!process.env.NETLIFY ? values['with-netlify-static'] ? 'netlify-static' : 'netlify-functions' : undefined) || (values['with-aws-lambda'] ? 'aws-lambda' : undefined)
|
|
96
110
|
});
|
|
97
111
|
}
|
|
98
112
|
async function runStart(options) {
|
|
99
113
|
const { distDir, publicDir, entriesJs } = await resolveConfig(config);
|
|
100
114
|
const loadEntries = ()=>import(pathToFileURL(path.resolve(distDir, entriesJs)).toString());
|
|
101
115
|
const app = new Hono();
|
|
116
|
+
app.use('*', serveStatic({
|
|
117
|
+
root: path.join(distDir, publicDir)
|
|
118
|
+
}));
|
|
102
119
|
app.use('*', honoPrdMiddleware({
|
|
103
120
|
...options,
|
|
104
121
|
config,
|
|
105
122
|
loadEntries,
|
|
106
123
|
env: process.env
|
|
107
124
|
}));
|
|
108
|
-
app.use('*', serveStatic({
|
|
109
|
-
root: path.join(distDir, publicDir)
|
|
110
|
-
}));
|
|
111
125
|
const port = parseInt(process.env.PORT || '8080', 10);
|
|
112
126
|
startServer(app, port);
|
|
113
127
|
}
|
|
@@ -141,27 +155,12 @@ Options:
|
|
|
141
155
|
--with-vercel Output for Vercel on build
|
|
142
156
|
--with-cloudflare Output for Cloudflare on build
|
|
143
157
|
--with-deno Output for Deno on build
|
|
158
|
+
--with-netlify Output for Netlify on build
|
|
159
|
+
--with-aws-lambda Output for AWS Lambda on build
|
|
144
160
|
-v, --version Display the version number
|
|
145
161
|
-h, --help Display this help message
|
|
146
162
|
`);
|
|
147
163
|
}
|
|
148
|
-
// TODO consider using a library such as `dotenv`
|
|
149
|
-
function loadEnv() {
|
|
150
|
-
if (existsSync('.env.local')) {
|
|
151
|
-
for (const line of readFileSync('.env.local', 'utf8').split('\n')){
|
|
152
|
-
const [key, value] = line.split('=');
|
|
153
|
-
if (key && value) {
|
|
154
|
-
if (value.startsWith('"') && value.endsWith('"')) {
|
|
155
|
-
process.env[key.trim()] = value.slice(1, -1);
|
|
156
|
-
} else if (value.startsWith("'") && value.endsWith("'")) {
|
|
157
|
-
process.env[key.trim()] = value.slice(1, -1);
|
|
158
|
-
} else {
|
|
159
|
-
process.env[key.trim()] = value.trim();
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
164
|
// TODO is this a good idea?
|
|
166
165
|
async function loadConfig() {
|
|
167
166
|
if (!existsSync('waku.config.ts')) {
|
package/dist/client.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ declare global {
|
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
7
|
type Elements = Promise<Record<string, ReactNode>>;
|
|
8
|
-
type SetElements = (
|
|
8
|
+
type SetElements = (updater: Elements | ((prev: Elements) => Elements)) => void;
|
|
9
9
|
type CacheEntry = [
|
|
10
10
|
input: string,
|
|
11
11
|
searchParamsString: string,
|
package/dist/client.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
'use client';
|
|
3
3
|
import { createContext, createElement, memo, use, useCallback, useState, startTransition } from 'react';
|
|
4
4
|
import RSDWClient from 'react-server-dom-webpack/client';
|
|
5
|
-
import { encodeInput } from './lib/renderers/utils.js';
|
|
5
|
+
import { encodeInput, encodeActionId } from './lib/renderers/utils.js';
|
|
6
6
|
const { createFromFetch, encodeReply } = RSDWClient;
|
|
7
7
|
const BASE_PATH = `${import.meta.env?.WAKU_CONFIG_BASE_PATH}${import.meta.env?.WAKU_CONFIG_RSC_PATH}/`;
|
|
8
8
|
const checkStatus = async (responsePromise)=>{
|
|
@@ -37,7 +37,7 @@ export const fetchRSC = (input, searchParamsString, setElements, cache = fetchCa
|
|
|
37
37
|
}
|
|
38
38
|
const options = {
|
|
39
39
|
async callServer (actionId, args) {
|
|
40
|
-
const response = fetch(BASE_PATH + encodeInput(
|
|
40
|
+
const response = fetch(BASE_PATH + encodeInput(encodeActionId(actionId)), {
|
|
41
41
|
method: 'POST',
|
|
42
42
|
body: await encodeReply(args)
|
|
43
43
|
});
|
package/dist/config.d.ts
CHANGED
|
@@ -27,6 +27,11 @@ export interface Config {
|
|
|
27
27
|
* Defaults to "assets".
|
|
28
28
|
*/
|
|
29
29
|
assetsDir?: string;
|
|
30
|
+
/**
|
|
31
|
+
* The SSR directory relative to distDir.
|
|
32
|
+
* Defaults to "ssr".
|
|
33
|
+
*/
|
|
34
|
+
ssrDir?: string;
|
|
30
35
|
/**
|
|
31
36
|
* The index.html file for any directories.
|
|
32
37
|
* Defaults to "index.html".
|
|
@@ -3,5 +3,5 @@ export declare function build(options: {
|
|
|
3
3
|
config?: Config;
|
|
4
4
|
ssr?: boolean;
|
|
5
5
|
env?: Record<string, string>;
|
|
6
|
-
deploy?: 'vercel-static' | 'vercel-serverless' | 'cloudflare' | 'deno' | undefined;
|
|
6
|
+
deploy?: 'vercel-static' | 'vercel-serverless' | 'cloudflare' | 'deno' | 'netlify-static' | 'netlify-functions' | 'aws-lambda' | undefined;
|
|
7
7
|
}): Promise<void>;
|