Skip to content

Commit

Permalink
step 2 for middleware architecture (#550)
Browse files Browse the repository at this point in the history
* use rsc middleware from ssr middleware

* move worker files

* wip: refactor renderRsc api

* wip: refactor renderRscWithWorker with object context

* wip: dev-server middleware

* fix format

* wip: refactor getSsrConfigWithWorker with object context

* wip: ssr for dev

* fix ssr for dev

* revert the flag

* fix header

* wip: revert the flag for dev

* Revert "wip: revert the flag for dev"

This reverts commit 4b8fbd1.

* null ssr config instead of throw

* code splittable for cfw

* all other serve-*

* remove unused
  • Loading branch information
dai-shi authored Mar 1, 2024
1 parent 47846fe commit 4e9ac55
Show file tree
Hide file tree
Showing 28 changed files with 602 additions and 293 deletions.
2 changes: 1 addition & 1 deletion e2e/fixtures/rsc-basic/src/entries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ export default defineEntries(
async () => [{ pathname: '/', entries: [{ input: '' }] }],
// getSsrConfig
async () => {
throw new Error('SSR is should not be used in this test.');
return null;
},
);
6 changes: 3 additions & 3 deletions packages/waku/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
"types": "./dist/config.d.ts",
"default": "./dist/config.js"
},
"./middleware": {
"types": "./dist/middleware.d.ts",
"default": "./dist/middleware.js"
"./middleware/*": {
"types": "./dist/middleware/*.d.ts",
"default": "./dist/middleware/*.js"
},
"./prd": {
"types": "./dist/prd.d.ts",
Expand Down
21 changes: 10 additions & 11 deletions packages/waku/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,14 @@ if (values.version) {

async function runDev(options: { ssr: boolean }) {
const app = new Hono();
app.use(
'*',
honoDevMiddleware({ ...options, config, env: process.env as any }),
);
if (!process.env.WAKU_OLD_MIDDLEWARE) {
app.use('*', runner({ config, env: process.env as any, cmd: 'dev' }));
} else {
app.use(
'*',
honoDevMiddleware({ ...options, config, env: process.env as any }),
);
}
const port = parseInt(process.env.PORT || '3000', 10);
await startServer(app, port);
}
Expand Down Expand Up @@ -132,15 +136,10 @@ async function runStart(options: { ssr: boolean }) {
import(pathToFileURL(path.resolve(distDir, entriesJs)).toString());
const app = new Hono();
app.use('*', serveStatic({ root: path.join(distDir, publicDir) }));
if (process.env.WAKU_WIP_MIDDLEWARE) {
if (!process.env.WAKU_OLD_MIDDLEWARE) {
app.use(
'*',
runner({
config,
env: process.env as any,
cmd: 'start',
loadEntries,
}),
runner({ config, env: process.env as any, cmd: 'start', loadEntries }),
);
} else {
app.use(
Expand Down
64 changes: 38 additions & 26 deletions packages/waku/src/lib/builder/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,16 +432,20 @@ const emitRscFiles = async (
encodeInput(input),
);
await mkdir(joinPath(destRscFile, '..'), { recursive: true });
const readable = await renderRsc({
input,
searchParams: new URLSearchParams(),
method: 'GET',
config,
context,
moduleIdCallback: (id) => addClientModule(input, id),
isDev: false,
entries: distEntries,
});
const readable = await renderRsc(
{
input,
searchParams: new URLSearchParams(),
method: 'GET',
config,
context,
moduleIdCallback: (id) => addClientModule(input, id),
},
{
isDev: false,
entries: distEntries,
},
);
await pipeline(
Readable.fromWeb(readable as any),
createWriteStream(destRscFile),
Expand Down Expand Up @@ -548,23 +552,31 @@ const emitHtmlFiles = async (
searchParams: new URLSearchParams(),
htmlHead,
renderRscForHtml: (input, searchParams) =>
renderRsc({
entries: distEntries,
config,
input,
searchParams,
method: 'GET',
context,
isDev: false,
}),
renderRsc(
{
config,
input,
searchParams,
method: 'GET',
context,
},
{
isDev: false,
entries: distEntries,
},
),
getSsrConfigForHtml: (pathname, searchParams) =>
getSsrConfig({
config,
pathname,
searchParams,
isDev: false,
entries: distEntries,
}),
getSsrConfig(
{
config,
pathname,
searchParams,
},
{
isDev: false,
entries: distEntries,
},
),
loadClientModule: (key) =>
distEntries.loadModule(CLIENT_PREFIX + key),
isDev: false,
Expand Down
9 changes: 4 additions & 5 deletions packages/waku/src/lib/builder/serve-aws-lambda.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import path from 'node:path';
import { existsSync, readFileSync } from 'node:fs';
import { Hono } from 'hono';
import { handle } from 'hono/aws-lambda';
import { serveStatic } from '@hono/node-server/serve-static';

import { honoMiddleware } from '../old-wrappers/hono-prd.js';
import path from 'node:path';
import { existsSync, readFileSync } from 'node:fs';
import { runner } from '../hono/runner.js';

const ssr = !!import.meta.env.WAKU_BUILD_SSR;
const distDir = process.env?.WAKU_BUILD_DIST_DIR ?? '';
const publicDir = import.meta.env.WAKU_CONFIG_PUBLIC_DIR!;
const loadEntries = () => import(import.meta.env.WAKU_ENTRIES_FILE!);
Expand All @@ -15,7 +14,7 @@ const env = process.env as Record<string, string>;

const app = new Hono();
app.use('*', serveStatic({ root: `${distDir}/${publicDir}` }));
app.use('*', honoMiddleware({ loadEntries, ssr, env }));
app.use('*', runner({ cmd: 'start', loadEntries, env }));
app.notFound(async (c) => {
const file = path.join(distDir, publicDir, '404.html');
if (existsSync(file)) {
Expand Down
7 changes: 3 additions & 4 deletions packages/waku/src/lib/builder/serve-cloudflare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import { serveStatic } from 'hono/cloudflare-workers';
// eslint-disable-next-line import/no-unresolved
import manifest from '__STATIC_CONTENT_MANIFEST';

import { honoMiddleware } from '../old-wrappers/hono-prd.js';
import { runner } from '../hono/runner.js';

const ssr = !!import.meta.env.WAKU_BUILD_SSR;
const loadEntries = () => import(import.meta.env.WAKU_ENTRIES_FILE!);
let serveWaku: ReturnType<typeof honoMiddleware> | undefined;
let serveWaku: ReturnType<typeof runner> | undefined;
let staticContent: any;

const parsedManifest: Record<string, string> = JSON.parse(manifest);
Expand All @@ -34,7 +33,7 @@ export default {
ctx: Parameters<typeof app.fetch>[2],
) {
if (!serveWaku) {
serveWaku = honoMiddleware({ loadEntries, ssr, env });
serveWaku = runner({ cmd: 'start', loadEntries, env });
staticContent = env.__STATIC_CONTENT;
}
return app.fetch(request, env, ctx);
Expand Down
5 changes: 2 additions & 3 deletions packages/waku/src/lib/builder/serve-deno.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,18 @@ import { Hono } from 'https://deno.land/x/hono/mod.ts';
// @ts-expect-error no types
import { serveStatic } from 'https://deno.land/x/hono/middleware.ts';

import { honoMiddleware } from '../old-wrappers/hono-prd.js';
import { runner } from '../hono/runner.js';

declare const Deno: any;

const ssr = !!import.meta.env.WAKU_BUILD_SSR;
const distDir = import.meta.env.WAKU_CONFIG_DIST_DIR;
const publicDir = import.meta.env.WAKU_CONFIG_PUBLIC_DIR;
const loadEntries = () => import(import.meta.env.WAKU_ENTRIES_FILE!);
const env = Deno.env.toObject();

const app = new Hono();
app.use('*', serveStatic({ root: `${distDir}/${publicDir}` }));
app.use('*', honoMiddleware({ loadEntries, ssr, env }));
app.use('*', runner({ cmd: 'start', loadEntries, env }));
app.notFound(async (c: any) => {
const file = `${distDir}/${publicDir}/404.html`;
const info = await Deno.stat(file);
Expand Down
5 changes: 2 additions & 3 deletions packages/waku/src/lib/builder/serve-netlify.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { Hono } from 'hono';
import type { Context } from '@netlify/functions';

import { honoMiddleware } from '../old-wrappers/hono-prd.js';
import { runner } from '../hono/runner.js';

const ssr = !!import.meta.env.WAKU_BUILD_SSR;
const loadEntries = () => import(import.meta.env.WAKU_ENTRIES_FILE!);
const env: Record<string, string> = process.env as any;

const app = new Hono();
app.use('*', honoMiddleware({ loadEntries, ssr, env }));
app.use('*', runner({ cmd: 'start', loadEntries, env }));
app.notFound((c) => {
const notFoundHtml = (globalThis as any).__WAKU_NOT_FOUND_HTML__;
if (typeof notFoundHtml === 'string') {
Expand Down
7 changes: 3 additions & 4 deletions packages/waku/src/lib/builder/serve-partykit.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Hono } from 'hono';

import { honoMiddleware } from '../old-wrappers/hono-prd.js';
import { runner } from '../hono/runner.js';

const ssr = !!import.meta.env.WAKU_BUILD_SSR;
const loadEntries = () => import(import.meta.env.WAKU_ENTRIES_FILE!);
let serveWaku: ReturnType<typeof honoMiddleware> | undefined;
let serveWaku: ReturnType<typeof runner> | undefined;

const app = new Hono();
app.use('*', (c, next) => serveWaku!(c, next));
Expand All @@ -30,7 +29,7 @@ app.notFound(async (c) => {
export default {
onFetch(request: Request, lobby: any, ctx: Parameters<typeof app.fetch>[2]) {
if (!serveWaku) {
serveWaku = honoMiddleware({ loadEntries, ssr, env: lobby });
serveWaku = runner({ cmd: 'start', loadEntries, env: lobby });
}
return app.fetch(request, lobby, ctx);
},
Expand Down
5 changes: 2 additions & 3 deletions packages/waku/src/lib/builder/serve-vercel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ import type { IncomingMessage, ServerResponse } from 'node:http';
import { Hono } from 'hono';
import { getRequestListener } from '@hono/node-server';

import { honoMiddleware } from '../old-wrappers/hono-prd.js';
import { runner } from '../hono/runner.js';

const ssr = !!import.meta.env.WAKU_BUILD_SSR;
const distDir = import.meta.env.WAKU_CONFIG_DIST_DIR!;
const publicDir = import.meta.env.WAKU_CONFIG_PUBLIC_DIR!;
const loadEntries = () => import(import.meta.env.WAKU_ENTRIES_FILE!);
const env: Record<string, string> = process.env as any;

const app = new Hono();
app.use('*', honoMiddleware({ loadEntries, ssr, env }));
app.use('*', runner({ cmd: 'start', loadEntries, env }));
app.notFound((c) => {
// FIXME better implementation using node stream?
const file = path.join(distDir, publicDir, '404.html');
Expand Down
32 changes: 17 additions & 15 deletions packages/waku/src/lib/handlers/handler-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
registerHotUpdateCallback,
renderRscWithWorker,
getSsrConfigWithWorker,
} from './dev-worker-api.js';
} from '../renderers/dev-worker-api.js';
import { patchReactRefresh } from '../plugins/patch-react-refresh.js';
import { rscIndexPlugin } from '../plugins/vite-plugin-rsc-index.js';
import { rscHmrPlugin, hotUpdate } from '../plugins/vite-plugin-rsc-hmr.js';
Expand All @@ -35,15 +35,18 @@ export const CLIENT_MODULE_MAP = {
export type CLIENT_MODULE_KEY = keyof typeof CLIENT_MODULE_MAP;

export function createHandler<
Context,
Req extends BaseReq,
Res extends BaseRes,
>(options: {
config?: Config;
ssr?: boolean;
env?: Record<string, string>;
unstable_prehook?: (req: Req, res: Res) => Context;
unstable_posthook?: (req: Req, res: Res, ctx: Context) => void;
unstable_prehook?: (req: Req, res: Res) => Record<string, unknown>;
unstable_posthook?: (
req: Req,
res: Res,
context: Record<string, unknown>,
) => void;
}): Handler<Req, Res> {
const { ssr, unstable_prehook, unstable_posthook } = options;
if (!unstable_prehook && unstable_posthook) {
Expand Down Expand Up @@ -141,7 +144,7 @@ export function createHandler<
}
await endStream(res.stream, String(err));
};
let context: Context | undefined;
let context: Record<string, unknown> | undefined;
try {
context = unstable_prehook?.(req, res);
} catch (e) {
Expand All @@ -155,16 +158,16 @@ export function createHandler<
}
try {
const input = decodeInput(req.url.pathname.slice(basePrefix.length));
const [readable, nextCtx] = await renderRscWithWorker({
const readable = await renderRscWithWorker({
input,
searchParamsString: req.url.searchParams.toString(),
searchParams: req.url.searchParams,
method,
contentType,
config,
context,
stream: req.stream,
body: req.stream,
});
unstable_posthook?.(req, res, nextCtx as Context);
unstable_posthook?.(req, res, context!);
await readable.pipeTo(res.stream);
} catch (e) {
await handleError(e);
Expand All @@ -179,26 +182,25 @@ export function createHandler<
searchParams: req.url.searchParams,
htmlHead: config.htmlHead,
renderRscForHtml: async (input, searchParams) => {
const [readable, nextCtx] = await renderRscWithWorker({
const readable = await renderRscWithWorker({
input,
searchParamsString: searchParams.toString(),
searchParams,
method: 'GET',
contentType: undefined,
config,
context,
});
context = nextCtx as Context;
return readable;
},
getSsrConfigForHtml: (pathname, options) =>
getSsrConfigWithWorker(config, pathname, options),
getSsrConfigForHtml: (pathname, searchParams) =>
getSsrConfigWithWorker({ config, pathname, searchParams }),
loadClientModule: (key) => import(CLIENT_MODULE_MAP[key]),
isDev: true,
rootDir: vite.config.root,
loadServerFile,
});
if (readable) {
unstable_posthook?.(req, res, context as Context);
unstable_posthook?.(req, res, context!);
res.setHeader('content-type', 'text/html; charset=utf-8');
await readable
.pipeThrough(await transformIndexHtml(req.url.pathname))
Expand Down
Loading

0 comments on commit 4e9ac55

Please sign in to comment.