Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: conditional ssr (minimal API only) #534

Merged
merged 10 commits into from
Feb 28, 2024
2 changes: 1 addition & 1 deletion e2e/fixtures/ssr-basic/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this isn't optimal.
We may revisit this in the future, or maybe it's okay with the Waku target.

hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion e2e/fixtures/ssr-swr/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion e2e/fixtures/ssr-target-bundle/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/01_template/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/02_demo/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/03_minimal/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/04_promise/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/05_actions/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
14 changes: 14 additions & 0 deletions examples/06_nesting/src/components/AppWithoutSsr.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { CounterWithoutSsr } from './CounterWithoutSsr.js';

const AppWithoutSsr = () => {
return (
<div style={{ border: '3px red dashed', margin: '1em', padding: '1em' }}>
<title>Waku</title>
<h1>Hello!!</h1>
<h3>This is a server component without SSR.</h3>
<CounterWithoutSsr />
</div>
);
};

export default AppWithoutSsr;
20 changes: 20 additions & 0 deletions examples/06_nesting/src/components/CounterWithoutSsr.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div style={{ border: '3px blue dashed', margin: '1em', padding: '1em' }}>
<p>Count: {count}</p>
<button onClick={handleClick}>Increment</button>
<h3>This is a client component.</h3>
</div>
);
};
16 changes: 13 additions & 3 deletions examples/06_nesting/src/entries.tsx
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -17,6 +17,9 @@ export default defineEntries(
if (params.has('InnerApp')) {
result.InnerApp = <InnerApp count={Number(params.get('InnerApp'))} />;
}
if (params.has('AppWithoutSsr')) {
result.AppWithoutSsr = <AppWithoutSsr />;
}
return result;
},
// getBuildConfig
Expand All @@ -32,6 +35,11 @@ export default defineEntries(
{ input: 'InnerApp=5', skipPrefetch: true },
],
},
{
pathname: '/no-ssr',
entries: [{ input: 'AppWithoutSsr' }],
isStatic: true,
},
],
// getSsrConfig
async (pathname) => {
Expand All @@ -41,6 +49,8 @@ export default defineEntries(
input: '',
body: <Slot id="App" />,
};
case '/no-ssr':
return null;
default:
return null;
}
Expand Down
18 changes: 14 additions & 4 deletions examples/06_nesting/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,25 @@ import { StrictMode } from 'react';
import { createRoot, hydrateRoot } from 'react-dom/client';
import { Root, Slot } from 'waku/client';

const pathname = window.location.pathname;

const rootElement = (
<StrictMode>
<Root>
<Slot id="App" />
</Root>
{pathname === '/' ? (
<Root>
<Slot id="App" />
</Root>
) : pathname === '/no-ssr' ? (
<Root initialInput="AppWithoutSsr">
<Slot id="AppWithoutSsr" />
</Root>
) : (
<h1>Not Found</h1>
)}
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/07_router/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/08_cookies/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/09_cssmodules/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/10_fs-router/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/11_form/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/12_css/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/13_path-alias/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
2 changes: 1 addition & 1 deletion examples/14_react-tweet/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const rootElement = (
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
if (document.body.dataset.hydrate) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
Expand Down
8 changes: 0 additions & 8 deletions packages/waku/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
await startServer(app, port);
}
Expand Down
13 changes: 3 additions & 10 deletions packages/waku/src/lib/builder/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ const buildSsrBundle = async (
base: config.basePath,
plugins: [
rscIndexPlugin({ ...config, cssAssets }),
rscEnvPlugin({ config, hydrate: true }),
rscEnvPlugin({ config }),
rscPrivatePlugin(config),
],
ssr: isNodeCompatible
Expand Down Expand Up @@ -349,7 +349,6 @@ const buildClientBundle = async (
config: ResolvedConfig,
clientEntryFiles: Record<string, string>,
serverBuildOutput: Awaited<ReturnType<typeof buildServerBundle>>,
ssr: boolean,
) => {
const mainJsFile = joinPath(rootDir, config.srcDir, config.mainJs);
const nonJsAssets = serverBuildOutput.output.flatMap(({ type, fileName }) =>
Expand All @@ -361,7 +360,7 @@ const buildClientBundle = async (
plugins: [
viteReact(),
rscIndexPlugin({ ...config, cssAssets }),
rscEnvPlugin({ config, hydrate: ssr }),
rscEnvPlugin({ config }),
rscPrivatePlugin(config),
],
build: {
Expand Down Expand Up @@ -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 });
Expand Down
16 changes: 2 additions & 14 deletions packages/waku/src/lib/handlers/handler-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export function createHandler<
base: config.basePath,
plugins: [
patchReactRefresh(viteReact()),
rscEnvPlugin({ config, hydrate: ssr }),
rscEnvPlugin({ config }),
rscPrivatePlugin(config),
rscIndexPlugin(config),
rscHmrPlugin(),
Expand Down Expand Up @@ -129,16 +129,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 + '/';
Expand Down Expand Up @@ -181,7 +171,7 @@ export function createHandler<
}
return;
}
if (ssr && !(await willBeHandledByVite(req.url.pathname))) {
if (ssr) {
try {
const readable = await renderHtml({
config,
Expand Down Expand Up @@ -215,8 +205,6 @@ export function createHandler<
.pipeTo(res.stream);
return;
}
next();
return;
} catch (e) {
await handleError(e);
return;
Expand Down
5 changes: 0 additions & 5 deletions packages/waku/src/lib/plugins/vite-plugin-rsc-env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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_')
Expand Down
4 changes: 2 additions & 2 deletions packages/waku/src/lib/renderers/html-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ globalThis.__WAKU_PREFETCHED__ = {
}
data += decoder.decode(chunk);
if (!headSent) {
if (!data.includes('</head><body>')) {
if (!/<\/head><body[^>]*>/.test(data)) {
return;
}
headSent = true;
Expand Down Expand Up @@ -148,7 +148,7 @@ const buildHtml = (
'html',
null,
createElement('head', { dangerouslySetInnerHTML: { __html: head } }),
createElement('body', null, body),
createElement('body', { 'data-hydrate': true }, body),
);

export const renderHtml = async (
Expand Down
Loading
Loading