@modern-js/plugin-bff 2.69.5 → 3.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli.js +256 -272
- package/dist/cjs/constants.js +43 -34
- package/dist/cjs/index.js +55 -19
- package/dist/cjs/loader.js +69 -65
- package/dist/cjs/runtime/create-request/index.js +39 -29
- package/dist/cjs/runtime/hono/adapter.js +128 -126
- package/dist/cjs/runtime/hono/index.js +78 -30
- package/dist/cjs/runtime/hono/operators.js +64 -67
- package/dist/cjs/server.js +159 -165
- package/dist/cjs/utils/clientGenerator.js +204 -206
- package/dist/cjs/utils/createHonoRoutes.js +128 -144
- package/dist/cjs/utils/crossProjectApiPlugin.js +91 -81
- package/dist/cjs/utils/pluginGenerator.js +66 -54
- package/dist/cjs/utils/runtimeGenerator.js +67 -45
- package/dist/esm/cli.mjs +214 -0
- package/dist/esm/constants.mjs +11 -0
- package/dist/esm/loader.mjs +39 -0
- package/dist/esm/runtime/create-request/{index.js → index.mjs} +1 -5
- package/dist/esm/runtime/hono/adapter.mjs +95 -0
- package/dist/{esm-node/runtime/hono/index.js → esm/runtime/hono/index.mjs} +2 -4
- package/dist/esm/runtime/hono/operators.mjs +31 -0
- package/dist/esm/server.mjs +122 -0
- package/dist/esm/utils/clientGenerator.mjs +175 -0
- package/dist/esm/utils/createHonoRoutes.mjs +91 -0
- package/dist/esm/utils/crossProjectApiPlugin.mjs +34 -0
- package/dist/esm/utils/pluginGenerator.mjs +29 -0
- package/dist/esm/utils/runtimeGenerator.mjs +43 -0
- package/dist/esm-node/cli.mjs +214 -0
- package/dist/esm-node/constants.mjs +11 -0
- package/dist/esm-node/index.mjs +1 -0
- package/dist/esm-node/loader.mjs +39 -0
- package/dist/esm-node/runtime/create-request/{index.js → index.mjs} +1 -5
- package/dist/esm-node/runtime/hono/adapter.mjs +95 -0
- package/dist/{esm/runtime/hono/index.js → esm-node/runtime/hono/index.mjs} +3 -5
- package/dist/esm-node/runtime/hono/operators.mjs +31 -0
- package/dist/esm-node/server.mjs +122 -0
- package/dist/esm-node/utils/clientGenerator.mjs +175 -0
- package/dist/esm-node/utils/createHonoRoutes.mjs +91 -0
- package/dist/esm-node/utils/crossProjectApiPlugin.mjs +34 -0
- package/dist/esm-node/utils/pluginGenerator.mjs +29 -0
- package/dist/esm-node/utils/runtimeGenerator.mjs +43 -0
- package/dist/types/loader.d.ts +2 -2
- package/dist/types/runtime/hono/adapter.d.ts +3 -3
- package/dist/types/server.d.ts +2 -2
- package/dist/types/utils/runtimeGenerator.d.ts +2 -1
- package/package.json +53 -31
- package/rslib.config.mts +4 -0
- package/dist/cjs/helper.js +0 -48
- package/dist/esm/cli.js +0 -425
- package/dist/esm/constants.js +0 -14
- package/dist/esm/helper.js +0 -13
- package/dist/esm/index.js +0 -1
- package/dist/esm/loader.js +0 -75
- package/dist/esm/runtime/hono/adapter.js +0 -243
- package/dist/esm/runtime/hono/operators.js +0 -79
- package/dist/esm/server.js +0 -258
- package/dist/esm/utils/clientGenerator.js +0 -517
- package/dist/esm/utils/createHonoRoutes.js +0 -319
- package/dist/esm/utils/crossProjectApiPlugin.js +0 -49
- package/dist/esm/utils/pluginGenerator.js +0 -94
- package/dist/esm/utils/runtimeGenerator.js +0 -55
- package/dist/esm-node/cli.js +0 -246
- package/dist/esm-node/constants.js +0 -14
- package/dist/esm-node/helper.js +0 -14
- package/dist/esm-node/loader.js +0 -49
- package/dist/esm-node/runtime/hono/adapter.js +0 -103
- package/dist/esm-node/runtime/hono/operators.js +0 -46
- package/dist/esm-node/server.js +0 -142
- package/dist/esm-node/utils/clientGenerator.js +0 -192
- package/dist/esm-node/utils/createHonoRoutes.js +0 -120
- package/dist/esm-node/utils/crossProjectApiPlugin.js +0 -47
- package/dist/esm-node/utils/pluginGenerator.js +0 -31
- package/dist/esm-node/utils/runtimeGenerator.js +0 -35
- package/dist/types/helper.d.ts +0 -2
- package/types.d.ts +0 -3
- /package/dist/{esm-node/index.js → esm/index.mjs} +0 -0
|
@@ -1,53 +1,68 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.n = (module)=>{
|
|
5
|
+
var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
|
|
6
|
+
__webpack_require__.d(getter, {
|
|
7
|
+
a: getter
|
|
8
|
+
});
|
|
9
|
+
return getter;
|
|
10
|
+
};
|
|
11
|
+
})();
|
|
12
|
+
(()=>{
|
|
13
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
14
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: definition[key]
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
})();
|
|
20
|
+
(()=>{
|
|
21
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
22
|
+
})();
|
|
23
|
+
(()=>{
|
|
24
|
+
__webpack_require__.r = (exports1)=>{
|
|
25
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
26
|
+
value: 'Module'
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
29
|
+
value: true
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
})();
|
|
33
|
+
var __webpack_exports__ = {};
|
|
34
|
+
__webpack_require__.r(__webpack_exports__);
|
|
35
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
36
|
+
default: ()=>utils_runtimeGenerator
|
|
32
37
|
});
|
|
33
|
-
|
|
34
|
-
var
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
const external_path_namespaceObject = require("path");
|
|
39
|
+
var external_path_default = /*#__PURE__*/ __webpack_require__.n(external_path_namespaceObject);
|
|
40
|
+
const utils_namespaceObject = require("@modern-js/utils");
|
|
41
|
+
const getPackageName = (appDirectory)=>{
|
|
42
|
+
try {
|
|
43
|
+
const packageJsonPath = external_path_default().resolve(appDirectory, './package.json');
|
|
44
|
+
const packageJson = require(packageJsonPath);
|
|
45
|
+
return packageJson.name;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
async function runtimeGenerator({ runtime, appDirectory, relativeDistPath, packageName }) {
|
|
51
|
+
const pluginDir = external_path_default().resolve(appDirectory, `./${relativeDistPath}`, 'runtime');
|
|
52
|
+
const requestId = packageName || getPackageName(appDirectory) || process.env.npm_package_name || 'default';
|
|
53
|
+
const source = `import { configure as _configure } from '${runtime}'
|
|
39
54
|
const configure = (options) => {
|
|
40
55
|
return _configure({
|
|
41
56
|
...options,
|
|
42
|
-
requestId: '${
|
|
57
|
+
requestId: '${requestId}',
|
|
43
58
|
});
|
|
44
59
|
}
|
|
45
60
|
export { configure }
|
|
46
61
|
`;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
62
|
+
const pluginPath = external_path_default().join(pluginDir, 'index.js');
|
|
63
|
+
await utils_namespaceObject.fs.ensureFile(pluginPath);
|
|
64
|
+
await utils_namespaceObject.fs.writeFile(pluginPath, source);
|
|
65
|
+
const tsSource = `type IOptions<F = typeof fetch> = {
|
|
51
66
|
request?: F;
|
|
52
67
|
interceptor?: (request: F) => F;
|
|
53
68
|
allowedHeaders?: string[];
|
|
@@ -58,8 +73,15 @@ async function runtimeGenerator({ runtime, appDirectory, relativeDistPath }) {
|
|
|
58
73
|
requestId?: string;
|
|
59
74
|
};
|
|
60
75
|
export declare const configure: (options: IOptions) => void;`;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
76
|
+
const pluginTypePath = external_path_default().join(pluginDir, 'index.d.ts');
|
|
77
|
+
await utils_namespaceObject.fs.ensureFile(pluginTypePath);
|
|
78
|
+
await utils_namespaceObject.fs.writeFile(pluginTypePath, tsSource);
|
|
64
79
|
}
|
|
65
|
-
|
|
80
|
+
const utils_runtimeGenerator = runtimeGenerator;
|
|
81
|
+
exports["default"] = __webpack_exports__["default"];
|
|
82
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
83
|
+
"default"
|
|
84
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
85
|
+
Object.defineProperty(exports, '__esModule', {
|
|
86
|
+
value: true
|
|
87
|
+
});
|
package/dist/esm/cli.mjs
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { ApiRouter } from "@modern-js/bff-core";
|
|
3
|
+
import { compile } from "@modern-js/server-utils";
|
|
4
|
+
import { API_DIR, DEFAULT_API_PREFIX, SHARED_DIR, fs, normalizeOutputPath } from "@modern-js/utils";
|
|
5
|
+
import clientGenerator from "./utils/clientGenerator";
|
|
6
|
+
import pluginGenerator from "./utils/pluginGenerator";
|
|
7
|
+
import runtimeGenerator from "./utils/runtimeGenerator";
|
|
8
|
+
const TS_CONFIG_FILENAME = 'tsconfig.json';
|
|
9
|
+
const RUNTIME_CREATE_REQUEST = '@modern-js/plugin-bff/client';
|
|
10
|
+
const RUNTIME_HONO = '@modern-js/plugin-bff/server';
|
|
11
|
+
const bffPlugin = ()=>({
|
|
12
|
+
name: '@modern-js/plugin-bff',
|
|
13
|
+
setup: (api)=>{
|
|
14
|
+
const compileApi = async ()=>{
|
|
15
|
+
const { appDirectory, distDirectory, apiDirectory, sharedDirectory, moduleType } = api.getAppContext();
|
|
16
|
+
const modernConfig = api.getNormalizedConfig();
|
|
17
|
+
const distDir = path.resolve(distDirectory);
|
|
18
|
+
const apiDir = apiDirectory || path.resolve(appDirectory, API_DIR);
|
|
19
|
+
const sharedDir = sharedDirectory || path.resolve(appDirectory, SHARED_DIR);
|
|
20
|
+
const tsconfigPath = path.resolve(appDirectory, TS_CONFIG_FILENAME);
|
|
21
|
+
const sourceDirs = [];
|
|
22
|
+
if (await fs.pathExists(apiDir)) sourceDirs.push(apiDir);
|
|
23
|
+
if (await fs.pathExists(sharedDir)) sourceDirs.push(sharedDir);
|
|
24
|
+
const { server } = modernConfig;
|
|
25
|
+
const { alias } = modernConfig.source;
|
|
26
|
+
const { alias: resolveAlias } = modernConfig.resolve;
|
|
27
|
+
const { babel } = modernConfig.tools;
|
|
28
|
+
if (sourceDirs.length > 0) {
|
|
29
|
+
const combinedAlias = [].concat(alias ?? []).concat(resolveAlias ?? []);
|
|
30
|
+
await compile(appDirectory, {
|
|
31
|
+
server,
|
|
32
|
+
alias: combinedAlias,
|
|
33
|
+
babelConfig: babel
|
|
34
|
+
}, {
|
|
35
|
+
sourceDirs,
|
|
36
|
+
distDir,
|
|
37
|
+
tsconfigPath,
|
|
38
|
+
moduleType,
|
|
39
|
+
throwErrorInsteadOfExit: true
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const generator = async ()=>{
|
|
44
|
+
const { appDirectory, apiDirectory, lambdaDirectory, port } = api.getAppContext();
|
|
45
|
+
const modernConfig = api.getNormalizedConfig();
|
|
46
|
+
const relativeDistPath = modernConfig?.output?.distPath?.root || 'dist';
|
|
47
|
+
const { bff } = modernConfig || {};
|
|
48
|
+
const prefix = bff?.prefix || DEFAULT_API_PREFIX;
|
|
49
|
+
const httpMethodDecider = bff?.httpMethodDecider;
|
|
50
|
+
const apiRouter = new ApiRouter({
|
|
51
|
+
apiDir: apiDirectory,
|
|
52
|
+
appDir: appDirectory,
|
|
53
|
+
lambdaDir: lambdaDirectory,
|
|
54
|
+
prefix,
|
|
55
|
+
httpMethodDecider,
|
|
56
|
+
isBuild: true
|
|
57
|
+
});
|
|
58
|
+
const lambdaDir = apiRouter.getLambdaDir();
|
|
59
|
+
const existLambda = apiRouter.isExistLambda();
|
|
60
|
+
const runtime = bff?.runtimeCreateRequest || RUNTIME_CREATE_REQUEST;
|
|
61
|
+
const relativeApiPath = path.relative(appDirectory, apiDirectory);
|
|
62
|
+
const relativeLambdaPath = path.relative(appDirectory, lambdaDir);
|
|
63
|
+
await pluginGenerator({
|
|
64
|
+
prefix,
|
|
65
|
+
appDirectory,
|
|
66
|
+
relativeDistPath,
|
|
67
|
+
relativeApiPath,
|
|
68
|
+
relativeLambdaPath
|
|
69
|
+
});
|
|
70
|
+
await clientGenerator({
|
|
71
|
+
prefix,
|
|
72
|
+
appDir: appDirectory,
|
|
73
|
+
apiDir: apiDirectory,
|
|
74
|
+
lambdaDir,
|
|
75
|
+
existLambda,
|
|
76
|
+
port,
|
|
77
|
+
requestCreator: bff?.requestCreator,
|
|
78
|
+
httpMethodDecider,
|
|
79
|
+
relativeDistPath,
|
|
80
|
+
relativeApiPath
|
|
81
|
+
});
|
|
82
|
+
await runtimeGenerator({
|
|
83
|
+
runtime,
|
|
84
|
+
appDirectory,
|
|
85
|
+
relativeDistPath
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
const handleCrossProjectInvocation = async (isBuild = false)=>{
|
|
89
|
+
const { bff } = api.getNormalizedConfig();
|
|
90
|
+
if (bff?.crossProject) {
|
|
91
|
+
if (!isBuild) await compileApi();
|
|
92
|
+
await generator();
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const isHono = ()=>{
|
|
96
|
+
const { bffRuntimeFramework } = api.getAppContext();
|
|
97
|
+
return 'hono' === bffRuntimeFramework;
|
|
98
|
+
};
|
|
99
|
+
const createCompressConfig = (devServer, prefix)=>{
|
|
100
|
+
if (!devServer || 'object' != typeof devServer || Array.isArray(devServer)) return;
|
|
101
|
+
const { compress } = devServer;
|
|
102
|
+
if (void 0 === compress || true === compress) return {
|
|
103
|
+
filter: (req)=>!req.url?.includes(prefix)
|
|
104
|
+
};
|
|
105
|
+
if (false === compress) return false;
|
|
106
|
+
return compress;
|
|
107
|
+
};
|
|
108
|
+
api.config(async ()=>{
|
|
109
|
+
const honoRuntimePath = isHono() ? {
|
|
110
|
+
[RUNTIME_HONO]: RUNTIME_HONO
|
|
111
|
+
} : void 0;
|
|
112
|
+
const devServer = api.getConfig()?.tools?.devServer;
|
|
113
|
+
const prefix = api.getConfig()?.bff?.prefix || DEFAULT_API_PREFIX;
|
|
114
|
+
const compress = createCompressConfig(devServer, prefix);
|
|
115
|
+
return {
|
|
116
|
+
tools: {
|
|
117
|
+
devServer: {
|
|
118
|
+
compress
|
|
119
|
+
},
|
|
120
|
+
bundlerChain: (chain, { CHAIN_ID, isServer })=>{
|
|
121
|
+
const { port, appDirectory, apiDirectory, lambdaDirectory } = api.getAppContext();
|
|
122
|
+
const modernConfig = api.getNormalizedConfig();
|
|
123
|
+
const { bff } = modernConfig || {};
|
|
124
|
+
const prefix = bff?.prefix || DEFAULT_API_PREFIX;
|
|
125
|
+
const httpMethodDecider = bff?.httpMethodDecider;
|
|
126
|
+
const apiRouter = new ApiRouter({
|
|
127
|
+
apiDir: apiDirectory,
|
|
128
|
+
appDir: appDirectory,
|
|
129
|
+
lambdaDir: lambdaDirectory,
|
|
130
|
+
prefix,
|
|
131
|
+
httpMethodDecider,
|
|
132
|
+
isBuild: true
|
|
133
|
+
});
|
|
134
|
+
const lambdaDir = apiRouter.getLambdaDir();
|
|
135
|
+
const existLambda = apiRouter.isExistLambda();
|
|
136
|
+
const apiRegexp = new RegExp(normalizeOutputPath(`${apiDirectory}${path.sep}.*(.[tj]s)$`));
|
|
137
|
+
const name = isServer ? 'server' : 'client';
|
|
138
|
+
const loaderPath = require.resolve('./loader');
|
|
139
|
+
chain.module.rule(CHAIN_ID.RULE.JS).exclude.add(apiRegexp);
|
|
140
|
+
chain.module.rule('js-bff-api').test(apiRegexp).use('custom-loader').loader(loaderPath.replace(/\\/g, '/')).options({
|
|
141
|
+
prefix,
|
|
142
|
+
appDir: appDirectory,
|
|
143
|
+
apiDir: apiDirectory,
|
|
144
|
+
lambdaDir,
|
|
145
|
+
existLambda,
|
|
146
|
+
port,
|
|
147
|
+
target: name,
|
|
148
|
+
requestCreator: bff?.requestCreator,
|
|
149
|
+
httpMethodDecider
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
output: {
|
|
154
|
+
externals: honoRuntimePath
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
api.modifyServerRoutes(({ routes })=>{
|
|
159
|
+
const modernConfig = api.getNormalizedConfig();
|
|
160
|
+
const { bff } = modernConfig || {};
|
|
161
|
+
const prefix = bff?.prefix || '/api';
|
|
162
|
+
const prefixList = [];
|
|
163
|
+
if (Array.isArray(prefix)) prefixList.push(...prefix);
|
|
164
|
+
else prefixList.push(prefix);
|
|
165
|
+
const apiServerRoutes = prefixList.map((pre)=>({
|
|
166
|
+
urlPath: pre,
|
|
167
|
+
isApi: true,
|
|
168
|
+
entryPath: '',
|
|
169
|
+
isSPA: false,
|
|
170
|
+
isSSR: false
|
|
171
|
+
}));
|
|
172
|
+
if (!isHono() && bff?.enableHandleWeb) return {
|
|
173
|
+
routes: routes.map((route)=>({
|
|
174
|
+
...route,
|
|
175
|
+
isApi: true
|
|
176
|
+
})).concat(apiServerRoutes)
|
|
177
|
+
};
|
|
178
|
+
return {
|
|
179
|
+
routes: routes.concat(apiServerRoutes)
|
|
180
|
+
};
|
|
181
|
+
});
|
|
182
|
+
api._internalServerPlugins(({ plugins })=>{
|
|
183
|
+
plugins.push({
|
|
184
|
+
name: '@modern-js/plugin-bff/server-plugin'
|
|
185
|
+
});
|
|
186
|
+
return {
|
|
187
|
+
plugins
|
|
188
|
+
};
|
|
189
|
+
});
|
|
190
|
+
api.onBeforeDev(async ()=>{
|
|
191
|
+
await handleCrossProjectInvocation();
|
|
192
|
+
});
|
|
193
|
+
api.onAfterBuild(async ()=>{
|
|
194
|
+
await compileApi();
|
|
195
|
+
await handleCrossProjectInvocation(true);
|
|
196
|
+
});
|
|
197
|
+
api.addWatchFiles(async ()=>{
|
|
198
|
+
const appContext = api.getAppContext();
|
|
199
|
+
const config = api.getNormalizedConfig();
|
|
200
|
+
if (config?.bff?.crossProject) return [
|
|
201
|
+
appContext.apiDirectory
|
|
202
|
+
];
|
|
203
|
+
return [];
|
|
204
|
+
});
|
|
205
|
+
api.onFileChanged(async (e)=>{
|
|
206
|
+
const { filename, eventType, isPrivate } = e;
|
|
207
|
+
const { appDirectory, apiDirectory } = api.getAppContext();
|
|
208
|
+
const relativeApiPath = path.relative(appDirectory, apiDirectory);
|
|
209
|
+
if (!isPrivate && ('change' === eventType || 'unlink' === eventType) && filename.startsWith(`${relativeApiPath}/`) && (filename.endsWith('.ts') || filename.endsWith('.js'))) await handleCrossProjectInvocation();
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
const cli = bffPlugin;
|
|
214
|
+
export { bffPlugin, cli as default };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { generateClient } from "@modern-js/bff-core";
|
|
2
|
+
import { logger } from "@modern-js/utils";
|
|
3
|
+
async function loader(source) {
|
|
4
|
+
this.cacheable();
|
|
5
|
+
const { resourcePath } = this;
|
|
6
|
+
delete require.cache[resourcePath];
|
|
7
|
+
const callback = this.async();
|
|
8
|
+
const draftOptions = this.getOptions();
|
|
9
|
+
const warning = `The file ${resourcePath} is not allowd to be imported in src directory, only API definition files are allowed.`;
|
|
10
|
+
if (!draftOptions.existLambda) {
|
|
11
|
+
logger.warn(warning);
|
|
12
|
+
callback(null, `throw new Error('${warning}')`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const options = {
|
|
16
|
+
prefix: Array.isArray(draftOptions.prefix) ? draftOptions.prefix[0] : draftOptions.prefix,
|
|
17
|
+
appDir: draftOptions.appDir,
|
|
18
|
+
apiDir: draftOptions.apiDir,
|
|
19
|
+
lambdaDir: draftOptions.lambdaDir,
|
|
20
|
+
target: draftOptions.target,
|
|
21
|
+
port: Number(draftOptions.port),
|
|
22
|
+
source,
|
|
23
|
+
resourcePath,
|
|
24
|
+
httpMethodDecider: draftOptions.httpMethodDecider
|
|
25
|
+
};
|
|
26
|
+
const { lambdaDir } = draftOptions;
|
|
27
|
+
if (!resourcePath.startsWith(lambdaDir)) {
|
|
28
|
+
logger.warn(warning);
|
|
29
|
+
callback(null, `throw new Error('${warning}')`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (draftOptions.fetcher) options.fetcher = draftOptions.fetcher;
|
|
33
|
+
if (draftOptions.requestCreator) options.requestCreator = draftOptions.requestCreator;
|
|
34
|
+
options.requireResolve = require.resolve;
|
|
35
|
+
const result = await generateClient(options);
|
|
36
|
+
callback(void 0, result.isOk ? result.value : `throw new Error('${result.value}')`);
|
|
37
|
+
}
|
|
38
|
+
const src_loader = loader;
|
|
39
|
+
export { src_loader as default };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Hono } from "@modern-js/server-core";
|
|
2
|
+
import { isProd, logger } from "@modern-js/utils";
|
|
3
|
+
import createHonoRoutes from "../../utils/createHonoRoutes";
|
|
4
|
+
const before = [
|
|
5
|
+
'custom-server-hook',
|
|
6
|
+
'custom-server-middleware',
|
|
7
|
+
'render'
|
|
8
|
+
];
|
|
9
|
+
class HonoAdapter {
|
|
10
|
+
wrapInArray(handler) {
|
|
11
|
+
if (Array.isArray(handler)) return handler;
|
|
12
|
+
return [
|
|
13
|
+
handler
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
constructor(api){
|
|
17
|
+
this.apiMiddleware = [];
|
|
18
|
+
this.apiServer = null;
|
|
19
|
+
this.isHono = true;
|
|
20
|
+
this.setHandlers = async ()=>{
|
|
21
|
+
if (!this.isHono) return;
|
|
22
|
+
const { apiHandlerInfos } = this.api.getServerContext();
|
|
23
|
+
const honoHandlers = createHonoRoutes(apiHandlerInfos);
|
|
24
|
+
this.apiMiddleware = honoHandlers.map(({ path, method, handler })=>({
|
|
25
|
+
name: 'hono-bff-api',
|
|
26
|
+
path,
|
|
27
|
+
method,
|
|
28
|
+
handler,
|
|
29
|
+
order: 'post',
|
|
30
|
+
before
|
|
31
|
+
}));
|
|
32
|
+
};
|
|
33
|
+
this.registerApiRoutes = async ()=>{
|
|
34
|
+
if (!this.isHono) return;
|
|
35
|
+
this.apiServer = new Hono();
|
|
36
|
+
this.apiMiddleware.forEach(({ path = '*', method = 'all', handler })=>{
|
|
37
|
+
const handlers = this.wrapInArray(handler);
|
|
38
|
+
if (0 === handlers.length) return;
|
|
39
|
+
const firstHandler = handlers[0];
|
|
40
|
+
const restHandlers = handlers.slice(1);
|
|
41
|
+
const m = method;
|
|
42
|
+
const server = this.apiServer;
|
|
43
|
+
if (!server) return;
|
|
44
|
+
const register = server[m];
|
|
45
|
+
register.call(server, path, firstHandler, ...restHandlers);
|
|
46
|
+
});
|
|
47
|
+
this.apiServer.onError(async (err, c)=>{
|
|
48
|
+
try {
|
|
49
|
+
const serverConfig = this.api.getServerConfig();
|
|
50
|
+
const onErrorHandler = serverConfig?.onError;
|
|
51
|
+
if (onErrorHandler) {
|
|
52
|
+
const result = await onErrorHandler(err, c);
|
|
53
|
+
if (result instanceof Response) return result;
|
|
54
|
+
} else logger.error(err);
|
|
55
|
+
} catch (configError) {
|
|
56
|
+
logger.error(`Error in serverConfig.onError handler: ${configError}`);
|
|
57
|
+
}
|
|
58
|
+
return c.json({
|
|
59
|
+
message: err?.message || '[BFF] Internal Server Error'
|
|
60
|
+
}, err?.status || 500);
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
this.registerMiddleware = async (options)=>{
|
|
64
|
+
const { prefix } = options;
|
|
65
|
+
const { bffRuntimeFramework } = this.api.getServerContext();
|
|
66
|
+
if ('hono' !== bffRuntimeFramework) {
|
|
67
|
+
this.isHono = false;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const { middlewares: globalMiddlewares } = this.api.getServerContext();
|
|
71
|
+
await this.setHandlers();
|
|
72
|
+
if (isProd()) globalMiddlewares.push(...this.apiMiddleware);
|
|
73
|
+
else {
|
|
74
|
+
await this.registerApiRoutes();
|
|
75
|
+
const dynamicApiMiddleware = {
|
|
76
|
+
name: 'dynamic-bff-handler',
|
|
77
|
+
path: `${prefix}/*`,
|
|
78
|
+
method: 'all',
|
|
79
|
+
order: 'post',
|
|
80
|
+
before,
|
|
81
|
+
handler: async (c, next)=>{
|
|
82
|
+
if (this.apiServer) {
|
|
83
|
+
const response = await this.apiServer.fetch(c.req.raw, c.env);
|
|
84
|
+
if (404 !== response.status) return new Response(response.body, response);
|
|
85
|
+
}
|
|
86
|
+
await next();
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
globalMiddlewares.push(dynamicApiMiddleware);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
this.api = api;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export { HonoAdapter };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useHonoContext } from "@modern-js/server-core";
|
|
2
|
+
const Pipe = (func)=>({
|
|
3
|
+
name: 'pipe',
|
|
4
|
+
async execute (executeHelper, next) {
|
|
5
|
+
const { inputs } = executeHelper;
|
|
6
|
+
const ctx = useHonoContext();
|
|
7
|
+
const { res } = ctx;
|
|
8
|
+
if ('function' == typeof func) {
|
|
9
|
+
let isPiped = true;
|
|
10
|
+
const end = (value)=>{
|
|
11
|
+
isPiped = false;
|
|
12
|
+
if ('function' == typeof value) return void value(res);
|
|
13
|
+
return value;
|
|
14
|
+
};
|
|
15
|
+
const output = await func(inputs, end);
|
|
16
|
+
if (!isPiped) if (output) return executeHelper.result = output;
|
|
17
|
+
else return;
|
|
18
|
+
executeHelper.inputs = output;
|
|
19
|
+
await next();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const Middleware = (middleware)=>({
|
|
24
|
+
name: 'middleware',
|
|
25
|
+
metadata (helper) {
|
|
26
|
+
const middlewares = helper.getMetadata('pipe') || [];
|
|
27
|
+
middlewares.push(middleware);
|
|
28
|
+
helper.setMetadata('middleware', middlewares);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
export { Middleware, Pipe };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { ApiRouter } from "@modern-js/bff-core";
|
|
3
|
+
import { API_DIR, isFunction, isProd, isWebOnly, requireExistModule } from "@modern-js/utils";
|
|
4
|
+
import { API_APP_NAME } from "./constants";
|
|
5
|
+
import { HonoAdapter } from "./runtime/hono/adapter";
|
|
6
|
+
class Storage {
|
|
7
|
+
reset() {
|
|
8
|
+
this.middlewares = [];
|
|
9
|
+
}
|
|
10
|
+
constructor(){
|
|
11
|
+
this.middlewares = [];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const createTransformAPI = (storage)=>({
|
|
15
|
+
addMiddleware (fn) {
|
|
16
|
+
storage.middlewares.push(fn);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const server = ()=>({
|
|
20
|
+
name: '@modern-js/plugin-bff',
|
|
21
|
+
setup: (api)=>{
|
|
22
|
+
const storage = new Storage();
|
|
23
|
+
const transformAPI = createTransformAPI(storage);
|
|
24
|
+
let apiAppPath = '';
|
|
25
|
+
let apiRouter;
|
|
26
|
+
const honoAdapter = new HonoAdapter(api);
|
|
27
|
+
api.onPrepare(async ()=>{
|
|
28
|
+
const appContext = api.getServerContext();
|
|
29
|
+
const { appDirectory, distDirectory, render } = appContext;
|
|
30
|
+
const root = isProd() ? distDirectory : appDirectory;
|
|
31
|
+
const apiPath = path.resolve(root || process.cwd(), API_DIR);
|
|
32
|
+
apiAppPath = path.resolve(apiPath, API_APP_NAME);
|
|
33
|
+
const apiMod = await requireExistModule(apiAppPath);
|
|
34
|
+
if (apiMod && 'function' == typeof apiMod) apiMod(transformAPI);
|
|
35
|
+
const { middlewares } = storage;
|
|
36
|
+
api.updateServerContext({
|
|
37
|
+
...appContext,
|
|
38
|
+
apiMiddlewares: middlewares
|
|
39
|
+
});
|
|
40
|
+
const config = api.getServerConfig();
|
|
41
|
+
const prefix = config?.bff?.prefix || '/api';
|
|
42
|
+
const enableHandleWeb = config?.bff?.enableHandleWeb;
|
|
43
|
+
const httpMethodDecider = config?.bff?.httpMethodDecider;
|
|
44
|
+
const { distDirectory: pwd, middlewares: globalMiddlewares } = api.getServerContext();
|
|
45
|
+
const webOnly = await isWebOnly();
|
|
46
|
+
let handler;
|
|
47
|
+
if (webOnly) handler = async (c, next)=>{
|
|
48
|
+
c.body('');
|
|
49
|
+
await next();
|
|
50
|
+
};
|
|
51
|
+
else {
|
|
52
|
+
const runner = api.getHooks();
|
|
53
|
+
const renderHandler = enableHandleWeb ? render : null;
|
|
54
|
+
handler = await runner.prepareApiServer.call({
|
|
55
|
+
pwd: pwd,
|
|
56
|
+
prefix,
|
|
57
|
+
render: renderHandler,
|
|
58
|
+
httpMethodDecider
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (handler && isFunction(handler)) globalMiddlewares.push({
|
|
62
|
+
name: 'bind-bff',
|
|
63
|
+
handler: (c, next)=>{
|
|
64
|
+
if (!c.req.path.startsWith(prefix) && !enableHandleWeb) return next();
|
|
65
|
+
return handler(c, next);
|
|
66
|
+
},
|
|
67
|
+
order: 'post',
|
|
68
|
+
before: [
|
|
69
|
+
'custom-server-hook',
|
|
70
|
+
'custom-server-middleware',
|
|
71
|
+
'render'
|
|
72
|
+
]
|
|
73
|
+
});
|
|
74
|
+
honoAdapter.registerMiddleware({
|
|
75
|
+
prefix,
|
|
76
|
+
enableHandleWeb
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
api.onReset(async ({ event })=>{
|
|
80
|
+
storage.reset();
|
|
81
|
+
const appContext = api.getServerContext();
|
|
82
|
+
const newApiModule = await requireExistModule(apiAppPath);
|
|
83
|
+
if (newApiModule && 'function' == typeof newApiModule) newApiModule(transformAPI);
|
|
84
|
+
const { middlewares } = storage;
|
|
85
|
+
api.updateServerContext({
|
|
86
|
+
...appContext,
|
|
87
|
+
apiMiddlewares: middlewares
|
|
88
|
+
});
|
|
89
|
+
if ('file-change' === event.type) {
|
|
90
|
+
const apiHandlerInfos = await apiRouter.getApiHandlers();
|
|
91
|
+
const appContext = api.getServerContext();
|
|
92
|
+
api.updateServerContext({
|
|
93
|
+
...appContext,
|
|
94
|
+
apiHandlerInfos
|
|
95
|
+
});
|
|
96
|
+
await honoAdapter.setHandlers();
|
|
97
|
+
await honoAdapter.registerApiRoutes();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
api.prepareApiServer(async (input, next)=>{
|
|
101
|
+
const { pwd, prefix, httpMethodDecider } = input;
|
|
102
|
+
const apiDir = path.resolve(pwd, API_DIR);
|
|
103
|
+
const appContext = api.getServerContext();
|
|
104
|
+
const { apiDirectory, lambdaDirectory } = appContext;
|
|
105
|
+
apiRouter = new ApiRouter({
|
|
106
|
+
appDir: pwd,
|
|
107
|
+
apiDir: apiDirectory || apiDir,
|
|
108
|
+
lambdaDir: lambdaDirectory,
|
|
109
|
+
prefix,
|
|
110
|
+
httpMethodDecider
|
|
111
|
+
});
|
|
112
|
+
const apiHandlerInfos = await apiRouter.getApiHandlers();
|
|
113
|
+
api.updateServerContext({
|
|
114
|
+
...appContext,
|
|
115
|
+
apiRouter,
|
|
116
|
+
apiHandlerInfos
|
|
117
|
+
});
|
|
118
|
+
return next(input);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
export { server as default };
|