@umijs/mfsu 4.0.0-beta.9 → 4.0.0-canary.202200505.1

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/mfsu.js CHANGED
@@ -1,52 +1,61 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
12
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
4
  };
14
5
  Object.defineProperty(exports, "__esModule", { value: true });
15
6
  exports.MFSU = void 0;
7
+ const bundler_utils_1 = require("@umijs/bundler-utils");
16
8
  const utils_1 = require("@umijs/utils");
9
+ const assert_1 = __importDefault(require("assert"));
17
10
  const fs_1 = require("fs");
18
11
  const path_1 = require("path");
19
12
  const mrmime_1 = require("../compiled/mrmime");
20
13
  // @ts-ignore
21
14
  const webpack_virtual_modules_1 = __importDefault(require("../compiled/webpack-virtual-modules"));
22
- const autoExport_1 = __importDefault(require("./babelPlugins/autoExport"));
23
15
  const awaitImport_1 = __importDefault(require("./babelPlugins/awaitImport/awaitImport"));
24
16
  const getRealPath_1 = require("./babelPlugins/awaitImport/getRealPath");
25
17
  const constants_1 = require("./constants");
26
18
  const dep_1 = require("./dep/dep");
27
19
  const depBuilder_1 = require("./depBuilder/depBuilder");
28
20
  const depInfo_1 = require("./depInfo");
21
+ const awaitImport_2 = __importDefault(require("./esbuildHandlers/awaitImport"));
29
22
  const types_1 = require("./types");
30
23
  const makeArray_1 = require("./utils/makeArray");
31
24
  const buildDepPlugin_1 = require("./webpackPlugins/buildDepPlugin");
32
- const writeCachePlugin_1 = require("./webpackPlugins/writeCachePlugin");
33
25
  class MFSU {
34
26
  constructor(opts) {
35
27
  this.alias = {};
36
28
  this.externals = [];
37
29
  this.depConfig = null;
30
+ this.buildDepsAgain = false;
31
+ this.progress = { done: false };
32
+ this.publicPath = '/';
38
33
  this.opts = opts;
39
34
  this.opts.mfName = this.opts.mfName || constants_1.DEFAULT_MF_NAME;
40
35
  this.opts.tmpBase =
41
36
  this.opts.tmpBase || (0, path_1.join)(process.cwd(), constants_1.DEFAULT_TMP_DIR_NAME);
42
37
  this.opts.mode = this.opts.mode || types_1.Mode.development;
43
38
  this.opts.getCacheDependency = this.opts.getCacheDependency || (() => ({}));
39
+ this.onProgress = (progress) => {
40
+ var _a, _b;
41
+ this.progress = {
42
+ ...this.progress,
43
+ ...progress,
44
+ };
45
+ (_b = (_a = this.opts).onMFSUProgress) === null || _b === void 0 ? void 0 : _b.call(_a, this.progress);
46
+ };
44
47
  this.opts.cwd = this.opts.cwd || process.cwd();
45
48
  this.depInfo = new depInfo_1.DepInfo({ mfsu: this });
46
49
  this.depBuilder = new depBuilder_1.DepBuilder({ mfsu: this });
47
50
  this.depInfo.loadCache();
48
51
  }
49
- setWebpackConfig(opts) {
52
+ // swc don't support top-level await
53
+ // ref: https://github.com/vercel/next.js/issues/31054
54
+ asyncImport(content) {
55
+ return `await import('${(0, utils_1.winPath)(content)}');`;
56
+ // return `(async () => await import('${content}'))();`;
57
+ }
58
+ async setWebpackConfig(opts) {
50
59
  var _a;
51
60
  const { mfName } = this.opts;
52
61
  /**
@@ -58,64 +67,163 @@ class MFSU {
58
67
  // entry
59
68
  const entry = {};
60
69
  const virtualModules = {};
61
- Object.keys(opts.config.entry).forEach((key) => {
70
+ // ensure entry object type
71
+ const entryObject = utils_1.lodash.isString(opts.config.entry)
72
+ ? { default: [opts.config.entry] }
73
+ : opts.config.entry;
74
+ (0, assert_1.default)(utils_1.lodash.isPlainObject(entryObject), `webpack config 'entry' value must be a string or an object.`);
75
+ for (const key of Object.keys(entryObject)) {
62
76
  const virtualPath = `./mfsu-virtual-entry/${key}.js`;
63
- virtualModules[virtualPath] =
64
- // @ts-ignore
65
- opts.config
66
- .entry[key].map((entry) => `await import('${entry}')`)
67
- .join('\n') + `\nexport default 1;`;
77
+ const virtualContent = [];
78
+ let index = 1;
79
+ let hasDefaultExport = false;
80
+ const entryFiles = utils_1.lodash.isArray(entryObject[key])
81
+ ? entryObject[key]
82
+ : [entryObject[key]];
83
+ for (let entry of entryFiles) {
84
+ // ensure entry is a file
85
+ if ((0, fs_1.statSync)(entry).isDirectory()) {
86
+ const realEntry = (0, utils_1.tryPaths)([
87
+ (0, path_1.join)(entry, 'index.tsx'),
88
+ (0, path_1.join)(entry, 'index.ts'),
89
+ ]);
90
+ (0, assert_1.default)(realEntry, `entry file not found, please configure the specific entry path. (e.g. 'src/index.tsx')`);
91
+ entry = realEntry;
92
+ }
93
+ const content = (0, fs_1.readFileSync)(entry, 'utf-8');
94
+ const [_imports, exports] = await (0, bundler_utils_1.parseModule)({ content, path: entry });
95
+ if (exports.length) {
96
+ virtualContent.push(`const k${index} = ${this.asyncImport(entry)}`);
97
+ for (const exportName of exports) {
98
+ if (exportName === 'default') {
99
+ hasDefaultExport = true;
100
+ virtualContent.push(`export default k${index}.${exportName}`);
101
+ }
102
+ else {
103
+ virtualContent.push(`export const ${exportName} = k${index}.${exportName}`);
104
+ }
105
+ }
106
+ }
107
+ else {
108
+ virtualContent.push(this.asyncImport(entry));
109
+ }
110
+ index += 1;
111
+ }
112
+ if (!hasDefaultExport) {
113
+ virtualContent.push(`export default 1;`);
114
+ }
115
+ virtualModules[virtualPath] = virtualContent.join('\n');
68
116
  entry[key] = virtualPath;
69
- });
117
+ }
70
118
  opts.config.entry = entry;
71
119
  // plugins
72
120
  opts.config.plugins = opts.config.plugins || [];
121
+ // support publicPath auto
122
+ let publicPath = opts.config.output.publicPath;
123
+ if (publicPath === 'auto') {
124
+ publicPath = '/';
125
+ }
126
+ this.publicPath = publicPath;
73
127
  opts.config.plugins.push(...[
74
128
  new webpack_virtual_modules_1.default(virtualModules),
75
129
  new this.opts.implementor.container.ModuleFederationPlugin({
76
130
  name: '__',
77
131
  remotes: {
78
- // TODO: support runtime public path
79
- [mfName]: `${mfName}@${opts.config.output.publicPath}${constants_1.REMOTE_FILE_FULL}`,
132
+ [mfName]: this.opts.runtimePublicPath
133
+ ? // ref:
134
+ // https://webpack.js.org/concepts/module-federation/#promise-based-dynamic-remotes
135
+ `
136
+ promise new Promise(resolve => {
137
+ const remoteUrlWithVersion = window.publicPath + '${constants_1.REMOTE_FILE_FULL}';
138
+ const script = document.createElement('script');
139
+ script.src = remoteUrlWithVersion;
140
+ script.onload = () => {
141
+ // the injected script has loaded and is available on window
142
+ // we can now resolve this Promise
143
+ const proxy = {
144
+ get: (request) => window['${mfName}'].get(request),
145
+ init: (arg) => {
146
+ try {
147
+ return window['${mfName}'].init(arg);
148
+ } catch(e) {
149
+ console.log('remote container already initialized');
150
+ }
151
+ }
152
+ }
153
+ resolve(proxy);
154
+ }
155
+ // inject this script with the src set to the versioned remoteEntry.js
156
+ document.head.appendChild(script);
157
+ })
158
+ `.trimLeft()
159
+ : `${mfName}@${publicPath}${constants_1.REMOTE_FILE_FULL}`,
80
160
  },
81
161
  }),
82
162
  new buildDepPlugin_1.BuildDepPlugin({
83
163
  onCompileDone: () => {
84
- this.buildDeps().catch((e) => {
85
- utils_1.logger.error(e);
86
- });
87
- },
88
- }),
89
- new writeCachePlugin_1.WriteCachePlugin({
90
- onWriteCache: () => {
91
- this.depInfo.writeCache();
164
+ if (this.depBuilder.isBuilding) {
165
+ this.buildDepsAgain = true;
166
+ }
167
+ else {
168
+ this.buildDeps()
169
+ .then(() => {
170
+ this.onProgress({
171
+ done: true,
172
+ });
173
+ })
174
+ .catch((e) => {
175
+ utils_1.logger.error(e);
176
+ this.onProgress({
177
+ done: true,
178
+ });
179
+ });
180
+ }
92
181
  },
93
182
  }),
183
+ // new WriteCachePlugin({
184
+ // onWriteCache: lodash.debounce(() => {
185
+ // this.depInfo.writeCache();
186
+ // }, 300),
187
+ // }),
94
188
  ]);
189
+ // ensure topLevelAwait enabled
190
+ utils_1.lodash.set(opts.config, 'experiments.topLevelAwait', true);
95
191
  /**
96
192
  * depConfig
97
193
  */
98
194
  this.depConfig = opts.depConfig;
99
195
  }
100
- buildDeps() {
101
- return __awaiter(this, void 0, void 0, function* () {
102
- if (!this.depInfo.shouldBuild())
103
- return;
104
- this.depInfo.snapshot();
105
- const deps = dep_1.Dep.buildDeps({
106
- deps: this.depInfo.moduleGraph.depSnapshotModules,
107
- cwd: this.opts.cwd,
108
- mfsu: this,
109
- });
110
- yield this.depBuilder.build({
111
- deps,
112
- });
196
+ async buildDeps() {
197
+ const shouldBuild = this.depInfo.shouldBuild();
198
+ if (!shouldBuild) {
199
+ utils_1.logger.info('MFSU skip buildDeps');
200
+ return;
201
+ }
202
+ this.depInfo.snapshot();
203
+ const deps = dep_1.Dep.buildDeps({
204
+ deps: this.depInfo.moduleGraph.depSnapshotModules,
205
+ cwd: this.opts.cwd,
206
+ mfsu: this,
207
+ });
208
+ utils_1.logger.info(`MFSU buildDeps since ${shouldBuild}`);
209
+ utils_1.logger.debug(deps.map((dep) => dep.file).join(', '));
210
+ await this.depBuilder.build({
211
+ deps,
113
212
  });
213
+ // Write cache
214
+ this.depInfo.writeCache();
215
+ if (this.buildDepsAgain) {
216
+ utils_1.logger.info('MFSU buildDepsAgain');
217
+ this.buildDepsAgain = false;
218
+ this.buildDeps().catch((e) => {
219
+ utils_1.logger.error(e);
220
+ });
221
+ }
114
222
  }
115
223
  getMiddlewares() {
116
224
  return [
117
225
  (req, res, next) => {
118
- const publicPath = '/';
226
+ const publicPath = this.publicPath;
119
227
  const isMF = req.path.startsWith(`${publicPath}${constants_1.MF_VA_PREFIX}`) ||
120
228
  req.path.startsWith(`${publicPath}${constants_1.MF_DEP_PREFIX}`) ||
121
229
  req.path.startsWith(`${publicPath}${constants_1.MF_STATIC_PREFIX}`);
@@ -126,7 +234,7 @@ class MFSU {
126
234
  }
127
235
  res.setHeader('content-type', (0, mrmime_1.lookup)((0, path_1.extname)(req.path)) || 'text/plain');
128
236
  const relativePath = req.path.replace(new RegExp(`^${publicPath}`), '/');
129
- const content = (0, fs_1.readFileSync)((0, path_1.join)(this.opts.tmpBase, relativePath), 'utf-8');
237
+ const content = (0, fs_1.readFileSync)((0, path_1.join)(this.opts.tmpBase, relativePath));
130
238
  res.send(content);
131
239
  });
132
240
  }
@@ -136,43 +244,50 @@ class MFSU {
136
244
  },
137
245
  ];
138
246
  }
247
+ getAwaitImportCollectOpts() {
248
+ return {
249
+ onTransformDeps: () => { },
250
+ onCollect: ({ file, data, }) => {
251
+ this.depInfo.moduleGraph.onFileChange({
252
+ file,
253
+ // @ts-ignore
254
+ deps: [
255
+ ...Array.from(data.matched).map((item) => ({
256
+ file: item.sourceValue,
257
+ isDependency: true,
258
+ version: dep_1.Dep.getDepVersion({
259
+ dep: item.sourceValue,
260
+ cwd: this.opts.cwd,
261
+ }),
262
+ })),
263
+ ...Array.from(data.unMatched).map((item) => ({
264
+ file: (0, getRealPath_1.getRealPath)({
265
+ file,
266
+ dep: item.sourceValue,
267
+ }),
268
+ isDependency: false,
269
+ })),
270
+ ],
271
+ });
272
+ },
273
+ exportAllMembers: this.opts.exportAllMembers,
274
+ unMatchLibs: this.opts.unMatchLibs,
275
+ remoteName: this.opts.mfName,
276
+ alias: this.alias,
277
+ externals: this.externals,
278
+ };
279
+ }
139
280
  getBabelPlugins() {
281
+ return [[awaitImport_1.default, this.getAwaitImportCollectOpts()]];
282
+ }
283
+ getEsbuildLoaderHandler() {
284
+ const cache = new Map();
285
+ const checkOpts = this.getAwaitImportCollectOpts();
140
286
  return [
141
- autoExport_1.default,
142
- [
143
- awaitImport_1.default,
144
- {
145
- onTransformDeps: () => { },
146
- onCollect: ({ file, data, }) => {
147
- this.depInfo.moduleGraph.onFileChange({
148
- file,
149
- // @ts-ignore
150
- deps: [
151
- ...Array.from(data.matched).map((item) => ({
152
- file: item.sourceValue,
153
- isDependency: true,
154
- version: dep_1.Dep.getDepVersion({
155
- dep: item.sourceValue,
156
- cwd: this.opts.cwd,
157
- }),
158
- })),
159
- ...Array.from(data.unMatched).map((item) => ({
160
- file: (0, getRealPath_1.getRealPath)({
161
- file,
162
- dep: item.sourceValue,
163
- }),
164
- isDependency: false,
165
- })),
166
- ],
167
- });
168
- },
169
- exportAllMembers: this.opts.exportAllMembers,
170
- unMatchLibs: this.opts.unMatchLibs,
171
- remoteName: this.opts.mfName,
172
- alias: this.alias,
173
- externals: this.externals,
174
- },
175
- ],
287
+ (0, awaitImport_2.default)({
288
+ cache,
289
+ opts: checkOpts,
290
+ }),
176
291
  ];
177
292
  }
178
293
  }
@@ -31,6 +31,7 @@ export declare class ModuleGraph {
31
31
  roots: string[];
32
32
  fileModules: Record<string, {
33
33
  importedModules: string[];
34
+ isRoot?: boolean | undefined;
34
35
  }>;
35
36
  depModules: Record<string, {
36
37
  version: string | null;
@@ -20,7 +20,12 @@ class ModuleGraph {
20
20
  this.rootModules = new Set();
21
21
  }
22
22
  restore(data) {
23
+ let fileMap = new Map();
23
24
  const addNode = ({ file, importer }) => {
25
+ // fix circular dependency
26
+ if (fileMap.has(file))
27
+ return;
28
+ fileMap.set(file, true);
24
29
  const mod = new ModuleNode(file);
25
30
  let isDependency = false;
26
31
  let info;
@@ -33,8 +38,10 @@ class ModuleGraph {
33
38
  }
34
39
  if (info.isRoot)
35
40
  mod.isRoot = true;
36
- if (importer)
41
+ if (importer) {
37
42
  mod.importers.add(importer);
43
+ importer.importedModules.add(mod);
44
+ }
38
45
  mod.isDependency = isDependency;
39
46
  if (info.version !== undefined) {
40
47
  mod.version = info.version;
@@ -68,6 +75,7 @@ class ModuleGraph {
68
75
  importedModules: Array.from(value.importedModules).map((item) => item.file),
69
76
  };
70
77
  if (value.isRoot) {
78
+ fileModules[key].isRoot = true;
71
79
  roots.push(key);
72
80
  }
73
81
  });
@@ -143,7 +151,7 @@ class ModuleGraph {
143
151
  this.deleteNode({ mod: importedModulesMap[key], importer: opts.mod });
144
152
  });
145
153
  newDeps.forEach((dep) => {
146
- this.addNode(Object.assign(Object.assign({}, dep), { importer: opts.mod }));
154
+ this.addNode({ ...dep, importer: opts.mod });
147
155
  });
148
156
  }
149
157
  addNode(opts) {
package/dist/types.d.ts CHANGED
@@ -1,4 +1,16 @@
1
+ import type { ImportSpecifier } from '@umijs/bundler-utils/compiled/es-module-lexer';
2
+ import type { TransformOptions } from '@umijs/bundler-utils/compiled/esbuild';
1
3
  export declare enum Mode {
2
4
  development = "development",
3
5
  production = "production"
4
6
  }
7
+ export interface IEsbuildLoaderHandlerParams {
8
+ code: string;
9
+ filePath: string;
10
+ imports: readonly ImportSpecifier[];
11
+ exports: readonly string[];
12
+ }
13
+ export interface IEsbuildLoaderOpts extends Partial<TransformOptions> {
14
+ handler?: Array<(opts: IEsbuildLoaderHandlerParams) => string>;
15
+ implementation?: typeof import('@umijs/bundler-utils/compiled/esbuild');
16
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umijs/mfsu",
3
- "version": "4.0.0-beta.9",
3
+ "version": "4.0.0-canary.202200505.1",
4
4
  "description": "@umijs/mfsu",
5
5
  "homepage": "https://github.com/umijs/umi-next/tree/master/packages/mfsu#readme",
6
6
  "bugs": "https://github.com/umijs/umi-next/issues",
@@ -17,19 +17,19 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "build": "pnpm tsc",
20
- "build:deps": "pnpm esno ../../scripts/bundleDeps.ts",
21
- "dev": "pnpm build -- --watch"
20
+ "build:deps": "umi-scripts bundleDeps",
21
+ "dev": "pnpm build -- --watch",
22
+ "test": "umi-scripts jest-turbo"
22
23
  },
23
24
  "dependencies": {
24
- "@umijs/bundler-esbuild": "4.0.0-beta.9",
25
- "@umijs/bundler-utils": "4.0.0-beta.9",
26
- "@umijs/utils": "4.0.0-beta.9"
25
+ "@umijs/bundler-esbuild": "4.0.0-canary.202200505.1",
26
+ "@umijs/bundler-utils": "4.0.0-canary.202200505.1",
27
+ "@umijs/utils": "4.0.0-canary.202200505.1",
28
+ "enhanced-resolve": "5.9.2"
27
29
  },
28
30
  "devDependencies": {
29
- "@types/express": "4.17.13",
30
- "enhanced-resolve": "5.8.3",
31
31
  "mrmime": "1.0.0",
32
- "webpack": "5.61.0",
32
+ "webpack": "5.72.0",
33
33
  "webpack-virtual-modules": "0.4.3"
34
34
  },
35
35
  "publishConfig": {
@@ -1,7 +0,0 @@
1
- import * as Babel from '@umijs/bundler-utils/compiled/babel/core';
2
- import * as t from '@umijs/bundler-utils/compiled/babel/types';
3
- export default function (): {
4
- visitor: {
5
- Program(path: Babel.NodePath<t.Program>): void;
6
- };
7
- };
@@ -1,61 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
- Object.defineProperty(exports, "__esModule", { value: true });
22
- const t = __importStar(require("@umijs/bundler-utils/compiled/babel/types"));
23
- function default_1() {
24
- return {
25
- visitor: {
26
- Program(path) {
27
- let hasExport = false;
28
- path.node.body.forEach((node) => {
29
- if (
30
- // esm
31
- t.isExportNamedDeclaration(node) ||
32
- t.isExportDefaultDeclaration(node) ||
33
- t.isExportAllDeclaration(node) ||
34
- // cjs
35
- (t.isExpressionStatement(node) &&
36
- t.isAssignmentExpression(node.expression) &&
37
- t.isMemberExpression(node.expression.left) &&
38
- // exports.xxx =
39
- (t.isIdentifier(node.expression.left.object, {
40
- name: 'exports',
41
- }) ||
42
- // module.exports =
43
- (t.isIdentifier(node.expression.left.object, {
44
- name: 'module',
45
- }) &&
46
- t.isIdentifier(node.expression.left.property, {
47
- name: 'exports',
48
- }))))) {
49
- hasExport = true;
50
- }
51
- });
52
- if (!hasExport) {
53
- path.node.body.push(t.exportNamedDeclaration(t.variableDeclaration('const', [
54
- t.variableDeclarator(t.identifier('__mfsu'), t.numericLiteral(1)),
55
- ])));
56
- }
57
- },
58
- },
59
- };
60
- }
61
- exports.default = default_1;