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

Refactor: use Worker only in DEV #218

Merged
merged 7 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions packages/waku/src/lib/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ import type { Config, ResolvedConfig } from '../config.js';
import { resolveConfig, viteInlineConfig } from './config.js';
import { normalizePath } from './utils/path.js';
import { encodeInput, generatePrefetchCode } from './middleware/rsc/utils.js';
import {
shutdown as shutdownRsc,
renderRSC,
getBuildConfigRSC,
} from './middleware/rsc/worker-api.js';
import { renderRSC, getBuildConfigRSC } from './rsc/renderer.js';
import { rscIndexPlugin } from './vite-plugin/rsc-index-plugin.js';
import { rscAnalyzePlugin } from './vite-plugin/rsc-analyze-plugin.js';
import { rscTransformPlugin } from './vite-plugin/rsc-transform-plugin.js';
Expand Down Expand Up @@ -233,7 +229,7 @@ const buildClientBundle = async (
};

const emitRscFiles = async (config: ResolvedConfig) => {
const buildConfig = await getBuildConfigRSC(config);
const buildConfig = await getBuildConfigRSC({ config });
const clientModuleMap = new Map<string, Set<string>>();
const addClientModule = (input: string, id: string) => {
let idSet = clientModuleMap.get(input);
Expand Down Expand Up @@ -261,14 +257,13 @@ const emitRscFiles = async (config: ResolvedConfig) => {
if (!rscFileSet.has(destFile)) {
rscFileSet.add(destFile);
await fsPromises.mkdir(path.dirname(destFile), { recursive: true });
const [readable] = await renderRSC({
const readable = await renderRSC({
input,
method: 'GET',
headers: {},
config,
command: 'build',
context,
moduleIdCallback: (id) => addClientModule(input, id),
isDev: false,
});
await pipeline(
Readable.fromWeb(readable as any),
Expand Down Expand Up @@ -493,5 +488,4 @@ export async function build(options: { config: Config; ssr?: boolean }) {
emitVercelOutput(config, clientBuildOutput, rscFiles, htmlFiles);

await shutdownSsr();
await shutdownRsc();
}
75 changes: 51 additions & 24 deletions packages/waku/src/lib/middleware/rsc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import type { Config } from '../../config.js';
import { resolveConfig } from '../config.js';
import { endStream } from '../utils/stream.js';
import { renderHtml } from './rsc/ssr.js';
import { decodeInput, hasStatusCode } from './rsc/utils.js';
import { decodeInput, hasStatusCode, deepFreeze } from './rsc/utils.js';
import {
registerReloadCallback,
registerImportCallback,
renderRSC,
renderRSC as renderRSCWorker,
} from './rsc/worker-api.js';
import { renderRSC } from '../rsc/renderer.js';
import { patchReactRefresh } from '../vite-plugin/patch-react-refresh.js';
import type { BaseReq, BaseRes, Middleware } from './types.js';

Expand Down Expand Up @@ -166,30 +167,56 @@ export function rsc<
return;
}
}
if (pathStr.startsWith(basePrefix)) {
const { method, headers } = req;
if (method !== 'GET' && method !== 'POST') {
throw new Error(`Unsupported method '${method}'`);
if (command !== 'dev') {
if (pathStr.startsWith(basePrefix)) {
const { method, headers } = req;
if (method !== 'GET' && method !== 'POST') {
throw new Error(`Unsupported method '${method}'`);
}
try {
const input = decodeInput(pathStr.slice(basePrefix.length));
const readable = await renderRSC({
config,
input,
method,
context,
body: req.stream,
contentType: headers['content-type'] as string | undefined,
isDev: false,
});
unstable_posthook?.(req, res, context as Context);
deepFreeze(context);
readable.pipeTo(res.stream);
} catch (e) {
handleError(e);
}
return;
}
try {
const input = decodeInput(pathStr.slice(basePrefix.length));
const [readable, nextCtx] = await renderRSC({
input,
method,
headers,
config,
command,
context,
stream: req.stream,
});
unstable_posthook?.(req, res, nextCtx as Context);
readable.pipeTo(res.stream);
} catch (e) {
handleError(e);
} else {
// command === 'dev'
if (pathStr.startsWith(basePrefix)) {
const { method, headers } = req;
if (method !== 'GET' && method !== 'POST') {
throw new Error(`Unsupported method '${method}'`);
}
try {
const input = decodeInput(pathStr.slice(basePrefix.length));
const [readable, nextCtx] = await renderRSCWorker({
input,
method,
headers,
config,
command,
context,
stream: req.stream,
});
unstable_posthook?.(req, res, nextCtx as Context);
readable.pipeTo(res.stream);
} catch (e) {
handleError(e);
}
return;
}
return;
}
if (command === 'dev') {
const vite = await getViteServer();
// TODO Do we still need this?
// HACK re-export "?v=..." URL to avoid dual module hazard.
Expand Down
33 changes: 23 additions & 10 deletions packages/waku/src/lib/middleware/rsc/ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { viteInlineConfig } from '../../config.js';
import { defineEntries } from '../../../server.js';
import { concatUint8Arrays } from '../../utils/stream.js';
import { normalizePath } from '../../utils/path.js';
import { renderRSC } from './worker-api.js';
import { hasStatusCode } from './utils.js';
import { renderRSC as renderRSCWorker } from './worker-api.js';
import { renderRSC } from '../../rsc/renderer.js';
import { hasStatusCode, deepFreeze } from './utils.js';

const loadReact = async (
config: ResolvedConfig,
Expand Down Expand Up @@ -357,14 +358,26 @@ export const renderHtml = async <Context>(
let stream: ReadableStream;
let nextCtx: Context;
try {
[stream, nextCtx] = await renderRSC({
input: ssrConfig.input,
method: 'GET',
headers: {},
config,
command,
context,
});
if (command !== 'dev') {
stream = await renderRSC({
config,
input: ssrConfig.input,
method: 'GET',
context,
isDev: false,
});
deepFreeze(context);
nextCtx = context;
} else {
[stream, nextCtx] = await renderRSCWorker({
input: ssrConfig.input,
method: 'GET',
headers: {},
config,
command,
context,
});
}
} catch (e) {
if (hasStatusCode(e) && e.statusCode === 404) {
return null;
Expand Down
34 changes: 0 additions & 34 deletions packages/waku/src/lib/middleware/rsc/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,37 +56,3 @@ export const deepFreeze = (x: unknown): void => {
}
}
};

// TODO is this correct? better to use a library?
export const parseFormData = (body: string, contentType: string) => {
const boundary = contentType.split('boundary=')[1];
const parts = body.split(`--${boundary}`);
const formData = new FormData();
for (const part of parts) {
if (part.trim() === '' || part === '--') continue;
const [rawHeaders, content] = part.split('\r\n\r\n', 2);
const headers = rawHeaders!.split('\r\n').reduce(
(acc, currentHeader) => {
const [key, value] = currentHeader.split(': ');
acc[key!.toLowerCase()] = value!;
return acc;
},
{} as Record<string, string>,
);
const contentDisposition = headers['content-disposition'];
const nameMatch = /name="([^"]+)"/.exec(contentDisposition!);
const filenameMatch = /filename="([^"]+)"/.exec(contentDisposition!);
if (nameMatch) {
const name = nameMatch[1];
if (filenameMatch) {
const filename = filenameMatch[1];
const type = headers['content-type'] || 'application/octet-stream';
const blob = new Blob([content!], { type });
formData.append(name!, blob, filename);
} else {
formData.append(name!, content!.trim());
}
}
}
return formData;
};
Loading
Loading