@bleedingdev/modern-js-plugin-bff 3.5.0-ultramodern.86 → 3.5.0-ultramodern.89
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/generator.js +33 -1
- package/dist/cjs/utils/effectSourceLoader.js +80 -1
- package/dist/esm/cli/generator.mjs +33 -1
- package/dist/esm/utils/effectSourceLoader.mjs +78 -2
- package/dist/esm-node/cli/generator.mjs +33 -1
- package/dist/esm-node/utils/effectSourceLoader.mjs +78 -2
- package/dist/types/utils/effectSourceLoader.d.ts +5 -0
- package/package.json +12 -12
|
@@ -46,6 +46,7 @@ const external_path_namespaceObject = require("path");
|
|
|
46
46
|
var external_path_default = /*#__PURE__*/ __webpack_require__.n(external_path_namespaceObject);
|
|
47
47
|
const clientGenerator_js_namespaceObject = require("../utils/clientGenerator.js");
|
|
48
48
|
var clientGenerator_js_default = /*#__PURE__*/ __webpack_require__.n(clientGenerator_js_namespaceObject);
|
|
49
|
+
const effectSourceLoader_js_namespaceObject = require("../utils/effectSourceLoader.js");
|
|
49
50
|
const pluginGenerator_js_namespaceObject = require("../utils/pluginGenerator.js");
|
|
50
51
|
var pluginGenerator_js_default = /*#__PURE__*/ __webpack_require__.n(pluginGenerator_js_namespaceObject);
|
|
51
52
|
const runtimeGenerator_js_namespaceObject = require("../utils/runtimeGenerator.js");
|
|
@@ -53,9 +54,30 @@ var runtimeGenerator_js_default = /*#__PURE__*/ __webpack_require__.n(runtimeGen
|
|
|
53
54
|
const external_prefix_js_namespaceObject = require("./prefix.js");
|
|
54
55
|
const external_serverGlobalVars_js_namespaceObject = require("./serverGlobalVars.js");
|
|
55
56
|
const RUNTIME_CREATE_REQUEST = '@modern-js/plugin-bff/client';
|
|
57
|
+
const effectEntryExtensions = [
|
|
58
|
+
'.js',
|
|
59
|
+
'.jsx',
|
|
60
|
+
'.ts',
|
|
61
|
+
'.tsx',
|
|
62
|
+
'.mjs',
|
|
63
|
+
'.mts',
|
|
64
|
+
'.cjs',
|
|
65
|
+
'.cts'
|
|
66
|
+
];
|
|
67
|
+
function resolveEffectSourceEntry(appDirectory, apiDirectory, configuredEntry) {
|
|
68
|
+
const entry = configuredEntry ? external_path_default().isAbsolute(configuredEntry) ? configuredEntry : external_path_default().resolve(appDirectory, configuredEntry) : external_path_default().resolve(apiDirectory, 'index');
|
|
69
|
+
return external_path_default().extname(entry) ? entry : effectEntryExtensions.map((extension)=>`${entry}${extension}`).find((candidate)=>utils_namespaceObject.fs.existsSync(candidate));
|
|
70
|
+
}
|
|
71
|
+
function resolveBuiltEffectEntry(appDirectory, distDirectory, sourceEntry) {
|
|
72
|
+
if (!sourceEntry) return;
|
|
73
|
+
const relativeEntry = external_path_default().relative(appDirectory, sourceEntry);
|
|
74
|
+
if ('..' === relativeEntry || relativeEntry.startsWith(`..${external_path_default().sep}`)) throw new Error(`Effect BFF entry must be inside the application directory: ${sourceEntry}`);
|
|
75
|
+
const builtEntry = external_path_default().resolve(distDirectory, relativeEntry).replace(/\.(?:[cm]?ts|tsx|jsx)$/u, '.js');
|
|
76
|
+
return utils_namespaceObject.fs.existsSync(builtEntry) ? builtEntry : void 0;
|
|
77
|
+
}
|
|
56
78
|
const createBffGenerator = (api)=>{
|
|
57
79
|
const compileApi = async ()=>{
|
|
58
|
-
const { appDirectory, distDirectory, apiDirectory, sharedDirectory, moduleType } = api.getAppContext();
|
|
80
|
+
const { appDirectory, distDirectory, apiDirectory, bffRuntimeFramework, sharedDirectory, moduleType } = api.getAppContext();
|
|
59
81
|
const modernConfig = api.getNormalizedConfig();
|
|
60
82
|
const distDir = external_path_default().resolve(distDirectory);
|
|
61
83
|
const apiDir = apiDirectory || external_path_default().resolve(appDirectory, utils_namespaceObject.API_DIR);
|
|
@@ -79,6 +101,16 @@ const createBffGenerator = (api)=>{
|
|
|
79
101
|
throwErrorInsteadOfExit: true
|
|
80
102
|
});
|
|
81
103
|
await (0, external_serverGlobalVars_js_namespaceObject.transformServerGlobalVars)(sourceDirs.map((sourceDir)=>external_path_default().resolve(distDir, external_path_default().relative(appDirectory, sourceDir))), serializedGlobalVars);
|
|
104
|
+
if ('effect' === bffRuntimeFramework) {
|
|
105
|
+
const sourceEntry = resolveEffectSourceEntry(appDirectory, apiDir, modernConfig.bff?.effect?.entry);
|
|
106
|
+
const builtEntry = resolveBuiltEffectEntry(appDirectory, distDir, sourceEntry);
|
|
107
|
+
if (!builtEntry) throw new Error(`Effect BFF entry was not emitted into ${distDir}: ${sourceEntry ?? external_path_default().resolve(apiDir, 'index')}`);
|
|
108
|
+
await (0, effectSourceLoader_js_namespaceObject.bundleEffectEntryForNode)({
|
|
109
|
+
appDir: appDirectory,
|
|
110
|
+
entryPath: builtEntry,
|
|
111
|
+
format: 'module' === moduleType ? 'esm' : 'cjs'
|
|
112
|
+
});
|
|
113
|
+
}
|
|
82
114
|
}
|
|
83
115
|
};
|
|
84
116
|
const generate = async ()=>{
|
|
@@ -37,12 +37,14 @@ var __webpack_require__ = {};
|
|
|
37
37
|
var __webpack_exports__ = {};
|
|
38
38
|
__webpack_require__.r(__webpack_exports__);
|
|
39
39
|
__webpack_require__.d(__webpack_exports__, {
|
|
40
|
+
bundleEffectEntryForNode: ()=>bundleEffectEntryForNode,
|
|
40
41
|
loadEffectSourceModule: ()=>loadEffectSourceModule
|
|
41
42
|
});
|
|
42
43
|
const external_node_crypto_namespaceObject = require("node:crypto");
|
|
43
44
|
var external_node_crypto_default = /*#__PURE__*/ __webpack_require__.n(external_node_crypto_namespaceObject);
|
|
44
45
|
const external_node_fs_namespaceObject = require("node:fs");
|
|
45
46
|
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
|
|
47
|
+
const external_node_module_namespaceObject = require("node:module");
|
|
46
48
|
const external_node_path_namespaceObject = require("node:path");
|
|
47
49
|
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
48
50
|
const external_node_url_namespaceObject = require("node:url");
|
|
@@ -113,6 +115,81 @@ function preserveSourceModuleSemantics() {
|
|
|
113
115
|
}
|
|
114
116
|
};
|
|
115
117
|
}
|
|
118
|
+
const nodeBuiltins = new Set([
|
|
119
|
+
...external_node_module_namespaceObject.builtinModules,
|
|
120
|
+
...external_node_module_namespaceObject.builtinModules.map((name)=>`node:${name}`)
|
|
121
|
+
]);
|
|
122
|
+
const dependencyResolutionMarker = 'modern-js-effect-dependency-resolution';
|
|
123
|
+
function isBareSpecifier(specifier) {
|
|
124
|
+
return !specifier.startsWith('.') && !specifier.startsWith('/') && !external_node_path_default().isAbsolute(specifier);
|
|
125
|
+
}
|
|
126
|
+
function externalizeInstalledDependencies() {
|
|
127
|
+
return {
|
|
128
|
+
name: 'modern-js-effect-installed-dependencies',
|
|
129
|
+
setup (buildApi) {
|
|
130
|
+
buildApi.onResolve({
|
|
131
|
+
filter: /.*/
|
|
132
|
+
}, async (args)=>{
|
|
133
|
+
if (!isBareSpecifier(args.path) || nodeBuiltins.has(args.path) || args.pluginData?.[dependencyResolutionMarker] === true) return nodeBuiltins.has(args.path) ? {
|
|
134
|
+
external: true,
|
|
135
|
+
path: args.path
|
|
136
|
+
} : void 0;
|
|
137
|
+
const resolution = await buildApi.resolve(args.path, {
|
|
138
|
+
importer: args.importer,
|
|
139
|
+
kind: args.kind,
|
|
140
|
+
namespace: args.namespace,
|
|
141
|
+
pluginData: {
|
|
142
|
+
...args.pluginData,
|
|
143
|
+
[dependencyResolutionMarker]: true
|
|
144
|
+
},
|
|
145
|
+
resolveDir: args.resolveDir
|
|
146
|
+
});
|
|
147
|
+
if (resolution.errors.length > 0) return {
|
|
148
|
+
external: true,
|
|
149
|
+
path: args.path
|
|
150
|
+
};
|
|
151
|
+
if (resolution.external || !resolution.path) return {
|
|
152
|
+
external: true,
|
|
153
|
+
path: args.path
|
|
154
|
+
};
|
|
155
|
+
const realPath = await external_node_fs_default().promises.realpath(resolution.path).catch(()=>resolution.path);
|
|
156
|
+
if (realPath.includes(`${external_node_path_default().sep}node_modules${external_node_path_default().sep}`)) return {
|
|
157
|
+
external: true,
|
|
158
|
+
path: args.path
|
|
159
|
+
};
|
|
160
|
+
return {
|
|
161
|
+
namespace: resolution.namespace,
|
|
162
|
+
path: resolution.path,
|
|
163
|
+
pluginData: resolution.pluginData,
|
|
164
|
+
sideEffects: resolution.sideEffects,
|
|
165
|
+
suffix: resolution.suffix,
|
|
166
|
+
warnings: resolution.warnings,
|
|
167
|
+
watchDirs: resolution.watchDirs,
|
|
168
|
+
watchFiles: resolution.watchFiles
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
async function bundleEffectEntryForNode(options) {
|
|
175
|
+
await (0, external_esbuild_namespaceObject.build)({
|
|
176
|
+
absWorkingDir: options.appDir,
|
|
177
|
+
allowOverwrite: true,
|
|
178
|
+
bundle: true,
|
|
179
|
+
entryPoints: [
|
|
180
|
+
options.entryPath
|
|
181
|
+
],
|
|
182
|
+
format: options.format,
|
|
183
|
+
logLevel: 'silent',
|
|
184
|
+
outfile: options.entryPath,
|
|
185
|
+
platform: 'node',
|
|
186
|
+
plugins: [
|
|
187
|
+
externalizeInstalledDependencies(),
|
|
188
|
+
preserveSourceModuleSemantics()
|
|
189
|
+
],
|
|
190
|
+
target: 'node20'
|
|
191
|
+
});
|
|
192
|
+
}
|
|
116
193
|
function isWatchableInput(filename) {
|
|
117
194
|
return !filename.includes(`${external_node_path_default().sep}node_modules${external_node_path_default().sep}`) && (SOURCE_LOADERS.has(external_node_path_default().extname(filename).toLowerCase()) || '.json' === external_node_path_default().extname(filename).toLowerCase());
|
|
118
195
|
}
|
|
@@ -147,9 +224,9 @@ async function loadEffectSourceModule(options) {
|
|
|
147
224
|
logLevel: 'silent',
|
|
148
225
|
metafile: true,
|
|
149
226
|
outfile: outputPath,
|
|
150
|
-
packages: 'external',
|
|
151
227
|
platform: 'node',
|
|
152
228
|
plugins: [
|
|
229
|
+
externalizeInstalledDependencies(),
|
|
153
230
|
preserveSourceModuleSemantics()
|
|
154
231
|
],
|
|
155
232
|
sourcemap: 'inline',
|
|
@@ -164,8 +241,10 @@ async function loadEffectSourceModule(options) {
|
|
|
164
241
|
const revision = external_node_crypto_default().createHash('sha256').update(output).digest('hex');
|
|
165
242
|
return normalizeImportedModule(await dynamicImport(`${(0, external_node_url_namespaceObject.pathToFileURL)(outputPath).href}?v=${revision}`));
|
|
166
243
|
}
|
|
244
|
+
exports.bundleEffectEntryForNode = __webpack_exports__.bundleEffectEntryForNode;
|
|
167
245
|
exports.loadEffectSourceModule = __webpack_exports__.loadEffectSourceModule;
|
|
168
246
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
247
|
+
"bundleEffectEntryForNode",
|
|
169
248
|
"loadEffectSourceModule"
|
|
170
249
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
171
250
|
Object.defineProperty(exports, '__esModule', {
|
|
@@ -3,14 +3,36 @@ import { compile } from "@modern-js/server-utils";
|
|
|
3
3
|
import { API_DIR, SHARED_DIR, fs, resolveServerTsconfig } from "@modern-js/utils";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import clientGenerator from "../utils/clientGenerator.mjs";
|
|
6
|
+
import { bundleEffectEntryForNode } from "../utils/effectSourceLoader.mjs";
|
|
6
7
|
import pluginGenerator from "../utils/pluginGenerator.mjs";
|
|
7
8
|
import runtimeGenerator from "../utils/runtimeGenerator.mjs";
|
|
8
9
|
import { getPrimaryPrefix } from "./prefix.mjs";
|
|
9
10
|
import { serializeServerGlobalVars, transformServerGlobalVars } from "./serverGlobalVars.mjs";
|
|
10
11
|
const RUNTIME_CREATE_REQUEST = '@modern-js/plugin-bff/client';
|
|
12
|
+
const effectEntryExtensions = [
|
|
13
|
+
'.js',
|
|
14
|
+
'.jsx',
|
|
15
|
+
'.ts',
|
|
16
|
+
'.tsx',
|
|
17
|
+
'.mjs',
|
|
18
|
+
'.mts',
|
|
19
|
+
'.cjs',
|
|
20
|
+
'.cts'
|
|
21
|
+
];
|
|
22
|
+
function resolveEffectSourceEntry(appDirectory, apiDirectory, configuredEntry) {
|
|
23
|
+
const entry = configuredEntry ? path.isAbsolute(configuredEntry) ? configuredEntry : path.resolve(appDirectory, configuredEntry) : path.resolve(apiDirectory, 'index');
|
|
24
|
+
return path.extname(entry) ? entry : effectEntryExtensions.map((extension)=>`${entry}${extension}`).find((candidate)=>fs.existsSync(candidate));
|
|
25
|
+
}
|
|
26
|
+
function resolveBuiltEffectEntry(appDirectory, distDirectory, sourceEntry) {
|
|
27
|
+
if (!sourceEntry) return;
|
|
28
|
+
const relativeEntry = path.relative(appDirectory, sourceEntry);
|
|
29
|
+
if ('..' === relativeEntry || relativeEntry.startsWith(`..${path.sep}`)) throw new Error(`Effect BFF entry must be inside the application directory: ${sourceEntry}`);
|
|
30
|
+
const builtEntry = path.resolve(distDirectory, relativeEntry).replace(/\.(?:[cm]?ts|tsx|jsx)$/u, '.js');
|
|
31
|
+
return fs.existsSync(builtEntry) ? builtEntry : void 0;
|
|
32
|
+
}
|
|
11
33
|
const createBffGenerator = (api)=>{
|
|
12
34
|
const compileApi = async ()=>{
|
|
13
|
-
const { appDirectory, distDirectory, apiDirectory, sharedDirectory, moduleType } = api.getAppContext();
|
|
35
|
+
const { appDirectory, distDirectory, apiDirectory, bffRuntimeFramework, sharedDirectory, moduleType } = api.getAppContext();
|
|
14
36
|
const modernConfig = api.getNormalizedConfig();
|
|
15
37
|
const distDir = path.resolve(distDirectory);
|
|
16
38
|
const apiDir = apiDirectory || path.resolve(appDirectory, API_DIR);
|
|
@@ -34,6 +56,16 @@ const createBffGenerator = (api)=>{
|
|
|
34
56
|
throwErrorInsteadOfExit: true
|
|
35
57
|
});
|
|
36
58
|
await transformServerGlobalVars(sourceDirs.map((sourceDir)=>path.resolve(distDir, path.relative(appDirectory, sourceDir))), serializedGlobalVars);
|
|
59
|
+
if ('effect' === bffRuntimeFramework) {
|
|
60
|
+
const sourceEntry = resolveEffectSourceEntry(appDirectory, apiDir, modernConfig.bff?.effect?.entry);
|
|
61
|
+
const builtEntry = resolveBuiltEffectEntry(appDirectory, distDir, sourceEntry);
|
|
62
|
+
if (!builtEntry) throw new Error(`Effect BFF entry was not emitted into ${distDir}: ${sourceEntry ?? path.resolve(apiDir, 'index')}`);
|
|
63
|
+
await bundleEffectEntryForNode({
|
|
64
|
+
appDir: appDirectory,
|
|
65
|
+
entryPath: builtEntry,
|
|
66
|
+
format: 'module' === moduleType ? 'esm' : 'cjs'
|
|
67
|
+
});
|
|
68
|
+
}
|
|
37
69
|
}
|
|
38
70
|
};
|
|
39
71
|
const generate = async ()=>{
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import node_crypto from "node:crypto";
|
|
2
2
|
import node_fs from "node:fs";
|
|
3
|
+
import { builtinModules } from "node:module";
|
|
3
4
|
import node_path from "node:path";
|
|
4
5
|
import { pathToFileURL } from "node:url";
|
|
5
6
|
import { build, transform } from "esbuild";
|
|
@@ -69,6 +70,81 @@ function preserveSourceModuleSemantics() {
|
|
|
69
70
|
}
|
|
70
71
|
};
|
|
71
72
|
}
|
|
73
|
+
const nodeBuiltins = new Set([
|
|
74
|
+
...builtinModules,
|
|
75
|
+
...builtinModules.map((name)=>`node:${name}`)
|
|
76
|
+
]);
|
|
77
|
+
const dependencyResolutionMarker = 'modern-js-effect-dependency-resolution';
|
|
78
|
+
function isBareSpecifier(specifier) {
|
|
79
|
+
return !specifier.startsWith('.') && !specifier.startsWith('/') && !node_path.isAbsolute(specifier);
|
|
80
|
+
}
|
|
81
|
+
function externalizeInstalledDependencies() {
|
|
82
|
+
return {
|
|
83
|
+
name: 'modern-js-effect-installed-dependencies',
|
|
84
|
+
setup (buildApi) {
|
|
85
|
+
buildApi.onResolve({
|
|
86
|
+
filter: /.*/
|
|
87
|
+
}, async (args)=>{
|
|
88
|
+
if (!isBareSpecifier(args.path) || nodeBuiltins.has(args.path) || args.pluginData?.[dependencyResolutionMarker] === true) return nodeBuiltins.has(args.path) ? {
|
|
89
|
+
external: true,
|
|
90
|
+
path: args.path
|
|
91
|
+
} : void 0;
|
|
92
|
+
const resolution = await buildApi.resolve(args.path, {
|
|
93
|
+
importer: args.importer,
|
|
94
|
+
kind: args.kind,
|
|
95
|
+
namespace: args.namespace,
|
|
96
|
+
pluginData: {
|
|
97
|
+
...args.pluginData,
|
|
98
|
+
[dependencyResolutionMarker]: true
|
|
99
|
+
},
|
|
100
|
+
resolveDir: args.resolveDir
|
|
101
|
+
});
|
|
102
|
+
if (resolution.errors.length > 0) return {
|
|
103
|
+
external: true,
|
|
104
|
+
path: args.path
|
|
105
|
+
};
|
|
106
|
+
if (resolution.external || !resolution.path) return {
|
|
107
|
+
external: true,
|
|
108
|
+
path: args.path
|
|
109
|
+
};
|
|
110
|
+
const realPath = await node_fs.promises.realpath(resolution.path).catch(()=>resolution.path);
|
|
111
|
+
if (realPath.includes(`${node_path.sep}node_modules${node_path.sep}`)) return {
|
|
112
|
+
external: true,
|
|
113
|
+
path: args.path
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
namespace: resolution.namespace,
|
|
117
|
+
path: resolution.path,
|
|
118
|
+
pluginData: resolution.pluginData,
|
|
119
|
+
sideEffects: resolution.sideEffects,
|
|
120
|
+
suffix: resolution.suffix,
|
|
121
|
+
warnings: resolution.warnings,
|
|
122
|
+
watchDirs: resolution.watchDirs,
|
|
123
|
+
watchFiles: resolution.watchFiles
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
async function bundleEffectEntryForNode(options) {
|
|
130
|
+
await build({
|
|
131
|
+
absWorkingDir: options.appDir,
|
|
132
|
+
allowOverwrite: true,
|
|
133
|
+
bundle: true,
|
|
134
|
+
entryPoints: [
|
|
135
|
+
options.entryPath
|
|
136
|
+
],
|
|
137
|
+
format: options.format,
|
|
138
|
+
logLevel: 'silent',
|
|
139
|
+
outfile: options.entryPath,
|
|
140
|
+
platform: 'node',
|
|
141
|
+
plugins: [
|
|
142
|
+
externalizeInstalledDependencies(),
|
|
143
|
+
preserveSourceModuleSemantics()
|
|
144
|
+
],
|
|
145
|
+
target: 'node20'
|
|
146
|
+
});
|
|
147
|
+
}
|
|
72
148
|
function isWatchableInput(filename) {
|
|
73
149
|
return !filename.includes(`${node_path.sep}node_modules${node_path.sep}`) && (SOURCE_LOADERS.has(node_path.extname(filename).toLowerCase()) || '.json' === node_path.extname(filename).toLowerCase());
|
|
74
150
|
}
|
|
@@ -103,9 +179,9 @@ async function loadEffectSourceModule(options) {
|
|
|
103
179
|
logLevel: 'silent',
|
|
104
180
|
metafile: true,
|
|
105
181
|
outfile: outputPath,
|
|
106
|
-
packages: 'external',
|
|
107
182
|
platform: 'node',
|
|
108
183
|
plugins: [
|
|
184
|
+
externalizeInstalledDependencies(),
|
|
109
185
|
preserveSourceModuleSemantics()
|
|
110
186
|
],
|
|
111
187
|
sourcemap: 'inline',
|
|
@@ -120,4 +196,4 @@ async function loadEffectSourceModule(options) {
|
|
|
120
196
|
const revision = node_crypto.createHash('sha256').update(output).digest('hex');
|
|
121
197
|
return normalizeImportedModule(await dynamicImport(`${pathToFileURL(outputPath).href}?v=${revision}`));
|
|
122
198
|
}
|
|
123
|
-
export { loadEffectSourceModule };
|
|
199
|
+
export { bundleEffectEntryForNode, loadEffectSourceModule };
|
|
@@ -4,14 +4,36 @@ import { compile } from "@modern-js/server-utils";
|
|
|
4
4
|
import { API_DIR, SHARED_DIR, fs, resolveServerTsconfig } from "@modern-js/utils";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import clientGenerator from "../utils/clientGenerator.mjs";
|
|
7
|
+
import { bundleEffectEntryForNode } from "../utils/effectSourceLoader.mjs";
|
|
7
8
|
import pluginGenerator from "../utils/pluginGenerator.mjs";
|
|
8
9
|
import runtimeGenerator from "../utils/runtimeGenerator.mjs";
|
|
9
10
|
import { getPrimaryPrefix } from "./prefix.mjs";
|
|
10
11
|
import { serializeServerGlobalVars, transformServerGlobalVars } from "./serverGlobalVars.mjs";
|
|
11
12
|
const RUNTIME_CREATE_REQUEST = '@modern-js/plugin-bff/client';
|
|
13
|
+
const effectEntryExtensions = [
|
|
14
|
+
'.js',
|
|
15
|
+
'.jsx',
|
|
16
|
+
'.ts',
|
|
17
|
+
'.tsx',
|
|
18
|
+
'.mjs',
|
|
19
|
+
'.mts',
|
|
20
|
+
'.cjs',
|
|
21
|
+
'.cts'
|
|
22
|
+
];
|
|
23
|
+
function resolveEffectSourceEntry(appDirectory, apiDirectory, configuredEntry) {
|
|
24
|
+
const entry = configuredEntry ? path.isAbsolute(configuredEntry) ? configuredEntry : path.resolve(appDirectory, configuredEntry) : path.resolve(apiDirectory, 'index');
|
|
25
|
+
return path.extname(entry) ? entry : effectEntryExtensions.map((extension)=>`${entry}${extension}`).find((candidate)=>fs.existsSync(candidate));
|
|
26
|
+
}
|
|
27
|
+
function resolveBuiltEffectEntry(appDirectory, distDirectory, sourceEntry) {
|
|
28
|
+
if (!sourceEntry) return;
|
|
29
|
+
const relativeEntry = path.relative(appDirectory, sourceEntry);
|
|
30
|
+
if ('..' === relativeEntry || relativeEntry.startsWith(`..${path.sep}`)) throw new Error(`Effect BFF entry must be inside the application directory: ${sourceEntry}`);
|
|
31
|
+
const builtEntry = path.resolve(distDirectory, relativeEntry).replace(/\.(?:[cm]?ts|tsx|jsx)$/u, '.js');
|
|
32
|
+
return fs.existsSync(builtEntry) ? builtEntry : void 0;
|
|
33
|
+
}
|
|
12
34
|
const createBffGenerator = (api)=>{
|
|
13
35
|
const compileApi = async ()=>{
|
|
14
|
-
const { appDirectory, distDirectory, apiDirectory, sharedDirectory, moduleType } = api.getAppContext();
|
|
36
|
+
const { appDirectory, distDirectory, apiDirectory, bffRuntimeFramework, sharedDirectory, moduleType } = api.getAppContext();
|
|
15
37
|
const modernConfig = api.getNormalizedConfig();
|
|
16
38
|
const distDir = path.resolve(distDirectory);
|
|
17
39
|
const apiDir = apiDirectory || path.resolve(appDirectory, API_DIR);
|
|
@@ -35,6 +57,16 @@ const createBffGenerator = (api)=>{
|
|
|
35
57
|
throwErrorInsteadOfExit: true
|
|
36
58
|
});
|
|
37
59
|
await transformServerGlobalVars(sourceDirs.map((sourceDir)=>path.resolve(distDir, path.relative(appDirectory, sourceDir))), serializedGlobalVars);
|
|
60
|
+
if ('effect' === bffRuntimeFramework) {
|
|
61
|
+
const sourceEntry = resolveEffectSourceEntry(appDirectory, apiDir, modernConfig.bff?.effect?.entry);
|
|
62
|
+
const builtEntry = resolveBuiltEffectEntry(appDirectory, distDir, sourceEntry);
|
|
63
|
+
if (!builtEntry) throw new Error(`Effect BFF entry was not emitted into ${distDir}: ${sourceEntry ?? path.resolve(apiDir, 'index')}`);
|
|
64
|
+
await bundleEffectEntryForNode({
|
|
65
|
+
appDir: appDirectory,
|
|
66
|
+
entryPath: builtEntry,
|
|
67
|
+
format: 'module' === moduleType ? 'esm' : 'cjs'
|
|
68
|
+
});
|
|
69
|
+
}
|
|
38
70
|
}
|
|
39
71
|
};
|
|
40
72
|
const generate = async ()=>{
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import node_crypto from "node:crypto";
|
|
3
3
|
import node_fs from "node:fs";
|
|
4
|
+
import { builtinModules } from "node:module";
|
|
4
5
|
import node_path from "node:path";
|
|
5
6
|
import { pathToFileURL } from "node:url";
|
|
6
7
|
import { build, transform } from "esbuild";
|
|
@@ -70,6 +71,81 @@ function preserveSourceModuleSemantics() {
|
|
|
70
71
|
}
|
|
71
72
|
};
|
|
72
73
|
}
|
|
74
|
+
const nodeBuiltins = new Set([
|
|
75
|
+
...builtinModules,
|
|
76
|
+
...builtinModules.map((name)=>`node:${name}`)
|
|
77
|
+
]);
|
|
78
|
+
const dependencyResolutionMarker = 'modern-js-effect-dependency-resolution';
|
|
79
|
+
function isBareSpecifier(specifier) {
|
|
80
|
+
return !specifier.startsWith('.') && !specifier.startsWith('/') && !node_path.isAbsolute(specifier);
|
|
81
|
+
}
|
|
82
|
+
function externalizeInstalledDependencies() {
|
|
83
|
+
return {
|
|
84
|
+
name: 'modern-js-effect-installed-dependencies',
|
|
85
|
+
setup (buildApi) {
|
|
86
|
+
buildApi.onResolve({
|
|
87
|
+
filter: /.*/
|
|
88
|
+
}, async (args)=>{
|
|
89
|
+
if (!isBareSpecifier(args.path) || nodeBuiltins.has(args.path) || args.pluginData?.[dependencyResolutionMarker] === true) return nodeBuiltins.has(args.path) ? {
|
|
90
|
+
external: true,
|
|
91
|
+
path: args.path
|
|
92
|
+
} : void 0;
|
|
93
|
+
const resolution = await buildApi.resolve(args.path, {
|
|
94
|
+
importer: args.importer,
|
|
95
|
+
kind: args.kind,
|
|
96
|
+
namespace: args.namespace,
|
|
97
|
+
pluginData: {
|
|
98
|
+
...args.pluginData,
|
|
99
|
+
[dependencyResolutionMarker]: true
|
|
100
|
+
},
|
|
101
|
+
resolveDir: args.resolveDir
|
|
102
|
+
});
|
|
103
|
+
if (resolution.errors.length > 0) return {
|
|
104
|
+
external: true,
|
|
105
|
+
path: args.path
|
|
106
|
+
};
|
|
107
|
+
if (resolution.external || !resolution.path) return {
|
|
108
|
+
external: true,
|
|
109
|
+
path: args.path
|
|
110
|
+
};
|
|
111
|
+
const realPath = await node_fs.promises.realpath(resolution.path).catch(()=>resolution.path);
|
|
112
|
+
if (realPath.includes(`${node_path.sep}node_modules${node_path.sep}`)) return {
|
|
113
|
+
external: true,
|
|
114
|
+
path: args.path
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
namespace: resolution.namespace,
|
|
118
|
+
path: resolution.path,
|
|
119
|
+
pluginData: resolution.pluginData,
|
|
120
|
+
sideEffects: resolution.sideEffects,
|
|
121
|
+
suffix: resolution.suffix,
|
|
122
|
+
warnings: resolution.warnings,
|
|
123
|
+
watchDirs: resolution.watchDirs,
|
|
124
|
+
watchFiles: resolution.watchFiles
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async function bundleEffectEntryForNode(options) {
|
|
131
|
+
await build({
|
|
132
|
+
absWorkingDir: options.appDir,
|
|
133
|
+
allowOverwrite: true,
|
|
134
|
+
bundle: true,
|
|
135
|
+
entryPoints: [
|
|
136
|
+
options.entryPath
|
|
137
|
+
],
|
|
138
|
+
format: options.format,
|
|
139
|
+
logLevel: 'silent',
|
|
140
|
+
outfile: options.entryPath,
|
|
141
|
+
platform: 'node',
|
|
142
|
+
plugins: [
|
|
143
|
+
externalizeInstalledDependencies(),
|
|
144
|
+
preserveSourceModuleSemantics()
|
|
145
|
+
],
|
|
146
|
+
target: 'node20'
|
|
147
|
+
});
|
|
148
|
+
}
|
|
73
149
|
function isWatchableInput(filename) {
|
|
74
150
|
return !filename.includes(`${node_path.sep}node_modules${node_path.sep}`) && (SOURCE_LOADERS.has(node_path.extname(filename).toLowerCase()) || '.json' === node_path.extname(filename).toLowerCase());
|
|
75
151
|
}
|
|
@@ -104,9 +180,9 @@ async function loadEffectSourceModule(options) {
|
|
|
104
180
|
logLevel: 'silent',
|
|
105
181
|
metafile: true,
|
|
106
182
|
outfile: outputPath,
|
|
107
|
-
packages: 'external',
|
|
108
183
|
platform: 'node',
|
|
109
184
|
plugins: [
|
|
185
|
+
externalizeInstalledDependencies(),
|
|
110
186
|
preserveSourceModuleSemantics()
|
|
111
187
|
],
|
|
112
188
|
sourcemap: 'inline',
|
|
@@ -121,4 +197,4 @@ async function loadEffectSourceModule(options) {
|
|
|
121
197
|
const revision = node_crypto.createHash('sha256').update(output).digest('hex');
|
|
122
198
|
return normalizeImportedModule(await dynamicImport(`${pathToFileURL(outputPath).href}?v=${revision}`));
|
|
123
199
|
}
|
|
124
|
-
export { loadEffectSourceModule };
|
|
200
|
+
export { bundleEffectEntryForNode, loadEffectSourceModule };
|
|
@@ -3,6 +3,11 @@ export type EffectSourceLoaderOptions = {
|
|
|
3
3
|
appDir?: string;
|
|
4
4
|
onDependency?: (dependency: string) => void;
|
|
5
5
|
};
|
|
6
|
+
export declare function bundleEffectEntryForNode(options: {
|
|
7
|
+
appDir: string;
|
|
8
|
+
entryPath: string;
|
|
9
|
+
format: 'cjs' | 'esm';
|
|
10
|
+
}): Promise<void>;
|
|
6
11
|
/**
|
|
7
12
|
* Loads an Effect source entry as native ESM while keeping its complete local
|
|
8
13
|
* source graph observable by the framework watcher.
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"modern",
|
|
18
18
|
"modern.js"
|
|
19
19
|
],
|
|
20
|
-
"version": "3.5.0-ultramodern.
|
|
20
|
+
"version": "3.5.0-ultramodern.89",
|
|
21
21
|
"types": "./dist/types/cli.d.ts",
|
|
22
22
|
"main": "./dist/cjs/cli.js",
|
|
23
23
|
"exports": {
|
|
@@ -154,12 +154,12 @@
|
|
|
154
154
|
},
|
|
155
155
|
"dependencies": {
|
|
156
156
|
"@effect/opentelemetry": "4.0.0-beta.97",
|
|
157
|
-
"@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.5.0-ultramodern.
|
|
158
|
-
"@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.5.0-ultramodern.
|
|
159
|
-
"@modern-js/create-request": "npm:@bleedingdev/modern-js-create-request@3.5.0-ultramodern.
|
|
160
|
-
"@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.5.0-ultramodern.
|
|
161
|
-
"@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.5.0-ultramodern.
|
|
162
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.
|
|
157
|
+
"@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.5.0-ultramodern.89",
|
|
158
|
+
"@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.5.0-ultramodern.89",
|
|
159
|
+
"@modern-js/create-request": "npm:@bleedingdev/modern-js-create-request@3.5.0-ultramodern.89",
|
|
160
|
+
"@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.5.0-ultramodern.89",
|
|
161
|
+
"@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.5.0-ultramodern.89",
|
|
162
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.89",
|
|
163
163
|
"@module-federation/runtime": "2.8.0",
|
|
164
164
|
"@opentelemetry/api": "1.9.1",
|
|
165
165
|
"@opentelemetry/api-logs": "0.220.0",
|
|
@@ -178,11 +178,11 @@
|
|
|
178
178
|
"type-is": "^2.1.0"
|
|
179
179
|
},
|
|
180
180
|
"devDependencies": {
|
|
181
|
-
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.5.0-ultramodern.
|
|
182
|
-
"@modern-js/bff-runtime": "npm:@bleedingdev/modern-js-bff-runtime@3.5.0-ultramodern.
|
|
183
|
-
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.
|
|
184
|
-
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.5.0-ultramodern.
|
|
185
|
-
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.
|
|
181
|
+
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.5.0-ultramodern.89",
|
|
182
|
+
"@modern-js/bff-runtime": "npm:@bleedingdev/modern-js-bff-runtime@3.5.0-ultramodern.89",
|
|
183
|
+
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.89",
|
|
184
|
+
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.5.0-ultramodern.89",
|
|
185
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.89",
|
|
186
186
|
"@rsbuild/core": "2.1.5",
|
|
187
187
|
"@rslib/core": "0.23.2",
|
|
188
188
|
"@scripts/rstest-config": "2.66.0",
|