From 301a5b77a3031de8adef52b4d4f4dcde6f797e07 Mon Sep 17 00:00:00 2001 From: daishi Date: Sun, 25 Feb 2024 21:44:22 +0900 Subject: [PATCH 1/7] examples/06 /no-ssr path --- .../src/components/AppWithoutSsr.tsx | 14 +++++++++++++ .../src/components/CounterWithoutSsr.tsx | 20 +++++++++++++++++++ examples/06_nesting/src/entries.tsx | 15 +++++++++++--- 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 examples/06_nesting/src/components/AppWithoutSsr.tsx create mode 100644 examples/06_nesting/src/components/CounterWithoutSsr.tsx diff --git a/examples/06_nesting/src/components/AppWithoutSsr.tsx b/examples/06_nesting/src/components/AppWithoutSsr.tsx new file mode 100644 index 000000000..739bfd159 --- /dev/null +++ b/examples/06_nesting/src/components/AppWithoutSsr.tsx @@ -0,0 +1,14 @@ +import { CounterWithoutSsr } from './CounterWithoutSsr.js'; + +const AppWithoutSsr = () => { + return ( +
+ Waku +

Hello!!

+

This is a server component without SSR.

+ +
+ ); +}; + +export default AppWithoutSsr; diff --git a/examples/06_nesting/src/components/CounterWithoutSsr.tsx b/examples/06_nesting/src/components/CounterWithoutSsr.tsx new file mode 100644 index 000000000..8691f10ce --- /dev/null +++ b/examples/06_nesting/src/components/CounterWithoutSsr.tsx @@ -0,0 +1,20 @@ +'use client'; + +import { useState } from 'react'; + +export const CounterWithoutSsr = () => { + if (typeof window === 'undefined') { + throw new Error('This component is for client only.'); + } + const [count, setCount] = useState(0); + const handleClick = () => { + setCount((c) => c + 1); + }; + return ( +
+

Count: {count}

+ +

This is a client component.

+
+ ); +}; diff --git a/examples/06_nesting/src/entries.tsx b/examples/06_nesting/src/entries.tsx index 8624b0612..bed049ff5 100644 --- a/examples/06_nesting/src/entries.tsx +++ b/examples/06_nesting/src/entries.tsx @@ -1,10 +1,10 @@ -import { lazy } from 'react'; import type { ReactNode } from 'react'; import { defineEntries } from 'waku/server'; import { Slot } from 'waku/client'; -const App = lazy(() => import('./components/App.js')); -const InnerApp = lazy(() => import('./components/InnerApp.js')); +import App from './components/App.js'; +import InnerApp from './components/InnerApp.js'; +import AppWithoutSsr from './components/AppWithoutSsr.js'; export default defineEntries( // renderEntries @@ -17,6 +17,9 @@ export default defineEntries( if (params.has('InnerApp')) { result.InnerApp = ; } + if (params.has('AppWithoutSsr')) { + result.AppWithoutSsr = ; + } return result; }, // getBuildConfig @@ -32,6 +35,10 @@ export default defineEntries( { input: 'InnerApp=5', skipPrefetch: true }, ], }, + { + pathname: '/no-ssr', + entries: [{ input: 'AppWithoutSsr' }], + }, ], // getSsrConfig async (pathname) => { @@ -41,6 +48,8 @@ export default defineEntries( input: '', body: , }; + case '/no-ssr': + return null; default: return null; } From 5e99e93c7e06d5bae4475046d18b594ec4523b3c Mon Sep 17 00:00:00 2001 From: daishi Date: Sun, 25 Feb 2024 21:57:56 +0900 Subject: [PATCH 2/7] always enable history api callback in DEV --- packages/waku/src/cli.ts | 8 -------- packages/waku/src/lib/handlers/handler-dev.ts | 14 +------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/packages/waku/src/cli.ts b/packages/waku/src/cli.ts index 2fedccc9d..0e9d34948 100644 --- a/packages/waku/src/cli.ts +++ b/packages/waku/src/cli.ts @@ -98,14 +98,6 @@ async function runDev(options: { ssr: boolean }) { '*', honoDevMiddleware({ ...options, config, env: process.env as any }), ); - app.notFound((c) => { - // TODO Will re-consider this later. Should not be hard-coded. - const file = 'public/404.html'; - if (existsSync(file)) { - return c.html(readFileSync(file, 'utf8'), 404); - } - return c.text('404 Not Found', 404); - }); const port = parseInt(process.env.PORT || '3000', 10); startServer(app, port); } diff --git a/packages/waku/src/lib/handlers/handler-dev.ts b/packages/waku/src/lib/handlers/handler-dev.ts index dffe4f839..38a381255 100644 --- a/packages/waku/src/lib/handlers/handler-dev.ts +++ b/packages/waku/src/lib/handlers/handler-dev.ts @@ -126,16 +126,6 @@ export function createHandler< }); }; - const willBeHandledByVite = async (pathname: string) => { - const vite = await vitePromise; - try { - const result = await vite.transformRequest(pathname); - return !!result; - } catch { - return false; - } - }; - return async (req, res, next) => { const [config, vite] = await Promise.all([configPromise, vitePromise]); const basePrefix = config.basePath + config.rscPath + '/'; @@ -178,7 +168,7 @@ export function createHandler< } return; } - if (ssr && !(await willBeHandledByVite(req.url.pathname))) { + if (ssr) { try { const readable = await renderHtml({ config, @@ -212,8 +202,6 @@ export function createHandler< .pipeTo(res.stream); return; } - next(); - return; } catch (e) { handleError(e); return; From fc321541b1f9d7c080e0e1dbe16c3109b8d60c07 Mon Sep 17 00:00:00 2001 From: daishi Date: Mon, 26 Feb 2024 22:08:32 +0900 Subject: [PATCH 3/7] breaking: runtime hydrate detection --- e2e/fixtures/ssr-basic/src/main.tsx | 2 +- e2e/fixtures/ssr-swr/src/main.tsx | 2 +- e2e/fixtures/ssr-target-bundle/src/main.tsx | 2 +- examples/01_template/src/main.tsx | 2 +- examples/02_demo/src/main.tsx | 2 +- examples/03_minimal/src/main.tsx | 2 +- examples/04_promise/src/main.tsx | 2 +- examples/05_actions/src/main.tsx | 2 +- examples/06_nesting/src/main.tsx | 2 +- examples/07_router/src/main.tsx | 2 +- examples/08_cookies/src/main.tsx | 2 +- examples/09_cssmodules/src/main.tsx | 2 +- examples/10_fs-router/src/main.tsx | 2 +- examples/11_form/src/main.tsx | 2 +- examples/12_css/src/main.tsx | 2 +- examples/13_path-alias/src/main.tsx | 2 +- packages/waku/src/lib/builder/build.ts | 13 +++---------- packages/waku/src/lib/handlers/handler-dev.ts | 2 +- .../waku/src/lib/plugins/vite-plugin-rsc-env.ts | 5 ----- packages/waku/src/lib/renderers/html-renderer.ts | 2 +- packages/website/src/main.tsx | 2 +- 21 files changed, 22 insertions(+), 34 deletions(-) diff --git a/e2e/fixtures/ssr-basic/src/main.tsx b/e2e/fixtures/ssr-basic/src/main.tsx index bc436da93..fe026c6b2 100644 --- a/e2e/fixtures/ssr-basic/src/main.tsx +++ b/e2e/fixtures/ssr-basic/src/main.tsx @@ -10,7 +10,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/e2e/fixtures/ssr-swr/src/main.tsx b/e2e/fixtures/ssr-swr/src/main.tsx index bc436da93..fe026c6b2 100644 --- a/e2e/fixtures/ssr-swr/src/main.tsx +++ b/e2e/fixtures/ssr-swr/src/main.tsx @@ -10,7 +10,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/e2e/fixtures/ssr-target-bundle/src/main.tsx b/e2e/fixtures/ssr-target-bundle/src/main.tsx index bc436da93..fe026c6b2 100644 --- a/e2e/fixtures/ssr-target-bundle/src/main.tsx +++ b/e2e/fixtures/ssr-target-bundle/src/main.tsx @@ -10,7 +10,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/01_template/src/main.tsx b/examples/01_template/src/main.tsx index 2ac42e6ae..a17518496 100644 --- a/examples/01_template/src/main.tsx +++ b/examples/01_template/src/main.tsx @@ -12,7 +12,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/02_demo/src/main.tsx b/examples/02_demo/src/main.tsx index 2ac42e6ae..a17518496 100644 --- a/examples/02_demo/src/main.tsx +++ b/examples/02_demo/src/main.tsx @@ -12,7 +12,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/03_minimal/src/main.tsx b/examples/03_minimal/src/main.tsx index bc436da93..fe026c6b2 100644 --- a/examples/03_minimal/src/main.tsx +++ b/examples/03_minimal/src/main.tsx @@ -10,7 +10,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/04_promise/src/main.tsx b/examples/04_promise/src/main.tsx index dce443795..f213f62aa 100644 --- a/examples/04_promise/src/main.tsx +++ b/examples/04_promise/src/main.tsx @@ -12,7 +12,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/05_actions/src/main.tsx b/examples/05_actions/src/main.tsx index bc436da93..fe026c6b2 100644 --- a/examples/05_actions/src/main.tsx +++ b/examples/05_actions/src/main.tsx @@ -10,7 +10,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/06_nesting/src/main.tsx b/examples/06_nesting/src/main.tsx index bc436da93..fe026c6b2 100644 --- a/examples/06_nesting/src/main.tsx +++ b/examples/06_nesting/src/main.tsx @@ -10,7 +10,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/07_router/src/main.tsx b/examples/07_router/src/main.tsx index 93b72ef52..271f927b7 100644 --- a/examples/07_router/src/main.tsx +++ b/examples/07_router/src/main.tsx @@ -12,7 +12,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/08_cookies/src/main.tsx b/examples/08_cookies/src/main.tsx index bc436da93..fe026c6b2 100644 --- a/examples/08_cookies/src/main.tsx +++ b/examples/08_cookies/src/main.tsx @@ -10,7 +10,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/09_cssmodules/src/main.tsx b/examples/09_cssmodules/src/main.tsx index bc436da93..fe026c6b2 100644 --- a/examples/09_cssmodules/src/main.tsx +++ b/examples/09_cssmodules/src/main.tsx @@ -10,7 +10,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/10_fs-router/src/main.tsx b/examples/10_fs-router/src/main.tsx index 93b72ef52..271f927b7 100644 --- a/examples/10_fs-router/src/main.tsx +++ b/examples/10_fs-router/src/main.tsx @@ -12,7 +12,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/11_form/src/main.tsx b/examples/11_form/src/main.tsx index bc436da93..fe026c6b2 100644 --- a/examples/11_form/src/main.tsx +++ b/examples/11_form/src/main.tsx @@ -10,7 +10,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/12_css/src/main.tsx b/examples/12_css/src/main.tsx index bc436da93..fe026c6b2 100644 --- a/examples/12_css/src/main.tsx +++ b/examples/12_css/src/main.tsx @@ -10,7 +10,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/examples/13_path-alias/src/main.tsx b/examples/13_path-alias/src/main.tsx index bc436da93..fe026c6b2 100644 --- a/examples/13_path-alias/src/main.tsx +++ b/examples/13_path-alias/src/main.tsx @@ -10,7 +10,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); diff --git a/packages/waku/src/lib/builder/build.ts b/packages/waku/src/lib/builder/build.ts index 1b88cfe8f..5f5a03b89 100644 --- a/packages/waku/src/lib/builder/build.ts +++ b/packages/waku/src/lib/builder/build.ts @@ -296,7 +296,7 @@ const buildSsrBundle = async ( base: config.basePath, plugins: [ rscIndexPlugin({ ...config, cssAssets }), - rscEnvPlugin({ config, hydrate: true }), + rscEnvPlugin({ config }), rscPrivatePlugin(config), ], ssr: isNodeCompatible @@ -349,7 +349,6 @@ const buildClientBundle = async ( config: ResolvedConfig, clientEntryFiles: Record, serverBuildOutput: Awaited>, - ssr: boolean, ) => { const mainJsFile = joinPath(rootDir, config.srcDir, config.mainJs); const nonJsAssets = serverBuildOutput.output.flatMap(({ type, fileName }) => @@ -361,7 +360,7 @@ const buildClientBundle = async ( plugins: [ viteReact(), rscIndexPlugin({ ...config, cssAssets }), - rscEnvPlugin({ config, hydrate: ssr }), + rscEnvPlugin({ config }), rscPrivatePlugin(config), ], build: { @@ -659,13 +658,7 @@ export async function build(options: { isNodeCompatible, ); } - await buildClientBundle( - rootDir, - config, - clientEntryFiles, - serverBuildOutput, - !!options.ssr, - ); + await buildClientBundle(rootDir, config, clientEntryFiles, serverBuildOutput); const distEntries = await import(filePathToFileURL(distEntriesFile)); const buildConfig = await getBuildConfig({ config, entries: distEntries }); diff --git a/packages/waku/src/lib/handlers/handler-dev.ts b/packages/waku/src/lib/handlers/handler-dev.ts index 38a381255..0c27bfb64 100644 --- a/packages/waku/src/lib/handlers/handler-dev.ts +++ b/packages/waku/src/lib/handlers/handler-dev.ts @@ -56,7 +56,7 @@ export function createHandler< base: config.basePath, plugins: [ patchReactRefresh(viteReact()), - rscEnvPlugin({ config, hydrate: ssr }), + rscEnvPlugin({ config }), rscPrivatePlugin(config), rscIndexPlugin(config), rscHmrPlugin(), diff --git a/packages/waku/src/lib/plugins/vite-plugin-rsc-env.ts b/packages/waku/src/lib/plugins/vite-plugin-rsc-env.ts index ab394a1d3..325b60a81 100644 --- a/packages/waku/src/lib/plugins/vite-plugin-rsc-env.ts +++ b/packages/waku/src/lib/plugins/vite-plugin-rsc-env.ts @@ -2,13 +2,11 @@ import type { Plugin } from 'vite'; export function rscEnvPlugin({ config, - hydrate, }: { config?: { basePath: string; rscPath: string; }; - hydrate?: boolean | undefined; }): Plugin { return { name: 'rsc-env-plugin', @@ -28,9 +26,6 @@ export function rscEnvPlugin({ ], ] : []), - ...(hydrate - ? [['import.meta.env.WAKU_HYDRATE', JSON.stringify('true')]] - : []), ...Object.entries((globalThis as any).__WAKU_PRIVATE_ENV__).flatMap( ([k, v]) => k.startsWith('WAKU_PUBLIC_') diff --git a/packages/waku/src/lib/renderers/html-renderer.ts b/packages/waku/src/lib/renderers/html-renderer.ts index 36189a813..4045474a2 100644 --- a/packages/waku/src/lib/renderers/html-renderer.ts +++ b/packages/waku/src/lib/renderers/html-renderer.ts @@ -198,7 +198,7 @@ const buildHtml = ( 'html', null, createElement('head', { dangerouslySetInnerHTML: { __html: head } }), - createElement('body', null, body), + createElement('body', { 'data-hydrate': true }, body), ); export const renderHtml = async ( diff --git a/packages/website/src/main.tsx b/packages/website/src/main.tsx index 2ac42e6ae..a17518496 100644 --- a/packages/website/src/main.tsx +++ b/packages/website/src/main.tsx @@ -12,7 +12,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); From 1b5ed6dd06718f160f9fb29ce4c778b936112052 Mon Sep 17 00:00:00 2001 From: daishi Date: Tue, 27 Feb 2024 14:20:11 +0900 Subject: [PATCH 4/7] fix ex 14 --- examples/14_react-tweet/src/main.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/14_react-tweet/src/main.tsx b/examples/14_react-tweet/src/main.tsx index 2ac42e6ae..a17518496 100644 --- a/examples/14_react-tweet/src/main.tsx +++ b/examples/14_react-tweet/src/main.tsx @@ -12,7 +12,7 @@ const rootElement = ( ); -if (import.meta.env.WAKU_HYDRATE) { +if (document.body.dataset.hydrate) { hydrateRoot(document.body, rootElement); } else { createRoot(document.body).render(rootElement); From 21601774892cbd26e0ed773b44cd7f767930ba41 Mon Sep 17 00:00:00 2001 From: daishi Date: Tue, 27 Feb 2024 14:48:51 +0900 Subject: [PATCH 5/7] fix html renderer --- packages/waku/src/lib/renderers/html-renderer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/waku/src/lib/renderers/html-renderer.ts b/packages/waku/src/lib/renderers/html-renderer.ts index 8efca67db..fdcaffd79 100644 --- a/packages/waku/src/lib/renderers/html-renderer.ts +++ b/packages/waku/src/lib/renderers/html-renderer.ts @@ -97,7 +97,7 @@ globalThis.__WAKU_PREFETCHED__ = { } data += decoder.decode(chunk); if (!headSent) { - if (!data.includes('')) { + if (!/<\/head>]*>/.test(data)) { return; } headSent = true; From 17b57d974cb8db73f3f7679021a94819b31ff940 Mon Sep 17 00:00:00 2001 From: daishi Date: Tue, 27 Feb 2024 15:14:40 +0900 Subject: [PATCH 6/7] ex06: /no-ssr page --- examples/06_nesting/src/main.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/examples/06_nesting/src/main.tsx b/examples/06_nesting/src/main.tsx index fe026c6b2..dc03c864f 100644 --- a/examples/06_nesting/src/main.tsx +++ b/examples/06_nesting/src/main.tsx @@ -2,11 +2,21 @@ import { StrictMode } from 'react'; import { createRoot, hydrateRoot } from 'react-dom/client'; import { Root, Slot } from 'waku/client'; +const pathname = window.location.pathname; + const rootElement = ( - - - + {pathname === '/' ? ( + + + + ) : pathname === '/no-ssr' ? ( + + + + ) : ( +

Not Found

+ )}
); From 30b12f8577fe46609ef15137bda76a08604474aa Mon Sep 17 00:00:00 2001 From: daishi Date: Wed, 28 Feb 2024 11:14:31 +0900 Subject: [PATCH 7/7] ex06: static for no-ssr page --- examples/06_nesting/src/entries.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/06_nesting/src/entries.tsx b/examples/06_nesting/src/entries.tsx index bed049ff5..0b0d31553 100644 --- a/examples/06_nesting/src/entries.tsx +++ b/examples/06_nesting/src/entries.tsx @@ -38,6 +38,7 @@ export default defineEntries( { pathname: '/no-ssr', entries: [{ input: 'AppWithoutSsr' }], + isStatic: true, }, ], // getSsrConfig