Skip to content

Commit 0386830

Browse files
committed
feat: resolve cr issues
1 parent d18dea2 commit 0386830

File tree

31 files changed

+299
-247
lines changed

31 files changed

+299
-247
lines changed

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
}

packages/cli/plugin-bff/package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"default": "./dist/cjs/loader.js"
4545
},
4646
"./runtime": {
47-
"types": "./dist/types/index.d.ts",
47+
"types": "./dist/types/runtime/index.d.ts",
4848
"jsnext:source": "./src/runtime/index.ts",
4949
"default": "./dist/cjs/runtime/index.js"
5050
},
@@ -65,6 +65,9 @@
6565
"server": [
6666
"./dist/types/server.d.ts"
6767
],
68+
"runtime": [
69+
"./dist/types/runtime/index.d.ts"
70+
],
6871
"runtime/create-request": [
6972
"./dist/types/runtime/create-request/index.d.ts"
7073
]

packages/cli/plugin-bff/src/cli.ts

+22-19
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,18 +131,22 @@ 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;
140-
141-
const runtimePath = isHono
142-
? useLocalRuntime
143-
? require.resolve('@modern-js/plugin-bff/runtime')
144-
: '@modern-js/plugin-bff/runtime'
142+
const useLocalRuntime = !isProd() && !useConfig?.bff?.crossProject;
143+
144+
const runtimePath = useLocalRuntime
145+
? require.resolve('@modern-js/plugin-bff/runtime')
146+
: '@modern-js/plugin-bff/runtime';
147+
148+
const alias = isHono()
149+
? { '@modern-js/runtime/server': runtimePath }
145150
: undefined;
146151

147152
return {
@@ -200,9 +205,7 @@ export const bffPlugin = (): CliPlugin<AppTools> => ({
200205
},
201206
source: {
202207
moduleScopes: [`./${API_DIR}`, /create-request/],
203-
alias: runtimePath
204-
? { '@modern-js/runtime/server': runtimePath }
205-
: undefined,
208+
alias,
206209
},
207210
};
208211
},
@@ -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 => {

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()) {

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
});

packages/cli/plugin-bff/src/utils/createHonoRoutes.ts

+60-15
Original file line numberDiff line numberDiff line change
@@ -110,40 +110,85 @@ const getHonoInput = async (c: Context) => {
110110

111111
try {
112112
const contentType = c.req.header('content-type') || '';
113+
113114
if (typeIs.is(contentType, ['application/json'])) {
114115
try {
115-
draft.data = await c.req.json();
116+
const rawBody = await resolveRawBody(c);
117+
const decodedBody = decodeBuffer(rawBody, contentType);
118+
draft.data = safeJsonParse(decodedBody);
116119
} catch {
117120
draft.data = {};
118121
}
119122
} else if (typeIs.is(contentType, ['multipart/form-data'])) {
120-
const formData = await resolveHonoFormData(c);
121-
draft.formData = formData;
123+
draft.formData = await resolveFormData(c);
122124
} else if (typeIs.is(contentType, ['application/x-www-form-urlencoded'])) {
123-
draft.formUrlencoded = await c.req.parseBody();
125+
const rawBody = await resolveRawBody(c);
126+
const decodedBody = decodeBuffer(rawBody, contentType);
127+
draft.formUrlencoded = parseUrlEncoded(decodedBody);
124128
} else {
125-
draft.body = await c.req.parseBody();
129+
const rawBody = await resolveRawBody(c);
130+
draft.body = rawBody.toString('utf8');
126131
}
127132
} catch (error) {
128133
draft.body = null;
129134
}
130135
return draft;
131136
};
132137

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

141-
resolve({
142-
...fields,
143-
...files,
143+
if (!c.env.node?.req) return {};
144+
145+
nodeReadable.headers = {
146+
'content-type': c.env.node.req.headers['content-type'],
147+
'content-length': c.env.node.req.headers['content-length'],
148+
};
149+
const form = formidable({
150+
multiples: true,
144151
});
145-
});
152+
153+
form.parse(nodeReadable, (err, fields, files) => {
154+
if (err) reject(err);
155+
resolve({ ...fields, ...files });
156+
});
157+
} catch (error) {
158+
reject(error);
159+
}
146160
});
147161
};
148162

163+
async function resolveRawBody(c: Context): Promise<Buffer> {
164+
const nodeReadable = c.env.node?.req;
165+
if (!nodeReadable) return Buffer.from('');
166+
167+
const chunks: Buffer[] = [];
168+
for await (const chunk of nodeReadable) {
169+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
170+
}
171+
return Buffer.concat(chunks as any);
172+
}
173+
174+
function decodeBuffer(body: Buffer, contentType: string): string {
175+
const charset = contentType.match(/charset=([\w-]+)/)?.[1] || 'utf8';
176+
return body.toString(charset as BufferEncoding);
177+
}
178+
179+
function parseUrlEncoded(data: string): Record<string, any> {
180+
const params = new URLSearchParams(data);
181+
return Object.fromEntries(params.entries());
182+
}
183+
184+
function safeJsonParse(data: string): Record<string, any> {
185+
if (!data.trim()) return {};
186+
try {
187+
return JSON.parse(data);
188+
} catch (error) {
189+
const { message } = error as Error;
190+
throw new Error(`Invalid JSON: ${message ? message : 'parse error'}`);
191+
}
192+
}
193+
149194
export default createHonoRoutes;

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/,

packages/cli/plugin-bff/types/runtime.d.ts

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
declare module '@modern-js/runtime/server' {
2-
import type { Request, Response, RequestHandler } from 'express';
32
import type { Context, MiddlewareHandler, Next } from 'hono';
43

54
import type {
@@ -19,8 +18,8 @@ declare module '@modern-js/runtime/server' {
1918
) => void;
2019

2120
export type Middleware = (
22-
context: MiddlewareContext,
23-
next: NextFunction,
21+
context: Context,
22+
next: Next,
2423
) => Promise<void> | void;
2524

2625
type HonoOptions = {
@@ -38,8 +37,6 @@ declare module '@modern-js/runtime/server' {
3837
export const Pipe: import('../src/runtime').Pipe;
3938
export const Middleware: import('../src/runtime').Middleware;
4039

41-
export type { RequestHandler };
42-
4340
export * from '@modern-js/bff-core';
4441
export * from '@modern-js/bff-runtime';
4542
}

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,

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);

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}`;

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() {

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() {

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,

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
});

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<

0 commit comments

Comments
 (0)