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

breaking: string only waku.config.ts #1281

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 10 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
10 changes: 5 additions & 5 deletions e2e/fixtures/broken-links/waku.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { defineConfig } from 'waku/config';

export default defineConfig({
middleware: () => [
import('waku/middleware/context'),
import('./src/redirects.js'),
import('waku/middleware/dev-server'),
import('waku/middleware/handler'),
middleware: [
'waku/middleware/context',
'./src/redirects.js',
'waku/middleware/dev-server',
'waku/middleware/handler',
],
});
10 changes: 5 additions & 5 deletions e2e/fixtures/rsc-basic/waku.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { defineConfig } from 'waku/config';

export default defineConfig({
middleware: () => [
import('waku/middleware/context'),
import('waku/middleware/dev-server'),
import('waku/middleware/handler'),
import('waku/middleware/fallback'),
middleware: [
'waku/middleware/context',
'waku/middleware/dev-server',
'waku/middleware/handler',
'waku/middleware/fallback',
],
});
10 changes: 5 additions & 5 deletions e2e/fixtures/rsc-css-modules/waku.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { defineConfig } from 'waku/config';

export default defineConfig({
middleware: () => [
import('waku/middleware/context'),
import('waku/middleware/dev-server'),
import('waku/middleware/handler'),
import('waku/middleware/fallback'),
middleware: [
'waku/middleware/context',
'waku/middleware/dev-server',
'waku/middleware/handler',
'waku/middleware/fallback',
],
});
10 changes: 5 additions & 5 deletions e2e/fixtures/ssr-catch-error/waku.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { defineConfig } from 'waku/config';

export default defineConfig({
middleware: () => [
import('waku/middleware/context'),
import('waku/middleware/dev-server'),
import('./src/middleware/validator.js'),
import('waku/middleware/handler'),
middleware: [
'waku/middleware/context',
'waku/middleware/dev-server',
'./src/middleware/validator.js',
'waku/middleware/handler',
],
/**
* Base path for HTTP requests to indicate RSC requests.
Expand Down
39 changes: 8 additions & 31 deletions examples/07_cloudflare/waku.config.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,15 @@
import type { Hono } from 'hono';
import { type Config, defineConfig } from 'waku/config';
import { defineConfig } from 'waku/config';

export default defineConfig({
...(import.meta.env && !import.meta.env.PROD
? {
unstable_honoEnhancer: ((createApp: (app: Hono) => Hono) => {
const handlerPromise = import('./waku.cloudflare-dev-server').then(
({ cloudflareDevServer }) =>
cloudflareDevServer({
// Optional config settings for the Cloudflare dev server (wrangler proxy)
// https://developers.cloudflare.com/workers/wrangler/api/#parameters-1
persist: {
path: '.wrangler/state/v3',
},
}),
);
return (appToCreate: Hono) => {
const app = createApp(appToCreate);
return {
fetch: async (req: Request) => {
const devHandler = await handlerPromise;
return devHandler(req, app);
},
};
};
}) as Config['unstable_honoEnhancer'],
unstable_honoEnhancer: './waku.hono-enhancer',
}
: {}),
middleware: () => {
return [
import('waku/middleware/context'),
import('waku/middleware/dev-server'),
import('./waku.cloudflare-middleware'),
import('waku/middleware/handler'),
];
},
middleware: [
'waku/middleware/context',
'waku/middleware/dev-server',
'./waku.cloudflare-middleware',
'waku/middleware/handler',
],
});
25 changes: 25 additions & 0 deletions examples/07_cloudflare/waku.hono-enhancer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { Hono } from 'hono';

const honoEnhancer = (createApp: (app: Hono) => Hono) => {
const handlerPromise = import('./waku.cloudflare-dev-server').then(
({ cloudflareDevServer }) =>
cloudflareDevServer({
// Optional config settings for the Cloudflare dev server (wrangler proxy)
// https://developers.cloudflare.com/workers/wrangler/api/#parameters-1
persist: {
path: '.wrangler/state/v3',
},
}),
);
return (appToCreate: Hono) => {
const app = createApp(appToCreate);
return {
fetch: async (req: Request) => {
const devHandler = await handlerPromise;
return devHandler(req, app);
},
};
};
};

export default honoEnhancer;
10 changes: 5 additions & 5 deletions examples/12_nossr/waku.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { defineConfig } from 'waku/config';

export default defineConfig({
middleware: () => [
import('waku/middleware/context'),
import('waku/middleware/dev-server'),
import('waku/middleware/handler'),
import('waku/middleware/fallback'),
middleware: [
'waku/middleware/context',
'waku/middleware/dev-server',
'waku/middleware/handler',
'waku/middleware/fallback',
],
});
10 changes: 5 additions & 5 deletions examples/38_cookies/waku.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { defineConfig } from 'waku/config';

export default defineConfig({
middleware: () => [
import('waku/middleware/context'),
import('./src/middleware/cookie.js'),
import('waku/middleware/dev-server'),
import('waku/middleware/handler'),
middleware: [
'waku/middleware/context',
'./src/middleware/cookie.js',
'waku/middleware/dev-server',
'waku/middleware/handler',
],
});
10 changes: 5 additions & 5 deletions examples/51_spa/waku.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { defineConfig } from 'waku/config';

export default defineConfig({
middleware: () => [
import('waku/middleware/context'),
import('waku/middleware/dev-server'),
import('waku/middleware/handler'),
import('waku/middleware/fallback'),
middleware: [
'waku/middleware/context',
'waku/middleware/dev-server',
'waku/middleware/handler',
'waku/middleware/fallback',
],
});
10 changes: 5 additions & 5 deletions examples/52_tanstack-router/waku.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { defineConfig } from 'waku/config';

export default defineConfig({
middleware: () => [
import('waku/middleware/context'),
import('waku/middleware/dev-server'),
import('waku/middleware/handler'),
import('waku/middleware/fallback'),
middleware: [
'waku/middleware/context',
'waku/middleware/dev-server',
'waku/middleware/handler',
'waku/middleware/fallback',
],
});
26 changes: 19 additions & 7 deletions packages/waku/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@ if (values.version) {

async function runDev() {
const config = await loadConfig();
const honoEnhancer =
config.unstable_honoEnhancer || ((createApp) => createApp);
const honoEnhancer: HonoEnhancer = config.unstable_honoEnhancer
? await loadHonoEnhancer(config.unstable_honoEnhancer)
: (fn) => fn;
const createApp = (app: Hono) => {
if (values['experimental-compress']) {
app.use(compress());
Expand Down Expand Up @@ -147,8 +148,9 @@ async function runBuild() {
async function runStart() {
const config = await loadConfig();
const { distDir = 'dist' } = config;
const honoEnhancer =
config.unstable_honoEnhancer || ((createApp) => createApp);
const honoEnhancer: HonoEnhancer = config.unstable_honoEnhancer
? await loadHonoEnhancer(config.unstable_honoEnhancer)
: (fn) => fn;
const loadEntries = () =>
import(pathToFileURL(path.resolve(distDir, DIST_ENTRIES_JS)).toString());
const createApp = (app: Hono) => {
Expand Down Expand Up @@ -220,7 +222,17 @@ async function loadConfig(): Promise<Config> {
if (!existsSync(CONFIG_FILE)) {
return {};
}
const { loadServerFile } = await import('./lib/utils/vite-loader.js');
const file = pathToFileURL(path.resolve(CONFIG_FILE)).toString();
return (await loadServerFile(file)).default;
const { loadServerModule } = await import('./lib/utils/vite-loader.js');
const fileUrl = pathToFileURL(path.resolve(CONFIG_FILE)).toString();
return (await loadServerModule<{ default: Config }>(fileUrl)).default;
}

type HonoEnhancer = <Hono>(fn: (app: Hono) => Hono) => (app: Hono) => Hono;

async function loadHonoEnhancer(file: string): Promise<HonoEnhancer> {
const { loadServerModule } = await import('./lib/utils/vite-loader.js');
const fileUrl = pathToFileURL(
path.resolve(CONFIG_FILE, '..', file),
).toString();
return (await loadServerModule<{ default: HonoEnhancer }>(fileUrl)).default;
}
14 changes: 6 additions & 8 deletions packages/waku/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,18 @@ export interface Config {
/**
* Middleware to use
* Defaults to:
* () => [
* import('waku/middleware/context'),
* import('waku/middleware/dev-server'),
* import('waku/middleware/handler'),
* [
* 'waku/middleware/context',
* 'waku/middleware/dev-server',
* 'waku/middleware/handler',
* ]
*/
middleware?: () => Promise<{ default: Middleware }>[];
middleware?: string[];
/**
* Enhancer for Hono
* Defaults to `undefined`
*/
unstable_honoEnhancer?:
| (<Hono>(createApp: (app: Hono) => Hono) => (app: Hono) => Hono)
| undefined;
unstable_honoEnhancer?: string | undefined;
/**
* Vite configuration options.
* `common` can contains shared configs that are shallowly merged with other configs.
Expand Down
2 changes: 2 additions & 0 deletions packages/waku/src/lib/builder/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ const buildServerBundle = async (
rscEntriesPlugin({
basePath: config.basePath,
rscBase: config.rscBase,
middleware: config.middleware,
rootDir,
srcDir: config.srcDir,
ssrDir: DIST_SSR,
moduleMap: {
Expand Down
8 changes: 4 additions & 4 deletions packages/waku/src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import type { Config } from '../config.js';

export type ConfigDev = Required<Config>;

const DEFAULT_MIDDLEWARE = () => [
import('waku/middleware/context'),
import('waku/middleware/dev-server'),
import('waku/middleware/handler'),
const DEFAULT_MIDDLEWARE = [
'waku/middleware/context',
'waku/middleware/dev-server',
'waku/middleware/handler',
];

// Keep async function for future extension
Expand Down
51 changes: 34 additions & 17 deletions packages/waku/src/lib/hono/engine.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,26 @@
import type { MiddlewareHandler } from 'hono';

import type { ConfigDev } from '../config.js';
import { resolveConfigDev } from '../config.js';
import type { HandlerContext, MiddlewareOptions } from '../middleware/types.js';
import type {
HandlerContext,
Middleware,
MiddlewareOptions,
} from '../middleware/types.js';

// Internal context key
const HONO_CONTEXT = '__hono_context';

// serverEngine returns hono middleware that runs Waku middleware.
export const serverEngine = (options: MiddlewareOptions): MiddlewareHandler => {
const entriesPromise =
const middlewarePromise: Promise<{ default: Middleware }[]> =
options.cmd === 'start'
? options.loadEntries()
: ('Error: loadEntries are not available' as never);
const configPromise =
options.cmd === 'start'
? entriesPromise.then((entries) =>
// TODO eliminate loadConfig
entries.loadConfig().then((config) => resolveConfigDev(config)),
)
: resolveConfigDev(options.config);
const handlersPromise = configPromise.then((config) =>
Promise.all(
config
.middleware()
.map(async (middleware) => (await middleware).default(options)),
),
? options.loadEntries().then((entries) => entries.loadMiddleware())
: resolveConfigDev(options.config).then((config) =>
loadMiddlewareDev(config),
);
const handlersPromise = middlewarePromise.then((middlewareList) =>
middlewareList.map((middleware) => middleware.default(options)),
);
return async (c, next) => {
const ctx: HandlerContext = {
Expand Down Expand Up @@ -67,3 +63,24 @@ export const serverEngine = (options: MiddlewareOptions): MiddlewareHandler => {
await next();
};
};

const DO_NOT_BUNDLE = '';

async function loadMiddlewareDev(
configDev: ConfigDev,
): Promise<{ default: Middleware }[]> {
const [{ resolve }, { pathToFileURL }, { loadServerModule }] =
await Promise.all([
import(/* @vite-ignore */ DO_NOT_BUNDLE + 'node:path'),
import(/* @vite-ignore */ DO_NOT_BUNDLE + 'node:url'),
import(/* @vite-ignore */ DO_NOT_BUNDLE + '../utils/vite-loader.js'),
]);
return Promise.all(
configDev.middleware.map(async (file) => {
const idOrFileURL = file.startsWith('./')
? pathToFileURL(resolve(file)).toString()
: file;
return loadServerModule(idOrFileURL);
}),
);
}
Loading
Loading