Skip to content

Commit

Permalink
Merge branch 'main' into cloudflare-pages
Browse files Browse the repository at this point in the history
  • Loading branch information
dai-shi committed Jul 25, 2024
2 parents bc90fcf + 8d0f896 commit 0c4b5b9
Show file tree
Hide file tree
Showing 18 changed files with 82 additions and 106 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ We recommend other frameworks for heavy ecommerce or enterprise applications. Wa
Start a new Waku project with the `create` command for your preferred package manager. It will scaffold a new project with our default [Waku starter](https://github.com/dai-shi/waku/tree/main/examples/01_template).

```
npm create waku@latest
npm create waku@next
```

**Node.js version requirement:** `^20.8.0` or `^18.17.0`
Expand Down Expand Up @@ -215,7 +215,7 @@ export const getConfig = async () => {

### Pages

Pages render a single route, segment route, or catch-all route based on the file system path (conventions below). All page components automatically receive two props related to the rendered route: `path` (string) and `searchParams` ([URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)).
Pages render a single route, segment route, or catch-all route based on the file system path (conventions below). All page components automatically receive two props related to the rendered route: `path` (string) and `query` (string).

#### Single routes

Expand Down Expand Up @@ -493,20 +493,20 @@ The `useRouter` hook can be used to inspect the current route or perform program

#### router properties

The `router` object has two properties related to the current route: `path` (string) and `searchParams` ([URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)).
The `router` object has two properties related to the current route: `path` (string) and `query` (string).

```tsx
'use client';

import { useRouter_UNSTABLE as useRouter } from 'waku';

export const Component = () => {
const { path, searchParams } = useRouter();
const { path, query } = useRouter();

return (
<>
<div>current path: {path}</div>
<div>current searchParams: {searchParams.toString()}</div>
<div>current query: {query}</div>
</>
);
};
Expand Down
3 changes: 3 additions & 0 deletions packages/waku/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ async function runDev() {
const config = await loadConfig();
const app = new Hono();
app.use('*', runner({ cmd: 'dev', config, env: process.env as any }));
// bypassing hono default notFound handler
// @ts-expect-error FIXME there might be a better way to handle this
app.use('*', (_c, _next) => {});
const port = parseInt(values.port || '3000', 10);
await startServer(app, port);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/waku/src/lib/builder/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ const buildServerBundle = async (
serverEntryFiles,
}),
rscRsdwPlugin(),
rscEnvPlugin({ config }),
rscEnvPlugin({ isDev: false, config }),
rscPrivatePlugin(config),
rscManagedPlugin({
...config,
Expand Down Expand Up @@ -317,7 +317,7 @@ const buildSsrBundle = async (
...config,
cssAssets,
}),
rscEnvPlugin({ config }),
rscEnvPlugin({ isDev: false, config }),
rscPrivatePlugin(config),
rscManagedPlugin({ ...config, addMainToInput: true }),
rscTransformPlugin({ isClient: true, isBuild: true, serverEntryFiles }),
Expand Down Expand Up @@ -392,7 +392,7 @@ const buildClientBundle = async (
...config,
cssAssets,
}),
rscEnvPlugin({ config }),
rscEnvPlugin({ isDev: false, config }),
rscPrivatePlugin(config),
rscManagedPlugin({ ...config, addMainToInput: true }),
rscTransformPlugin({ isClient: true, isBuild: true, serverEntryFiles }),
Expand Down
12 changes: 7 additions & 5 deletions packages/waku/src/lib/hono/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ export const runner = (options: MiddlewareOptions): MiddlewareHandler => {
});
};
await run(0);
return c.body(
ctx.res.body || null,
(ctx.res.status as any) || 200,
ctx.res.headers || {},
);
if (!c.finalized) {
return c.body(
ctx.res.body || null,
(ctx.res.status as any) || 200,
ctx.res.headers || {},
);
}
};
};
56 changes: 24 additions & 32 deletions packages/waku/src/lib/middleware/dev-server-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ const createMainViteServer = (
},
}),
rscRsdwPlugin(),
rscEnvPlugin({ config }),
rscEnvPlugin({ isDev: true, config }),
rscPrivatePlugin(config),
rscManagedPlugin(config),
rscIndexPlugin(config),
Expand All @@ -133,19 +133,18 @@ const createMainViteServer = (
return vite;
});

const loadServerFileMain = async (fileURL: string) => {
const vite = await vitePromise;
return vite.ssrLoadModule(fileURLToFilePath(fileURL));
};

const loadServerModuleMain = async (id: string) => {
if (id === 'waku' || id.startsWith('waku/')) {
const loadServerModuleMain = async (idOrFileURL: string) => {
if (idOrFileURL === 'waku' || idOrFileURL.startsWith('waku/')) {
// HACK I don't know why this is necessary.
// `external: ['waku']` doesn't somehow work?
return import(id);
return import(/* @vite-ignore */ idOrFileURL);
}
const vite = await vitePromise;
return vite.ssrLoadModule(id);
return vite.ssrLoadModule(
idOrFileURL.startsWith('file://')
? fileURLToFilePath(idOrFileURL)
: idOrFileURL,
);
};

const transformIndexHtml = async (pathname: string) => {
Expand Down Expand Up @@ -196,7 +195,6 @@ const createMainViteServer = (

return {
vitePromise,
loadServerFileMain,
loadServerModuleMain,
transformIndexHtml,
willBeHandledLater,
Expand All @@ -217,7 +215,7 @@ const createRscViteServer = (
nonjsResolvePlugin(),
devCommonJsPlugin({}),
rscRsdwPlugin(),
rscEnvPlugin({}),
rscEnvPlugin({ isDev: true }),
rscPrivatePlugin({ privateDir: config.privateDir, hotUpdateCallback }),
rscManagedPlugin({ basePath: config.basePath, srcDir: config.srcDir }),
rscTransformPlugin({ isClient: false, isBuild: false }),
Expand Down Expand Up @@ -255,14 +253,13 @@ const createRscViteServer = (
return vite;
});

const loadServerFileRsc = async (fileURL: string) => {
const vite = await vitePromise;
return vite.ssrLoadModule(fileURLToFilePath(fileURL));
};

const loadServerModuleRsc = async (id: string) => {
const loadServerModuleRsc = async (idOrFileURL: string) => {
const vite = await vitePromise;
return vite.ssrLoadModule(id);
return vite.ssrLoadModule(
idOrFileURL.startsWith('file://')
? fileURLToFilePath(idOrFileURL)
: idOrFileURL,
);
};

const loadEntriesDev = async (config: { srcDir: string }) => {
Expand Down Expand Up @@ -293,7 +290,6 @@ const createRscViteServer = (
};

return {
loadServerFileRsc,
loadServerModuleRsc,
loadEntriesDev,
resolveClientEntry,
Expand All @@ -309,23 +305,21 @@ export const devServer: Middleware = (options) => {
(globalThis as any).__WAKU_PRIVATE_ENV__ = options.env || {};
const configPromise = resolveConfig(options.config);

(globalThis as any).__WAKU_HACK_IMPORT__ = async (id: string) =>
loadServerFileRsc(id);
(globalThis as any).__WAKU_SERVER_HACK_IMPORT__ = (idOrFileURL: string) =>
loadServerModuleRsc(idOrFileURL);

(globalThis as any).__WAKU_CLIENT_HACK_IMPORT__ = (idOrFileURL: string) =>
loadServerModuleMain(idOrFileURL);

const {
vitePromise,
loadServerFileMain,
loadServerModuleMain,
transformIndexHtml,
willBeHandledLater,
} = createMainViteServer(configPromise);

const {
loadServerFileRsc,
loadServerModuleRsc,
loadEntriesDev,
resolveClientEntry,
} = createRscViteServer(configPromise);
const { loadServerModuleRsc, loadEntriesDev, resolveClientEntry } =
createRscViteServer(configPromise);

let initialModules: ClonableModuleNode[];

Expand Down Expand Up @@ -355,7 +349,7 @@ export const devServer: Middleware = (options) => {

ctx.unstable_devServer = {
rootDir: vite.config.root,
resolveClientEntryDev: (id: string) =>
resolveClientEntry: (id: string) =>
resolveClientEntry(
id,
{
Expand All @@ -364,10 +358,8 @@ export const devServer: Middleware = (options) => {
},
initialModules,
),
loadServerFileRsc,
loadServerModuleRsc,
loadEntriesDev,
loadServerFileMain,
loadServerModuleMain,
transformIndexHtml,
willBeHandledLater,
Expand Down
2 changes: 1 addition & 1 deletion packages/waku/src/lib/middleware/dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const devServer: Middleware = (options) => {
return (_ctx, next) => next();
}
const devServerImplPromise = import(
DO_NOT_BUNDLE + './dev-server-impl.js'
/* @vite-ignore */ DO_NOT_BUNDLE + './dev-server-impl.js'
).then(({ devServer }) => devServer(options));
return async (ctx, next) => {
const devServerImpl = await devServerImplPromise;
Expand Down
3 changes: 1 addition & 2 deletions packages/waku/src/lib/middleware/rsc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,8 @@ export const rsc: Middleware = (options) => {
const readable = await (devServer
? renderRsc(args, {
isDev: true,
loadServerFileRsc: devServer.loadServerFileRsc,
loadServerModuleRsc: devServer.loadServerModuleRsc,
resolveClientEntry: devServer.resolveClientEntryDev,
resolveClientEntry: devServer.resolveClientEntry,
entries: await devServer.loadEntriesDev(config),
})
: renderRsc(args, { isDev: false, entries }));
Expand Down
5 changes: 2 additions & 3 deletions packages/waku/src/lib/middleware/ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,12 @@ export const ssr: Middleware = (options) => {
{
isDev: true,
loadServerModuleRsc: devServer.loadServerModuleRsc,
resolveClientEntry: devServer.resolveClientEntryDev,
resolveClientEntry: devServer.resolveClientEntry,
entries: entriesDev!,
},
),
rootDir: devServer.rootDir,
loadServerFile: devServer.loadServerFileMain,
loadServerModule: devServer.loadServerModuleMain,
loadServerModuleMain: devServer.loadServerModuleMain,
}
: {
isDev: false,
Expand Down
8 changes: 3 additions & 5 deletions packages/waku/src/lib/middleware/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,10 @@ export type HandlerContext = {
readonly context: Record<string, unknown>;
unstable_devServer?: {
rootDir: string;
resolveClientEntryDev: (id: string) => string;
loadServerFileRsc: (fileURL: string) => Promise<Record<string, any>>;
loadServerModuleRsc: (id: string) => Promise<Record<string, any>>;
resolveClientEntry: (id: string) => string;
loadServerModuleRsc: (idOrFileURL: string) => Promise<Record<string, any>>;
loadEntriesDev: (config: { srcDir: string }) => Promise<EntriesDev>;
loadServerFileMain: (fileURL: string) => Promise<Record<string, any>>;
loadServerModuleMain: (id: string) => Promise<Record<string, any>>;
loadServerModuleMain: (idOrFileURL: string) => Promise<Record<string, any>>;
transformIndexHtml: (
pathname: string,
) => Promise<TransformStream<any, any>>;
Expand Down
11 changes: 11 additions & 0 deletions packages/waku/src/lib/plugins/vite-plugin-rsc-env.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import type { Plugin } from 'vite';
import * as dotenv from 'dotenv';

export function rscEnvPlugin({
isDev,
config,
}: {
isDev: boolean;
config?: {
basePath: string;
rscPath: string;
Expand All @@ -11,6 +14,14 @@ export function rscEnvPlugin({
return {
name: 'rsc-env-plugin',
config(viteConfig) {
if (isDev) {
dotenv.config({
path: ['.env.local', '.env'],
processEnv: (globalThis as any).__WAKU_PRIVATE_ENV__,
override: true,
});
}

viteConfig.define = {
...viteConfig.define,
...Object.fromEntries([
Expand Down
2 changes: 1 addition & 1 deletion packages/waku/src/lib/plugins/vite-plugin-rsc-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ ${opts.htmlHead}
// HACK: vite won't inject __vite__injectQuery anymore
// Vite optimizes `import()` so it adds `?import` to imported urls. That'd cause double module hazard! This way, I hack it to use a global function so it does not get optimized.
children: `
globalThis.__WAKU_HACK_IMPORT__ = (id) => import(id);
globalThis.__WAKU_CLIENT_HACK_IMPORT__ = (id) => import(id);
`,
},
...(opts.cssAssets || []).map((href) => ({
Expand Down
2 changes: 1 addition & 1 deletion packages/waku/src/lib/plugins/vite-plugin-rsc-rsdw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ globalThis.__WAKU_${type}_MODULE_LOADING__ ||= new Map();
globalThis.__WAKU_${type}_MODULE_CACHE__ ||= new Map();
globalThis.__WAKU_${type}_CHUNK_LOAD__ ||= (
id,
customImport = globalThis.__WAKU_HACK_IMPORT__
customImport = globalThis.__WAKU_${type}_HACK_IMPORT__
) => {
if (!globalThis.__WAKU_${type}_MODULE_LOADING__.has(id)) {
globalThis.__WAKU_${type}_MODULE_LOADING__.set(
Expand Down
15 changes: 4 additions & 11 deletions packages/waku/src/lib/renderers/html-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,7 @@ export const renderHtml = async (
| {
isDev: true;
rootDir: string;
loadServerFile: (fileURL: string) => Promise<unknown>;
loadServerModule: (id: string) => Promise<unknown>;
loadServerModuleMain: (idOrFileURL: string) => Promise<unknown>;
}
),
): Promise<ReadableStream | null> => {
Expand All @@ -214,7 +213,7 @@ export const renderHtml = async (

const loadClientModule = <T>(key: keyof typeof CLIENT_MODULE_MAP) =>
(isDev
? opts.loadServerModule(CLIENT_MODULE_MAP[key])
? opts.loadServerModuleMain(CLIENT_MODULE_MAP[key])
: opts.loadModule(CLIENT_PREFIX + key)) as Promise<T>;

const [
Expand Down Expand Up @@ -278,17 +277,11 @@ export const renderHtml = async (
fileWithAbsolutePath
.slice(wakuDist.length)
.replace(/\.\w+$/, '');
(globalThis as any).__WAKU_CLIENT_CHUNK_LOAD__(
id,
(id: string) => opts.loadServerModule(id),
);
(globalThis as any).__WAKU_CLIENT_CHUNK_LOAD__(id);
return { id, chunks: [id], name };
}
const id = filePathToFileURL(file);
(globalThis as any).__WAKU_CLIENT_CHUNK_LOAD__(
id,
(id: string) => opts.loadServerFile(id),
);
(globalThis as any).__WAKU_CLIENT_CHUNK_LOAD__(id);
return { id, chunks: [id], name };
}
// !isDev
Expand Down
5 changes: 2 additions & 3 deletions packages/waku/src/lib/renderers/rsc-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ type RenderRscOpts =
| {
isDev: true;
entries: EntriesDev;
loadServerFileRsc: (fileURL: string) => Promise<unknown>;
loadServerModuleRsc: (id: string) => Promise<unknown>;
loadServerModuleRsc: (idOrFileURL: string) => Promise<unknown>;
resolveClientEntry: (id: string) => string;
};

Expand Down Expand Up @@ -212,7 +211,7 @@ export async function renderRsc(
const [fileId, name] = rsfId.split('#') as [string, string];
let mod: any;
if (isDev) {
mod = await opts.loadServerFileRsc(filePathToFileURL(fileId));
mod = await opts.loadServerModuleRsc(filePathToFileURL(fileId));
} else {
if (!fileId.startsWith('@id/')) {
throw new Error('Unexpected server entry in PRD');
Expand Down
Loading

0 comments on commit 0c4b5b9

Please sign in to comment.