waku 0.19.0 → 0.19.2
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 +113 -18
- package/cli.js +4 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +17 -11
- package/dist/client.d.ts +11 -2
- package/dist/client.js +36 -34
- package/dist/config.d.ts +6 -0
- package/dist/dev.d.ts +2 -2
- package/dist/dev.js +2 -2
- package/dist/lib/builder/build.d.ts +1 -5
- package/dist/lib/builder/build.js +83 -74
- 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.d.ts +1 -1
- package/dist/lib/builder/output-cloudflare.js +6 -31
- package/dist/lib/builder/output-netlify.d.ts +2 -0
- package/dist/lib/builder/output-netlify.js +27 -0
- package/dist/lib/builder/output-vercel.d.ts +1 -1
- package/dist/lib/builder/output-vercel.js +8 -52
- 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 +6 -0
- package/dist/lib/builder/serve-cloudflare.js +23 -0
- package/dist/lib/builder/serve-deno.d.ts +1 -0
- package/dist/lib/builder/serve-deno.js +22 -0
- 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.d.ts +3 -0
- package/dist/lib/builder/serve-vercel.js +16 -0
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.js +1 -0
- package/dist/lib/handlers/dev-worker-api.d.ts +1 -1
- package/dist/lib/handlers/dev-worker-api.js +2 -2
- package/dist/lib/handlers/dev-worker-impl.js +17 -14
- package/dist/lib/handlers/handler-dev.js +8 -2
- package/dist/lib/handlers/handler-prd.d.ts +1 -1
- package/dist/lib/handlers/handler-prd.js +55 -53
- package/dist/lib/handlers/types.d.ts +0 -4
- package/dist/lib/plugins/vite-plugin-rsc-delegate.d.ts +2 -2
- package/dist/lib/plugins/vite-plugin-rsc-delegate.js +15 -8
- package/dist/lib/plugins/vite-plugin-rsc-hmr.d.ts +6 -2
- package/dist/lib/plugins/vite-plugin-rsc-hmr.js +66 -17
- package/dist/lib/plugins/vite-plugin-rsc-serve.d.ts +10 -0
- package/dist/lib/plugins/vite-plugin-rsc-serve.js +19 -0
- package/dist/lib/renderers/rsc-renderer.d.ts +2 -1
- package/dist/lib/renderers/rsc-renderer.js +1 -2
- package/dist/lib/utils/node-fs.d.ts +1 -0
- package/dist/lib/utils/node-fs.js +1 -0
- package/dist/lib/utils/path.d.ts +13 -0
- package/dist/lib/utils/path.js +66 -0
- package/dist/prd.d.ts +2 -2
- package/dist/prd.js +2 -2
- package/dist/router/client.d.ts +1 -0
- 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 -14
- package/src/cli.ts +34 -15
- package/src/client.ts +93 -79
- package/src/config.ts +6 -0
- package/src/dev.ts +2 -2
- package/src/lib/builder/build.ts +123 -87
- package/src/lib/builder/output-aws-lambda.ts +10 -0
- package/src/lib/builder/output-cloudflare.ts +5 -42
- package/src/lib/builder/output-netlify.ts +43 -0
- package/src/lib/builder/output-vercel.ts +8 -64
- package/src/lib/builder/serve-aws-lambda.ts +18 -0
- package/src/lib/builder/serve-cloudflare.ts +24 -0
- package/src/lib/builder/serve-deno.ts +22 -0
- package/src/lib/builder/serve-netlify.ts +14 -0
- package/src/lib/builder/serve-vercel.ts +17 -0
- package/src/lib/config.ts +1 -0
- package/src/lib/handlers/dev-worker-api.ts +3 -3
- package/src/lib/handlers/dev-worker-impl.ts +24 -12
- package/src/lib/handlers/handler-dev.ts +8 -2
- package/src/lib/handlers/handler-prd.ts +62 -57
- package/src/lib/handlers/types.ts +0 -6
- package/src/lib/plugins/vite-plugin-rsc-delegate.ts +15 -5
- package/src/lib/plugins/vite-plugin-rsc-hmr.ts +73 -14
- package/src/lib/plugins/vite-plugin-rsc-serve.ts +33 -0
- package/src/lib/renderers/rsc-renderer.ts +4 -7
- package/src/lib/utils/node-fs.ts +3 -0
- package/src/lib/utils/path.ts +81 -0
- package/src/prd.ts +2 -2
- package/src/router/client.ts +29 -4
- package/src/router/server.ts +83 -151
- package/src/server.ts +5 -4
- package/dist/lib/builder/output-deno.d.ts +0 -2
- package/dist/lib/builder/output-deno.js +0 -25
- package/dist/lib/plugins/vite-plugin-rsc-entries.d.ts +0 -6
- package/dist/lib/plugins/vite-plugin-rsc-entries.js +0 -22
- package/src/lib/builder/output-deno.ts +0 -43
- package/src/lib/plugins/vite-plugin-rsc-entries.ts +0 -28
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ visit [waku.gg](https://waku.gg) or `npm create waku@latest`
|
|
|
15
15
|
|
|
16
16
|
**Waku** _(wah-ku)_ or **わく** means “framework” in Japanese. As the minimal React framework, it aims to accelerate the work of developers at startups and agencies building small to medium-sized React projects. These include marketing websites, light ecommerce, and web applications.
|
|
17
17
|
|
|
18
|
-
We recommend other frameworks for heavy ecommerce or enterprise applications. Waku is a lightweight alternative designed to bring a fun developer experience to the modern React server components era. Yes, let’s make React development fun
|
|
18
|
+
We recommend other frameworks for heavy ecommerce or enterprise applications. Waku is a lightweight alternative designed to bring a fun developer experience to the modern React server components era. Yes, let’s make React development fun!
|
|
19
19
|
|
|
20
20
|
> Waku is in rapid development and some features are currently missing. Please try it on non-production projects and report any issues you may encounter. Expect that there will be some breaking changes on the road towards a stable v1 release. Contributors are welcome.
|
|
21
21
|
|
|
@@ -27,17 +27,29 @@ 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 composability that are only possible with the advent of React [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.
|
|
37
|
+
|
|
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 100% client components.
|
|
39
|
+
|
|
40
|
+
> Future versions of Waku may provide additional opt-in APIs to abstract some of the complexity away for an improved developer experience.
|
|
41
|
+
|
|
42
|
+
#### Overview
|
|
33
43
|
|
|
34
|
-
|
|
44
|
+
Each layout and page in Waku is composed of a React component heirarchy.
|
|
35
45
|
|
|
36
|
-
|
|
46
|
+
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 all imported components are hydrated and will run in the browser as well.
|
|
47
|
+
|
|
48
|
+
Server components can still be rendered below this boundary, but only via composition (e.g., `children` props).
|
|
37
49
|
|
|
38
50
|
#### Server components
|
|
39
51
|
|
|
40
|
-
|
|
52
|
+
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
53
|
|
|
42
54
|
```tsx
|
|
43
55
|
// server component
|
|
@@ -54,7 +66,7 @@ export const StorePage = async () => {
|
|
|
54
66
|
|
|
55
67
|
#### Client components
|
|
56
68
|
|
|
57
|
-
|
|
69
|
+
A `'use client'` directive placed at the top of a file will create a server-client boundary when the module is imported into a server component. All components imported below the boundary will be hydrated to run in the browser as well. They can use all traditional React features such as state, effects, and event handlers.
|
|
58
70
|
|
|
59
71
|
```tsx
|
|
60
72
|
// client component
|
|
@@ -74,13 +86,48 @@ export const Counter = () => {
|
|
|
74
86
|
};
|
|
75
87
|
```
|
|
76
88
|
|
|
89
|
+
#### Shared components
|
|
90
|
+
|
|
91
|
+
Simple React components that [meet all of the rules](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md#sharing-code-between-server-and-client) of both server and client components can be imported into either server or client components without affecting the server-client boundary.
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
// shared component
|
|
95
|
+
export const Headline = ({ children }) => {
|
|
96
|
+
return <h3>{children}</h3>;
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
77
100
|
#### Weaving patterns
|
|
78
101
|
|
|
79
|
-
Server components can import client components and doing so will create a server-client boundary. Client components cannot import server components, but they can accept server components as props such as `children`.
|
|
102
|
+
Server components can import client components and doing so will create a server-client boundary. Client components cannot import server components, but they can accept server components as props such as `children`. For example, you may want to add global context providers this way.
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
// ./src/templates/root-layout.tsx
|
|
106
|
+
import { Providers } from '../components/providers.js';
|
|
107
|
+
|
|
108
|
+
export const RootLayout = async ({ children }) => {
|
|
109
|
+
return (
|
|
110
|
+
<Providers>
|
|
111
|
+
<main>{children}</main>
|
|
112
|
+
</Providers>
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
// ./src/components/providers.tsx
|
|
119
|
+
'use client';
|
|
120
|
+
|
|
121
|
+
import { Provider } from 'jotai';
|
|
122
|
+
|
|
123
|
+
export const Providers = ({ children }) => {
|
|
124
|
+
return <Provider>{children}</Provider>;
|
|
125
|
+
};
|
|
126
|
+
```
|
|
80
127
|
|
|
81
128
|
#### Server-side rendering
|
|
82
129
|
|
|
83
|
-
Waku provides static prerendering (SSG) or server-side rendering (SSR) options for layouts and pages including their server
|
|
130
|
+
Waku provides static prerendering (SSG) or server-side rendering (SSR) options for layouts and pages including both their server and client components.
|
|
84
131
|
|
|
85
132
|
#### Further reading
|
|
86
133
|
|
|
@@ -90,7 +137,9 @@ To learn more about the modern React architecture, we recommend [Making Sense of
|
|
|
90
137
|
|
|
91
138
|
The entry point for routing in Waku projects is `./src/entries.tsx`. Export the `createPages` function to create your layouts and pages programatically.
|
|
92
139
|
|
|
93
|
-
Both `createLayout` and `createPage` accept a configuration object to specify the route path, React component, and render method
|
|
140
|
+
Both `createLayout` and `createPage` accept a configuration object to specify the route path, React component, and render method. Waku currently supports two options: `'static'` for static prerendering (SSG) or `'dynamic'` for server-side rendering (SSR).
|
|
141
|
+
|
|
142
|
+
For example, you can statically prerender a global header and footer in the root layout at build time, but dynamically render the rest of a home page at request time for personalized user experiences.
|
|
94
143
|
|
|
95
144
|
```tsx
|
|
96
145
|
// ./src/entries.tsx
|
|
@@ -244,7 +293,9 @@ export default createPages(async ({ createPage }) => {
|
|
|
244
293
|
|
|
245
294
|
#### Catch-all routes
|
|
246
295
|
|
|
247
|
-
Catch-all or "wildcard" routes (e.g., `/app/[...catchAll]`) have indefinite segments. Wildcard routes receive a prop with segment values as an ordered array.
|
|
296
|
+
Catch-all or "wildcard" routes (e.g., `/app/[...catchAll]`) have indefinite segments. Wildcard routes receive a prop with segment values as an ordered array.
|
|
297
|
+
|
|
298
|
+
For example, the `/app/profile/settings` route would receive a `catchAll` prop with the value `['profile', 'settings']`. These values can then be used to determine what to render in the component.
|
|
248
299
|
|
|
249
300
|
```tsx
|
|
250
301
|
// ./src/entries.tsx
|
|
@@ -323,7 +374,7 @@ export const Providers = ({ children }) => {
|
|
|
323
374
|
|
|
324
375
|
#### Other layouts
|
|
325
376
|
|
|
326
|
-
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.
|
|
377
|
+
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.
|
|
327
378
|
|
|
328
379
|
```tsx
|
|
329
380
|
// ./src/entries.tsx
|
|
@@ -347,10 +398,10 @@ import { Sidebar } from '../components/sidebar.js';
|
|
|
347
398
|
|
|
348
399
|
export const BlogLayout = async ({ children }) => {
|
|
349
400
|
return (
|
|
350
|
-
|
|
401
|
+
<div className="flex">
|
|
351
402
|
<div>{children}</div>
|
|
352
403
|
<Sidebar />
|
|
353
|
-
|
|
404
|
+
</div>
|
|
354
405
|
);
|
|
355
406
|
};
|
|
356
407
|
```
|
|
@@ -377,13 +428,13 @@ export const HomePage = async () => {
|
|
|
377
428
|
|
|
378
429
|
Static assets such as images, fonts, stylesheets, and scripts can be placed in a special `./public` folder of the Waku project root directory. The public directory structure is served relative to the `/` base path.
|
|
379
430
|
|
|
380
|
-
For example an image added to `./public/images/logo.svg` can be rendered via `<img src="/images/logo.svg" />`.
|
|
431
|
+
For example, an image added to `./public/images/logo.svg` can be rendered via `<img src="/images/logo.svg" />`.
|
|
381
432
|
|
|
382
433
|
## Data fetching
|
|
383
434
|
|
|
384
435
|
### Server
|
|
385
436
|
|
|
386
|
-
All of the wonderful patterns of React server components are supported. For example you can compile MDX files or perform code syntax highlighting on the server with zero impact on the client bundle size.
|
|
437
|
+
All of the wonderful patterns of React server components are supported. For example, you can compile MDX files or perform code syntax highlighting on the server with zero impact on the client bundle size.
|
|
387
438
|
|
|
388
439
|
```tsx
|
|
389
440
|
// ./src/templates/blog-article-page.tsx
|
|
@@ -395,8 +446,8 @@ export const BlogArticlePage = async ({ slug }) => {
|
|
|
395
446
|
|
|
396
447
|
return (
|
|
397
448
|
<>
|
|
398
|
-
<title>{article.frontmatter.title}</
|
|
399
|
-
<h1>{article.frontmatter.title}</
|
|
449
|
+
<title>{article.frontmatter.title}</title>
|
|
450
|
+
<h1>{article.frontmatter.title}</h1>
|
|
400
451
|
<MDX>{article.content}</MDX>
|
|
401
452
|
</>
|
|
402
453
|
);
|
|
@@ -444,6 +495,35 @@ export const HomePage = async () => {
|
|
|
444
495
|
};
|
|
445
496
|
```
|
|
446
497
|
|
|
498
|
+
Metadata could also be generated programatically.
|
|
499
|
+
|
|
500
|
+
```tsx
|
|
501
|
+
// ./src/templates/home-page.tsx
|
|
502
|
+
export const HomePage = async () => {
|
|
503
|
+
return (
|
|
504
|
+
<>
|
|
505
|
+
<Head />
|
|
506
|
+
<div>{/* ...*/}</div>
|
|
507
|
+
</>
|
|
508
|
+
);
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
const Head = async () => {
|
|
512
|
+
const metadata = await getMetadata();
|
|
513
|
+
|
|
514
|
+
return (
|
|
515
|
+
<>
|
|
516
|
+
<title>{metadata.title}</title>
|
|
517
|
+
<meta property="description" content={metadata.description} />
|
|
518
|
+
</>
|
|
519
|
+
);
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
const getMetadata = async () => {
|
|
523
|
+
/* ... */
|
|
524
|
+
};
|
|
525
|
+
```
|
|
526
|
+
|
|
447
527
|
## Styling
|
|
448
528
|
|
|
449
529
|
### Global styles
|
|
@@ -578,8 +658,23 @@ npx wrangler dev # or deploy
|
|
|
578
658
|
|
|
579
659
|
```
|
|
580
660
|
npm run build -- --with-deno
|
|
581
|
-
DENO_DEPLOY_TOKEN=... deployctl deploy --project=... --prod serve.
|
|
661
|
+
DENO_DEPLOY_TOKEN=... deployctl deploy --project=... --prod dist/serve.js --exclude node_modules
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
### Netlify Deploy (experimental)
|
|
665
|
+
|
|
666
|
+
```
|
|
667
|
+
npm run build -- --with-netlify
|
|
668
|
+
netlify deploy
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
### AWS Lambda (experimental)
|
|
672
|
+
|
|
582
673
|
```
|
|
674
|
+
npm run build -- --with-aws-lambda
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
The handler entrypoint is `dist/serve.js` - see [Hono AWS Lambda Deploy Docs](https://hono.dev/getting-started/aws-lambda#_3-deploy)
|
|
583
678
|
|
|
584
679
|
## Community
|
|
585
680
|
|
package/cli.js
ADDED
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
4
3
|
import { pathToFileURL } from 'node:url';
|
|
@@ -33,6 +32,15 @@ const { values, positionals } = parseArgs({
|
|
|
33
32
|
'with-deno': {
|
|
34
33
|
type: 'boolean'
|
|
35
34
|
},
|
|
35
|
+
'with-netlify': {
|
|
36
|
+
type: 'boolean'
|
|
37
|
+
},
|
|
38
|
+
'with-netlify-static': {
|
|
39
|
+
type: 'boolean'
|
|
40
|
+
},
|
|
41
|
+
'with-aws-lambda': {
|
|
42
|
+
type: 'boolean'
|
|
43
|
+
},
|
|
36
44
|
version: {
|
|
37
45
|
type: 'boolean',
|
|
38
46
|
short: 'v'
|
|
@@ -92,26 +100,22 @@ async function runBuild(options) {
|
|
|
92
100
|
...options,
|
|
93
101
|
config,
|
|
94
102
|
env: process.env,
|
|
95
|
-
|
|
96
|
-
type: values['with-vercel-static'] ? 'static' : 'serverless'
|
|
97
|
-
} : undefined,
|
|
98
|
-
cloudflare: !!values['with-cloudflare'],
|
|
99
|
-
deno: !!values['with-deno']
|
|
103
|
+
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'] ? values['with-netlify-static'] ? 'netlify-static' : 'netlify-functions' : undefined) || (values['with-aws-lambda'] ? 'aws-lambda' : undefined)
|
|
100
104
|
});
|
|
101
105
|
}
|
|
102
106
|
async function runStart(options) {
|
|
103
107
|
const { distDir, publicDir, entriesJs } = await resolveConfig(config);
|
|
104
|
-
const
|
|
108
|
+
const loadEntries = ()=>import(pathToFileURL(path.resolve(distDir, entriesJs)).toString());
|
|
105
109
|
const app = new Hono();
|
|
110
|
+
app.use('*', serveStatic({
|
|
111
|
+
root: path.join(distDir, publicDir)
|
|
112
|
+
}));
|
|
106
113
|
app.use('*', honoPrdMiddleware({
|
|
107
114
|
...options,
|
|
108
115
|
config,
|
|
109
|
-
|
|
116
|
+
loadEntries,
|
|
110
117
|
env: process.env
|
|
111
118
|
}));
|
|
112
|
-
app.use('*', serveStatic({
|
|
113
|
-
root: path.join(distDir, publicDir)
|
|
114
|
-
}));
|
|
115
119
|
const port = parseInt(process.env.PORT || '8080', 10);
|
|
116
120
|
startServer(app, port);
|
|
117
121
|
}
|
|
@@ -145,6 +149,8 @@ Options:
|
|
|
145
149
|
--with-vercel Output for Vercel on build
|
|
146
150
|
--with-cloudflare Output for Cloudflare on build
|
|
147
151
|
--with-deno Output for Deno on build
|
|
152
|
+
--with-netlify Output for Netlify on build
|
|
153
|
+
--with-aws-lambda Output for AWS Lambda on build
|
|
148
154
|
-v, --version Display the version number
|
|
149
155
|
-h, --help Display this help message
|
|
150
156
|
`);
|
package/dist/client.d.ts
CHANGED
|
@@ -5,11 +5,20 @@ declare global {
|
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
7
|
type Elements = Promise<Record<string, ReactNode>>;
|
|
8
|
-
|
|
8
|
+
type SetElements = (fn: (prev: Elements) => Elements) => void;
|
|
9
|
+
type CacheEntry = [
|
|
10
|
+
input: string,
|
|
11
|
+
searchParamsString: string,
|
|
12
|
+
setElements: SetElements,
|
|
13
|
+
elements: Elements
|
|
14
|
+
];
|
|
15
|
+
declare const fetchCache: [CacheEntry?];
|
|
16
|
+
export declare const fetchRSC: (input: string, searchParamsString: string, setElements: SetElements, cache?: [CacheEntry?]) => Elements;
|
|
9
17
|
export declare const prefetchRSC: (input: string, searchParamsString: string) => void;
|
|
10
|
-
export declare const Root: ({ initialInput, initialSearchParamsString, children, }: {
|
|
18
|
+
export declare const Root: ({ initialInput, initialSearchParamsString, cache, children, }: {
|
|
11
19
|
initialInput?: string;
|
|
12
20
|
initialSearchParamsString?: string;
|
|
21
|
+
cache?: typeof fetchCache;
|
|
13
22
|
children: ReactNode;
|
|
14
23
|
}) => import("react").FunctionComponentElement<import("react").ProviderProps<(input: string, searchParams?: URLSearchParams) => void>>;
|
|
15
24
|
export declare const useRefetch: () => (input: string, searchParams?: URLSearchParams) => void;
|
package/dist/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="react/canary" />
|
|
2
2
|
'use client';
|
|
3
|
-
import {
|
|
3
|
+
import { createContext, createElement, memo, use, useCallback, useState, startTransition } from 'react';
|
|
4
4
|
import RSDWClient from 'react-server-dom-webpack/client';
|
|
5
5
|
import { encodeInput } from './lib/renderers/utils.js';
|
|
6
6
|
const { createFromFetch, encodeReply } = RSDWClient;
|
|
@@ -14,15 +14,27 @@ const checkStatus = async (responsePromise)=>{
|
|
|
14
14
|
}
|
|
15
15
|
return response;
|
|
16
16
|
};
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
const getCached = (c, m, k)=>(m.has(k) ? m : m.set(k, c())).get(k);
|
|
18
|
+
const cache1 = new WeakMap();
|
|
19
|
+
const mergeElements = (a, b)=>{
|
|
20
|
+
const getResult = async ()=>{
|
|
21
|
+
const nextElements = {
|
|
22
|
+
...await a,
|
|
23
|
+
...await b
|
|
24
|
+
};
|
|
25
|
+
delete nextElements._value;
|
|
26
|
+
return nextElements;
|
|
21
27
|
};
|
|
22
|
-
|
|
23
|
-
return
|
|
24
|
-
}
|
|
25
|
-
|
|
28
|
+
const cache2 = getCached(()=>new WeakMap(), cache1, a);
|
|
29
|
+
return getCached(getResult, cache2, b);
|
|
30
|
+
};
|
|
31
|
+
const fetchCache = [];
|
|
32
|
+
export const fetchRSC = (input, searchParamsString, setElements, cache = fetchCache)=>{
|
|
33
|
+
let entry = cache[0];
|
|
34
|
+
if (entry && entry[0] === input && entry[1] === searchParamsString) {
|
|
35
|
+
entry[2] = setElements;
|
|
36
|
+
return entry[3];
|
|
37
|
+
}
|
|
26
38
|
const options = {
|
|
27
39
|
async callServer (actionId, args) {
|
|
28
40
|
const response = fetch(BASE_PATH + encodeInput(encodeURIComponent(actionId)), {
|
|
@@ -30,9 +42,10 @@ export const fetchRSC = cache((input, searchParamsString, rerender)=>{
|
|
|
30
42
|
body: await encodeReply(args)
|
|
31
43
|
});
|
|
32
44
|
const data = createFromFetch(checkStatus(response), options);
|
|
45
|
+
const setElements = entry[2];
|
|
33
46
|
startTransition(()=>{
|
|
34
47
|
// FIXME this causes rerenders even if data is empty
|
|
35
|
-
|
|
48
|
+
setElements((prev)=>mergeElements(prev, data));
|
|
36
49
|
});
|
|
37
50
|
return (await data)._value;
|
|
38
51
|
}
|
|
@@ -42,43 +55,32 @@ export const fetchRSC = cache((input, searchParamsString, rerender)=>{
|
|
|
42
55
|
const response = prefetched[url] || fetch(url);
|
|
43
56
|
delete prefetched[url];
|
|
44
57
|
const data = createFromFetch(checkStatus(response), options);
|
|
58
|
+
cache[0] = entry = [
|
|
59
|
+
input,
|
|
60
|
+
searchParamsString,
|
|
61
|
+
setElements,
|
|
62
|
+
data
|
|
63
|
+
];
|
|
45
64
|
return data;
|
|
46
|
-
}
|
|
47
|
-
export const prefetchRSC =
|
|
65
|
+
};
|
|
66
|
+
export const prefetchRSC = (input, searchParamsString)=>{
|
|
48
67
|
const prefetched = globalThis.__WAKU_PREFETCHED__ ||= {};
|
|
49
68
|
const url = BASE_PATH + encodeInput(input) + (searchParamsString ? '?' + searchParamsString : '');
|
|
50
69
|
if (!(url in prefetched)) {
|
|
51
70
|
prefetched[url] = fetch(url);
|
|
52
71
|
}
|
|
53
|
-
}
|
|
72
|
+
};
|
|
54
73
|
const RefetchContext = createContext(()=>{
|
|
55
74
|
throw new Error('Missing Root component');
|
|
56
75
|
});
|
|
57
76
|
const ElementsContext = createContext(null);
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
let rerender;
|
|
61
|
-
const stableRerender = (fn)=>{
|
|
62
|
-
rerender?.(fn);
|
|
63
|
-
};
|
|
64
|
-
const getRerender = ()=>stableRerender;
|
|
65
|
-
const setRerender = (newRerender)=>{
|
|
66
|
-
rerender = newRerender;
|
|
67
|
-
};
|
|
68
|
-
return [
|
|
69
|
-
getRerender,
|
|
70
|
-
setRerender
|
|
71
|
-
];
|
|
72
|
-
});
|
|
73
|
-
export const Root = ({ initialInput, initialSearchParamsString, children })=>{
|
|
74
|
-
const [getRerender, setRerender] = createRerender();
|
|
75
|
-
const [elements, setElements] = useState(()=>fetchRSC(initialInput || '', initialSearchParamsString || '', getRerender()));
|
|
76
|
-
setRerender(setElements);
|
|
77
|
+
export const Root = ({ initialInput, initialSearchParamsString, cache, children })=>{
|
|
78
|
+
const [elements, setElements] = useState(()=>fetchRSC(initialInput || '', initialSearchParamsString || '', (fn)=>setElements(fn), cache));
|
|
77
79
|
const refetch = useCallback((input, searchParams)=>{
|
|
78
|
-
const data = fetchRSC(input, searchParams?.toString() || '',
|
|
80
|
+
const data = fetchRSC(input, searchParams?.toString() || '', setElements, cache);
|
|
79
81
|
setElements((prev)=>mergeElements(prev, data));
|
|
80
82
|
}, [
|
|
81
|
-
|
|
83
|
+
cache
|
|
82
84
|
]);
|
|
83
85
|
return createElement(RefetchContext.Provider, {
|
|
84
86
|
value: refetch
|
package/dist/config.d.ts
CHANGED
|
@@ -44,6 +44,12 @@ export interface Config {
|
|
|
44
44
|
* Defaults to "entries.js".
|
|
45
45
|
*/
|
|
46
46
|
entriesJs?: string;
|
|
47
|
+
/**
|
|
48
|
+
* The serve.js file relative distDir.
|
|
49
|
+
* This file is used for deployment.
|
|
50
|
+
* Defaults to "serve.js".
|
|
51
|
+
*/
|
|
52
|
+
serveJs?: string;
|
|
47
53
|
/**
|
|
48
54
|
* Prefix for HTTP requests to indicate RSC requests.
|
|
49
55
|
* Defaults to "RSC".
|
package/dist/dev.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { honoMiddleware } from './lib/middleware/hono-dev.js';
|
|
2
|
-
export { connectMiddleware } from './lib/middleware/connect-dev.js';
|
|
1
|
+
export { honoMiddleware as unstable_honoMiddleware } from './lib/middleware/hono-dev.js';
|
|
2
|
+
export { connectMiddleware as unstable_connectMiddleware } from './lib/middleware/connect-dev.js';
|
|
3
3
|
export { createHandler as unstable_createHandler } from './lib/handlers/handler-dev.js';
|
|
4
4
|
export { build } from './lib/builder/build.js';
|
package/dist/dev.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { honoMiddleware } from './lib/middleware/hono-dev.js';
|
|
2
|
-
export { connectMiddleware } from './lib/middleware/connect-dev.js';
|
|
1
|
+
export { honoMiddleware as unstable_honoMiddleware } from './lib/middleware/hono-dev.js';
|
|
2
|
+
export { connectMiddleware as unstable_connectMiddleware } from './lib/middleware/connect-dev.js';
|
|
3
3
|
export { createHandler as unstable_createHandler } from './lib/handlers/handler-dev.js';
|
|
4
4
|
export { build } from './lib/builder/build.js';
|
|
@@ -3,9 +3,5 @@ export declare function build(options: {
|
|
|
3
3
|
config?: Config;
|
|
4
4
|
ssr?: boolean;
|
|
5
5
|
env?: Record<string, string>;
|
|
6
|
-
|
|
7
|
-
type: 'static' | 'serverless';
|
|
8
|
-
} | undefined;
|
|
9
|
-
cloudflare?: boolean;
|
|
10
|
-
deno?: boolean;
|
|
6
|
+
deploy?: 'vercel-static' | 'vercel-serverless' | 'cloudflare' | 'deno' | 'netlify-static' | 'netlify-functions' | 'aws-lambda' | undefined;
|
|
11
7
|
}): Promise<void>;
|