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.
Files changed (94) hide show
  1. package/README.md +113 -18
  2. package/cli.js +4 -0
  3. package/dist/cli.d.ts +0 -1
  4. package/dist/cli.js +17 -11
  5. package/dist/client.d.ts +11 -2
  6. package/dist/client.js +36 -34
  7. package/dist/config.d.ts +6 -0
  8. package/dist/dev.d.ts +2 -2
  9. package/dist/dev.js +2 -2
  10. package/dist/lib/builder/build.d.ts +1 -5
  11. package/dist/lib/builder/build.js +83 -74
  12. package/dist/lib/builder/output-aws-lambda.d.ts +2 -0
  13. package/dist/lib/builder/output-aws-lambda.js +7 -0
  14. package/dist/lib/builder/output-cloudflare.d.ts +1 -1
  15. package/dist/lib/builder/output-cloudflare.js +6 -31
  16. package/dist/lib/builder/output-netlify.d.ts +2 -0
  17. package/dist/lib/builder/output-netlify.js +27 -0
  18. package/dist/lib/builder/output-vercel.d.ts +1 -1
  19. package/dist/lib/builder/output-vercel.js +8 -52
  20. package/dist/lib/builder/serve-aws-lambda.d.ts +1 -0
  21. package/dist/lib/builder/serve-aws-lambda.js +19 -0
  22. package/dist/lib/builder/serve-cloudflare.d.ts +6 -0
  23. package/dist/lib/builder/serve-cloudflare.js +23 -0
  24. package/dist/lib/builder/serve-deno.d.ts +1 -0
  25. package/dist/lib/builder/serve-deno.js +22 -0
  26. package/dist/lib/builder/serve-netlify.d.ts +3 -0
  27. package/dist/lib/builder/serve-netlify.js +14 -0
  28. package/dist/lib/builder/serve-vercel.d.ts +3 -0
  29. package/dist/lib/builder/serve-vercel.js +16 -0
  30. package/dist/lib/config.d.ts +1 -0
  31. package/dist/lib/config.js +1 -0
  32. package/dist/lib/handlers/dev-worker-api.d.ts +1 -1
  33. package/dist/lib/handlers/dev-worker-api.js +2 -2
  34. package/dist/lib/handlers/dev-worker-impl.js +17 -14
  35. package/dist/lib/handlers/handler-dev.js +8 -2
  36. package/dist/lib/handlers/handler-prd.d.ts +1 -1
  37. package/dist/lib/handlers/handler-prd.js +55 -53
  38. package/dist/lib/handlers/types.d.ts +0 -4
  39. package/dist/lib/plugins/vite-plugin-rsc-delegate.d.ts +2 -2
  40. package/dist/lib/plugins/vite-plugin-rsc-delegate.js +15 -8
  41. package/dist/lib/plugins/vite-plugin-rsc-hmr.d.ts +6 -2
  42. package/dist/lib/plugins/vite-plugin-rsc-hmr.js +66 -17
  43. package/dist/lib/plugins/vite-plugin-rsc-serve.d.ts +10 -0
  44. package/dist/lib/plugins/vite-plugin-rsc-serve.js +19 -0
  45. package/dist/lib/renderers/rsc-renderer.d.ts +2 -1
  46. package/dist/lib/renderers/rsc-renderer.js +1 -2
  47. package/dist/lib/utils/node-fs.d.ts +1 -0
  48. package/dist/lib/utils/node-fs.js +1 -0
  49. package/dist/lib/utils/path.d.ts +13 -0
  50. package/dist/lib/utils/path.js +66 -0
  51. package/dist/prd.d.ts +2 -2
  52. package/dist/prd.js +2 -2
  53. package/dist/router/client.d.ts +1 -0
  54. package/dist/router/client.js +21 -5
  55. package/dist/router/server.d.ts +6 -2
  56. package/dist/router/server.js +79 -138
  57. package/dist/server.d.ts +4 -4
  58. package/package.json +21 -14
  59. package/src/cli.ts +34 -15
  60. package/src/client.ts +93 -79
  61. package/src/config.ts +6 -0
  62. package/src/dev.ts +2 -2
  63. package/src/lib/builder/build.ts +123 -87
  64. package/src/lib/builder/output-aws-lambda.ts +10 -0
  65. package/src/lib/builder/output-cloudflare.ts +5 -42
  66. package/src/lib/builder/output-netlify.ts +43 -0
  67. package/src/lib/builder/output-vercel.ts +8 -64
  68. package/src/lib/builder/serve-aws-lambda.ts +18 -0
  69. package/src/lib/builder/serve-cloudflare.ts +24 -0
  70. package/src/lib/builder/serve-deno.ts +22 -0
  71. package/src/lib/builder/serve-netlify.ts +14 -0
  72. package/src/lib/builder/serve-vercel.ts +17 -0
  73. package/src/lib/config.ts +1 -0
  74. package/src/lib/handlers/dev-worker-api.ts +3 -3
  75. package/src/lib/handlers/dev-worker-impl.ts +24 -12
  76. package/src/lib/handlers/handler-dev.ts +8 -2
  77. package/src/lib/handlers/handler-prd.ts +62 -57
  78. package/src/lib/handlers/types.ts +0 -6
  79. package/src/lib/plugins/vite-plugin-rsc-delegate.ts +15 -5
  80. package/src/lib/plugins/vite-plugin-rsc-hmr.ts +73 -14
  81. package/src/lib/plugins/vite-plugin-rsc-serve.ts +33 -0
  82. package/src/lib/renderers/rsc-renderer.ts +4 -7
  83. package/src/lib/utils/node-fs.ts +3 -0
  84. package/src/lib/utils/path.ts +81 -0
  85. package/src/prd.ts +2 -2
  86. package/src/router/client.ts +29 -4
  87. package/src/router/server.ts +83 -151
  88. package/src/server.ts +5 -4
  89. package/dist/lib/builder/output-deno.d.ts +0 -2
  90. package/dist/lib/builder/output-deno.js +0 -25
  91. package/dist/lib/plugins/vite-plugin-rsc-entries.d.ts +0 -6
  92. package/dist/lib/plugins/vite-plugin-rsc-entries.js +0 -22
  93. package/src/lib/builder/output-deno.ts +0 -43
  94. 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 again!
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
- Let's face it: React is getting complicated. But not without good reason!
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
- While there's a bit of a learning curve to modern React rendering, it introduces powerful new patterns of composability that are only made possible with the advent of React server components. So stick with us.
44
+ Each layout and page in Waku is composed of a React component heirarchy.
35
45
 
36
- Future versions of Waku may provide additional APIs to abstract away some of the complexity for an improved developer experience.
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
- Waku follows React conventions including support for [server components](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md) and [server actions](https://react.dev/reference/react/use-server). Server components can be made async to securely perform server-side logic and data fetching, but have no interactivity.
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
- Client components are specified with the `'use client'` directive at the top of the file. They can use all traditional React features such as state, effects, and event handlers.
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 _and_ client components. Client components are then hydrated in the browser to support events, effects, and so on.
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 (`'static'` for SSG or `'dynamic'` for SSR). Layout components must accept a `children` prop.
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. 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.
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}</h3>
399
- <h1>{article.frontmatter.title}</h3>
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.ts --exclude node_modules
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
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ // eslint-disable-next-line import/no-unresolved
4
+ import './dist/cli.js';
package/dist/cli.d.ts CHANGED
@@ -1,2 +1 @@
1
- #!/usr/bin/env node
2
1
  export {};
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
- vercel: values['with-vercel'] ?? !!process.env.VERCEL ? {
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 entries = import(pathToFileURL(path.resolve(distDir, entriesJs)).toString());
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
- entries,
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
- export declare const fetchRSC: (input: string, searchParamsString: string, rerender: (fn: (prev: Elements) => Elements) => void) => Elements;
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 { cache, createContext, createElement, memo, use, useCallback, useState, startTransition } from 'react';
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 mergeElements = cache(async (a, b)=>{
18
- const nextElements = {
19
- ...await a,
20
- ...await b
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
- delete nextElements._value;
23
- return nextElements;
24
- });
25
- export const fetchRSC = cache((input, searchParamsString, rerender)=>{
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
- rerender((prev)=>mergeElements(prev, data));
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 = cache((input, searchParamsString)=>{
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
- // HACK there should be a better way...
59
- const createRerender = cache(()=>{
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() || '', getRerender());
80
+ const data = fetchRSC(input, searchParams?.toString() || '', setElements, cache);
79
81
  setElements((prev)=>mergeElements(prev, data));
80
82
  }, [
81
- getRerender
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
- vercel?: {
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>;