Skip to content

Commit bf83462

Browse files
committed
feat: clone stream for hono bff
1 parent bc49b88 commit bf83462

File tree

29 files changed

+186
-124
lines changed

29 files changed

+186
-124
lines changed

Diff for: packages/cli/core/src/types/context.ts

+5
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,9 @@ export interface IAppContext {
8383
* @private
8484
*/
8585
partialsByEntrypoint?: Record<string, HtmlPartials>;
86+
/**
87+
* Identification for bff runtime framework
88+
* @private
89+
*/
90+
bffRuntimeFramework?: string;
8691
}

Diff for: packages/cli/plugin-bff/src/cli.ts

+15-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import type { AppTools, CliPlugin } from '@modern-js/app-tools';
33
import { ApiRouter } from '@modern-js/bff-core';
44
import { compile } from '@modern-js/server-utils';
55
import type { ServerRoute } from '@modern-js/types';
6-
import { fs, API_DIR, SHARED_DIR, normalizeOutputPath } from '@modern-js/utils';
6+
import {
7+
fs,
8+
API_DIR,
9+
SHARED_DIR,
10+
isProd,
11+
normalizeOutputPath,
12+
} from '@modern-js/utils';
713
import clientGenerator from './utils/clientGenerator';
814
import pluginGenerator from './utils/pluginGenerator';
915
import runtimeGenerator from './utils/runtimeGenerator';
@@ -15,11 +21,6 @@ const RUNTIME_CREATE_REQUEST = '@modern-js/plugin-bff/runtime/create-request';
1521
export const bffPlugin = (): CliPlugin<AppTools> => ({
1622
name: '@modern-js/plugin-bff',
1723
setup: api => {
18-
const useConfig = api.useConfigContext();
19-
20-
useConfig.bff ??= {};
21-
(useConfig.bff as any).runtimeFramework = 'hono';
22-
2324
const compileApi = async () => {
2425
const {
2526
appDirectory,
@@ -130,15 +131,17 @@ export const bffPlugin = (): CliPlugin<AppTools> => ({
130131
}
131132
};
132133

134+
const isHono = () => {
135+
const { bffRuntimeFramework } = api.useAppContext();
136+
return bffRuntimeFramework === 'hono';
137+
};
138+
133139
return {
134140
config() {
135141
const useConfig = api.useConfigContext();
136-
const { bff } = useConfig ?? {};
137-
const isHono = (bff as any)?.runtimeFramework === 'hono';
138-
const isDev = process.env.NODE_ENV === 'development';
139-
const useLocalRuntime = isDev && !useConfig?.bff?.crossProject;
142+
const useLocalRuntime = !isProd() && !useConfig?.bff?.crossProject;
140143

141-
const runtimePath = isHono
144+
const runtimePath = isHono()
142145
? useLocalRuntime
143146
? require.resolve('@modern-js/plugin-bff/runtime')
144147
: '@modern-js/plugin-bff/runtime'
@@ -227,7 +230,7 @@ export const bffPlugin = (): CliPlugin<AppTools> => ({
227230
isSSR: false,
228231
})) as ServerRoute[];
229232

230-
if ((bff as any).runtimeFramework !== 'hono' && bff?.enableHandleWeb) {
233+
if (!isHono() && bff?.enableHandleWeb) {
231234
return {
232235
routes: (
233236
routes.map(route => {

Diff for: packages/cli/plugin-bff/src/runtime/hono.ts

+4-21
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@ import createHonoRoutes from '../utils/createHonoRoutes';
88

99
const before = ['custom-server-hook', 'custom-server-middleware', 'render'];
1010

11-
type SF = (args: any) => void;
12-
1311
interface MiddlewareOptions {
1412
prefix: string;
1513
enableHandleWeb?: boolean;
16-
customMiddlewares: SF[];
1714
}
1815

1916
export class HonoRuntime {
@@ -54,10 +51,11 @@ export class HonoRuntime {
5451
};
5552

5653
registerMiddleware = async (options: MiddlewareOptions) => {
57-
const { prefix, enableHandleWeb, customMiddlewares } = options;
54+
const { prefix } = options;
55+
56+
const { bffRuntimeFramework } = this.api.useAppContext();
5857

59-
const { bff } = this.api.useConfigContext();
60-
if ((bff as any)?.runtimeFramework !== 'hono') {
58+
if (bffRuntimeFramework !== 'hono') {
6159
this.isHono = false;
6260
return;
6361
}
@@ -80,21 +78,6 @@ export class HonoRuntime {
8078
before,
8179
});
8280

83-
(customMiddlewares as unknown as MiddlewareHandler[]).forEach(handler => {
84-
globalMiddlewares.push({
85-
name: 'bff-custom-middleware',
86-
handler: (c: Context, next: Next) => {
87-
if (c.req.path.startsWith(prefix || '/api') || enableHandleWeb) {
88-
return handler(c, next);
89-
} else {
90-
return next();
91-
}
92-
},
93-
order: 'post',
94-
before,
95-
});
96-
});
97-
9881
await this.setHandlers();
9982

10083
if (isProd()) {

Diff for: packages/cli/plugin-bff/src/server.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import path from 'path';
22
import { ApiRouter } from '@modern-js/bff-core';
3-
import type { PluginAPI, ServerPlugin } from '@modern-js/server-core';
3+
import type { ServerPlugin } from '@modern-js/server-core';
44
import type { ServerNodeMiddleware } from '@modern-js/server-core/node';
55
import {
66
API_DIR,
@@ -107,7 +107,6 @@ export default (): ServerPlugin => ({
107107
}
108108

109109
honoRuntime.registerMiddleware({
110-
customMiddlewares: middlewares,
111110
prefix,
112111
enableHandleWeb,
113112
});

Diff for: packages/cli/plugin-bff/src/utils/createHonoRoutes.ts

+37-13
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,12 @@ const getHonoInput = async (c: Context) => {
112112
const contentType = c.req.header('content-type') || '';
113113
if (typeIs.is(contentType, ['application/json'])) {
114114
try {
115-
draft.data = await c.req.json();
115+
draft.data = await resolveData(c);
116116
} catch {
117117
draft.data = {};
118118
}
119119
} else if (typeIs.is(contentType, ['multipart/form-data'])) {
120-
const formData = await resolveHonoFormData(c);
121-
draft.formData = formData;
120+
draft.formData = await resolveFormData(c);
122121
} else if (typeIs.is(contentType, ['application/x-www-form-urlencoded'])) {
123122
draft.formUrlencoded = await c.req.parseBody();
124123
} else {
@@ -130,20 +129,45 @@ const getHonoInput = async (c: Context) => {
130129
return draft;
131130
};
132131

133-
const resolveHonoFormData = (c: Context): Promise<Record<string, any>> => {
134-
const form = formidable({ multiples: true });
132+
const resolveFormData = (c: Context): Promise<Record<string, any>> => {
135133
return new Promise((resolve, reject) => {
136-
form.parse(c.env.node?.req, (err, fields, files) => {
137-
if (err) {
138-
reject(err);
139-
}
134+
try {
135+
const nodeReadable = c.env.node?.req;
140136

141-
resolve({
142-
...fields,
143-
...files,
137+
if (!c.env.node?.req) return {};
138+
139+
nodeReadable.headers = {
140+
'content-type': c.env.node.req.headers['content-type'],
141+
'content-length': c.env.node.req.headers['content-length'],
142+
};
143+
const form = formidable({
144+
multiples: true,
144145
});
145-
});
146+
147+
form.parse(nodeReadable, (err, fields, files) => {
148+
if (err) reject(err);
149+
resolve({ ...fields, ...files });
150+
});
151+
} catch (error) {
152+
reject(error);
153+
}
146154
});
147155
};
148156

157+
async function resolveData(c: Context): Promise<Record<string, any>> {
158+
try {
159+
const nodeReadable = c.env.node?.req;
160+
if (!c.env.node?.req) return {};
161+
162+
let data = '';
163+
for await (const chunk of nodeReadable) {
164+
data += chunk.toString('utf8');
165+
}
166+
167+
return JSON.parse(data);
168+
} catch (error) {
169+
return {};
170+
}
171+
}
172+
149173
export default createHonoRoutes;

Diff for: packages/cli/plugin-bff/tests/__snapshots__/cli.test.ts.snap

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ exports[`bff cli plugin config 1`] = `
44
[
55
{
66
"source": {
7+
"alias": undefined,
78
"moduleScopes": [
89
"api",
910
/create-request/,

Diff for: packages/server/core/src/adapters/node/node.ts

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ const getRequestListener = (handler: RequestHandler) => {
114114
return async (req: NodeRequest, res: NodeResponse) => {
115115
try {
116116
const request = createWebRequest(req, res);
117+
117118
const response = await handler(request, {
118119
node: {
119120
req,

Diff for: packages/server/core/src/serverBase.ts

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export type ServerBaseOptions = {
3232
sharedDirectory?: string;
3333
apiDirectory?: string;
3434
lambdaDirectory?: string;
35+
bffRuntimeFramework?: string;
3536
};
3637
runMode?: 'apiOnly' | 'ssrOnly' | 'webOnly';
3738
};
@@ -102,6 +103,7 @@ export class ServerBase<E extends Env = any> {
102103
plugins: [],
103104
metaName: metaName || 'modern-js',
104105
serverBase: this,
106+
bffRuntimeFramework: context.bffRuntimeFramework,
105107
} as any;
106108

107109
return createContext<ISAppContext>(appContext);

Diff for: packages/server/create-request/src/browser.ts

-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ export const createUploader: UploadCreator = ({
162162
const fetcher = realRequest.get(requestId) || originFetch;
163163

164164
const { body, headers } = getUploadPayload(args);
165-
console.log('up headers', headers);
166165

167166
const configDomain = domainMap.get(requestId);
168167
const finalURL = `${configDomain || domain || ''}${path}`;

Diff for: packages/server/plugin-express/src/cli/index.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ export const expressPlugin = (): CliPlugin<AppTools> => ({
1212

1313
const useConfig = api.useConfigContext();
1414

15-
useConfig.bff ??= {};
16-
(useConfig.bff as any).runtimeFramework = 'express';
15+
const appContext = api.useAppContext();
16+
17+
api.setAppContext({
18+
...appContext,
19+
bffRuntimeFramework: 'express',
20+
});
1721

1822
return {
1923
config() {

Diff for: packages/server/plugin-koa/src/cli/index.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ export const koaPlugin = (): CliPlugin<AppTools> => ({
1111
const runtimeModulePath = path.resolve(__dirname, '../runtime');
1212
const useConfig = api.useConfigContext();
1313

14-
useConfig.bff ??= {};
15-
(useConfig.bff as any).runtimeFramework = 'koa';
14+
const appContext = api.useAppContext();
15+
16+
api.setAppContext({
17+
...appContext,
18+
bffRuntimeFramework: 'koa',
19+
});
1620

1721
return {
1822
config() {

Diff for: packages/solutions/app-tools/src/commands/dev.ts

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export const dev = async (
110110
apiDirectory: appContext.apiDirectory,
111111
lambdaDirectory: appContext.lambdaDirectory,
112112
sharedDirectory: appContext.sharedDirectory,
113+
bffRuntimeFramework: appContext.bffRuntimeFramework,
113114
},
114115
serverConfigPath,
115116
routes: serverRoutes,

Diff for: packages/solutions/app-tools/src/commands/serve.ts

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export const serve = async (
9595
appContext.appDirectory,
9696
appContext.distDirectory,
9797
),
98+
bffRuntimeFramework: appContext.bffRuntimeFramework,
9899
},
99100
runMode,
100101
});

Diff for: packages/solutions/app-tools/src/types/new.ts

+5
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ export interface AppToolsExtendContext<B extends Bundler = 'webpack'> {
162162
* @deprecated compat old plugin, default is app tools
163163
*/
164164
toolsType?: string;
165+
/**
166+
* Identification for bff runtime framework
167+
* @private
168+
*/
169+
bffRuntimeFramework?: string;
165170
}
166171

167172
export type AppToolsContext<B extends Bundler = 'webpack'> = AppContext<

Diff for: packages/solutions/app-tools/src/utils/initAppContext.ts

+1
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,6 @@ export const initAppContext = ({
5151
apiOnly: false,
5252
internalDirAlias: `@_${metaName.replace(/-/g, '_')}_internal`,
5353
internalSrcAlias: `@_${metaName.replace(/-/g, '_')}_src`,
54+
bffRuntimeFramework: 'hono',
5455
};
5556
};

Diff for: pnpm-lock.yaml

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: tests/integration/bff-corss-project/bff-api-app/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,4 @@
9393
"dist-1/runtime/**/*",
9494
"dist-1/plugin/**/*"
9595
]
96-
}
96+
}

Diff for: tests/integration/bff-hono/CHANGELOG.md

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# bff-express
2-
31
## 2.65.2
42

53
### Patch Changes

Diff for: tests/integration/bff-hono/api/_app.ts

-9
This file was deleted.

Diff for: tests/integration/bff-hono/api/context/index.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { useContext } from '@modern-js/runtime/server';
2+
3+
export default async () => {
4+
const ctx = useContext();
5+
const { res } = ctx;
6+
res.headers.set('x-id', '1');
7+
return {
8+
message: 'Hello Modern.js',
9+
};
10+
};

Diff for: tests/integration/bff-hono/api/index.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ import {
1212
} from '@modern-js/runtime/server';
1313
import { z } from 'zod';
1414

15-
export default async () => ({
16-
message: 'Hello Modern.js',
17-
});
15+
export default async () => {
16+
return {
17+
message: 'Hello Modern.js',
18+
};
19+
};
1820

1921
export const post = async ({ formUrlencoded }: { formUrlencoded: any }) => {
2022
return {
@@ -37,7 +39,6 @@ const ParamsSchema = z.object({
3739

3840
const HeadersSchema = z.object({
3941
'x-header': z.string(),
40-
'x-parse-through-body': z.string(),
4142
});
4243

4344
export const postHello = Api(

Diff for: tests/integration/bff-hono/modern.config.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ export default applyBaseConfig({
77
ssr: true,
88
},
99
bff: {
10-
prefix: '/bff-hono',
11-
enableHandleWeb: true,
10+
prefix: '/bff-api',
11+
// enableHandleWeb: true,
1212
// crossProject: true,
1313
},
1414
plugins: [bffPlugin(), serverPlugin()],

Diff for: tests/integration/bff-hono/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
"@types/react": "^18.3.11",
3232
"@types/react-dom": "^18.3.1",
3333
"typescript": "^5",
34-
"ts-node": "~10.8.1",
3534
"tsconfig-paths": "~3.14.1"
3635
},
3736
"exports": {

0 commit comments

Comments
 (0)