@umijs/mfsu 4.0.0-beta.9 → 4.0.0-rc.3

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.
@@ -1,12 +1,13 @@
1
1
  import * as Babel from '@umijs/bundler-utils/compiled/babel/core';
2
2
  import type { IOpts } from './awaitImport';
3
- export declare function checkMatch({ value, path, opts, isExportAll, depth, cache, }: {
3
+ export declare function checkMatch({ value, path, opts, isExportAll, depth, cache, filename, }: {
4
4
  value: string;
5
5
  path?: Babel.NodePath;
6
6
  opts?: IOpts;
7
7
  isExportAll?: boolean;
8
8
  depth?: number;
9
9
  cache?: Map<string, any>;
10
+ filename?: string;
10
11
  }): {
11
12
  isMatch: boolean;
12
13
  replaceValue: string;
@@ -12,7 +12,10 @@ const isExternals_1 = require("./isExternals");
12
12
  // const UNMATCH_LIBS = ['umi', 'dumi', '@alipay/bigfish'];
13
13
  const RE_NODE_MODULES = /node_modules/;
14
14
  const RE_UMI_LOCAL_DEV = /umi(-next)?\/packages\//;
15
- function checkMatch({ value, path, opts, isExportAll, depth, cache, }) {
15
+ function isUmiLocalDev(path) {
16
+ return RE_UMI_LOCAL_DEV.test((0, utils_1.winPath)(path));
17
+ }
18
+ function checkMatch({ value, path, opts, isExportAll, depth, cache, filename, }) {
16
19
  var _a, _b;
17
20
  let isMatch;
18
21
  let replaceValue = '';
@@ -20,6 +23,8 @@ function checkMatch({ value, path, opts, isExportAll, depth, cache, }) {
20
23
  (0, assert_1.default)(depth <= 10, `endless loop detected in checkMatch, please check your alias config.`);
21
24
  opts = opts || {};
22
25
  const remoteName = opts.remoteName || 'mf';
26
+ // FIXME: hard code for vite mode
27
+ value = value.replace(/^@fs\//, '/');
23
28
  if (
24
29
  // unMatch specified libs
25
30
  ((_a = opts.unMatchLibs) === null || _a === void 0 ? void 0 : _a.includes(value)) ||
@@ -38,7 +43,7 @@ function checkMatch({ value, path, opts, isExportAll, depth, cache, }) {
38
43
  isMatch = false;
39
44
  }
40
45
  else if ((0, path_1.isAbsolute)(value)) {
41
- isMatch = RE_NODE_MODULES.test(value) || RE_UMI_LOCAL_DEV.test(value);
46
+ isMatch = RE_NODE_MODULES.test(value) || isUmiLocalDev(value);
42
47
  }
43
48
  else {
44
49
  const aliasedPath = (0, getAliasedPath_1.getAliasedPath)({
@@ -53,6 +58,7 @@ function checkMatch({ value, path, opts, isExportAll, depth, cache, }) {
53
58
  isExportAll,
54
59
  depth: depth + 1,
55
60
  cache,
61
+ filename,
56
62
  });
57
63
  }
58
64
  else {
@@ -63,10 +69,10 @@ function checkMatch({ value, path, opts, isExportAll, depth, cache, }) {
63
69
  isMatch = !!(opts.exportAllMembers && value in opts.exportAllMembers);
64
70
  }
65
71
  if (isMatch) {
66
- replaceValue = `${remoteName}/${value}`;
72
+ replaceValue = `${remoteName}/${(0, utils_1.winPath)(value)}`;
67
73
  }
68
74
  // @ts-ignore
69
- const file = path === null || path === void 0 ? void 0 : path.hub.file.opts.filename;
75
+ const file = (path === null || path === void 0 ? void 0 : path.hub.file.opts.filename) || filename;
70
76
  (_b = opts.onTransformDeps) === null || _b === void 0 ? void 0 : _b.call(opts, {
71
77
  sourceValue: value,
72
78
  replaceValue,
package/dist/dep/dep.js CHANGED
@@ -37,10 +37,10 @@ function resolve(context, path) {
37
37
  }
38
38
  class Dep {
39
39
  constructor(opts) {
40
- this.file = opts.file;
40
+ this.file = (0, utils_1.winPath)(opts.file);
41
41
  this.version = opts.version;
42
42
  this.cwd = opts.cwd;
43
- this.shortFile = this.file.replace(this.cwd, '$CWD$');
43
+ this.shortFile = this.file;
44
44
  this.normalizedFile = this.shortFile.replace(/\//g, '_').replace(/:/g, '_');
45
45
  this.filePath = `${constants_1.MF_VA_PREFIX}${this.normalizedFile}.js`;
46
46
  this.mfsu = opts.mfsu;
@@ -98,7 +98,7 @@ export * from '${this.file}';
98
98
  const dep = (0, path_1.isAbsolute)(opts.dep)
99
99
  ? opts.dep
100
100
  : (0, path_1.join)(opts.cwd, 'node_modules', opts.dep);
101
- const pkg = utils_1.pkgUp.sync({
101
+ const pkg = utils_1.pkgUp.pkgUpSync({
102
102
  cwd: dep,
103
103
  });
104
104
  (0, assert_1.default)(pkg, `package.json not found for ${opts.dep}`);
@@ -63,11 +63,7 @@ class DepBuilder {
63
63
  entry: {
64
64
  [`${constants_1.MF_VA_PREFIX}remoteEntry`]: entryPath,
65
65
  },
66
- config: {
67
- outputPath: tmpDir,
68
- alias: this.opts.mfsu.alias,
69
- externals: this.opts.mfsu.externals,
70
- },
66
+ config: Object.assign(Object.assign({}, this.opts.mfsu.opts.depBuildConfig), { outputPath: tmpDir, alias: this.opts.mfsu.alias, externals: this.opts.mfsu.externals }),
71
67
  inlineStyle: true,
72
68
  });
73
69
  utils_1.logger.event(`[mfsu] compiled with esbuild successfully in ${+new Date() - date} ms`);
@@ -102,6 +98,7 @@ class DepBuilder {
102
98
  writeMFFiles(opts) {
103
99
  return __awaiter(this, void 0, void 0, function* () {
104
100
  const tmpBase = this.opts.mfsu.opts.tmpBase;
101
+ utils_1.fsExtra.mkdirpSync(tmpBase);
105
102
  // expose files
106
103
  for (const dep of opts.deps) {
107
104
  const content = yield dep.buildExposeContent();
@@ -148,7 +145,7 @@ class DepBuilder {
148
145
  webpack: this.opts.mfsu.opts.implementor,
149
146
  }));
150
147
  const exposes = opts.deps.reduce((memo, dep) => {
151
- memo[`./${dep.shortFile}`] = (0, path_1.join)(this.opts.mfsu.opts.tmpBase, dep.filePath);
148
+ memo[`./${dep.file}`] = (0, path_1.join)(this.opts.mfsu.opts.tmpBase, dep.filePath);
152
149
  return memo;
153
150
  }, {});
154
151
  depConfig.plugins.push(new this.opts.mfsu.opts.implementor.container.ModuleFederationPlugin({
@@ -299,15 +299,12 @@ ${opts.deps.map(getDepModuleStr).join(',\n')}
299
299
  `;
300
300
  }
301
301
  exports.getESBuildEntry = getESBuildEntry;
302
- function normalizeFile(file) {
303
- return file.replace(/\//g, '_');
304
- }
305
302
  function getDepModuleStr(dep) {
306
303
  return `
307
304
  "./${dep.file}": function() {
308
305
  return new Promise(resolve => {
309
- import('./${constants_1.MF_VA_PREFIX}${normalizeFile(dep.file)}.js').then(module => {
310
- resolve(() => module);
306
+ import('./${constants_1.MF_VA_PREFIX}${dep.normalizedFile}.js').then(module => {
307
+ resolve(() => module.default || module);
311
308
  });
312
309
  })
313
310
  }
package/dist/depInfo.js CHANGED
@@ -27,6 +27,7 @@ class DepInfo {
27
27
  }
28
28
  loadCache() {
29
29
  if ((0, fs_1.existsSync)(this.cacheFilePath)) {
30
+ utils_1.logger.info('MFSU restore cache');
30
31
  const { cacheDependency, moduleGraph } = JSON.parse((0, fs_1.readFileSync)(this.cacheFilePath, 'utf-8'));
31
32
  this.cacheDependency = cacheDependency;
32
33
  this.moduleGraph.restore(moduleGraph);
@@ -34,6 +35,7 @@ class DepInfo {
34
35
  }
35
36
  writeCache() {
36
37
  utils_1.fsExtra.mkdirpSync((0, path_1.dirname)(this.cacheFilePath));
38
+ utils_1.logger.info('MFSU write cache');
37
39
  (0, fs_1.writeFileSync)(this.cacheFilePath, JSON.stringify({
38
40
  cacheDependency: this.cacheDependency,
39
41
  moduleGraph: this.moduleGraph.toJSON(),
@@ -0,0 +1,2 @@
1
+ import { IEsbuildLoaderHandlerParams } from '../types';
2
+ export declare function autoCssModulesHandler(opts: IEsbuildLoaderHandlerParams): string;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.autoCssModulesHandler = void 0;
4
+ const utils_1 = require("@umijs/utils");
5
+ const CSS_MODULES_QUERY = '?modules';
6
+ const QUERY_LENGTH = CSS_MODULES_QUERY.length;
7
+ function autoCssModulesHandler(opts) {
8
+ let { code } = opts;
9
+ let offset = 0;
10
+ opts.imports.forEach((i) => {
11
+ if (i.d < 0 && (0, utils_1.isStyleFile)({ filename: i.n })) {
12
+ // import x from './index.less'
13
+ // => import x from '
14
+ const importSegment = code.substring(i.ss + offset, i.s + offset);
15
+ // is css module
16
+ if (~importSegment.indexOf(' from')) {
17
+ code = `${code.substring(0, i.e + offset)}${CSS_MODULES_QUERY}${code.substring(i.e + offset)}`;
18
+ offset += QUERY_LENGTH;
19
+ }
20
+ }
21
+ });
22
+ return code;
23
+ }
24
+ exports.autoCssModulesHandler = autoCssModulesHandler;
@@ -0,0 +1,6 @@
1
+ interface IOpts {
2
+ exports: string[];
3
+ code: string;
4
+ }
5
+ export default function autoExportHandler(opts: IOpts): string;
6
+ export {};
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ function autoExportHandler(opts) {
4
+ if (!opts.exports.length) {
5
+ return `${opts.code}\nexport const __mfsu = 1;`;
6
+ }
7
+ return opts.code;
8
+ }
9
+ exports.default = autoExportHandler;
@@ -0,0 +1,12 @@
1
+ import type { ImportSpecifier } from '@umijs/bundler-utils/compiled/es-module-lexer';
2
+ interface IParams {
3
+ cache: Map<string, any>;
4
+ opts: any;
5
+ }
6
+ interface IOpts {
7
+ code: string;
8
+ imports: ImportSpecifier[];
9
+ filePath: string;
10
+ }
11
+ export default function getAwaitImportHandler(params: IParams): (opts: IOpts) => string;
12
+ export {};
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const checkMatch_1 = require("../../babelPlugins/awaitImport/checkMatch");
4
+ function getAwaitImportHandler(params) {
5
+ return function awaitImportHandler(opts) {
6
+ var _a, _b;
7
+ let offset = 0;
8
+ let { code } = opts;
9
+ const { filePath, imports } = opts;
10
+ imports.forEach((i) => {
11
+ if (!i.n)
12
+ return;
13
+ const isLazyImport = i.d > 0;
14
+ const from = i.n;
15
+ const { isMatch, replaceValue } = (0, checkMatch_1.checkMatch)({
16
+ cache: params.cache,
17
+ value: from,
18
+ opts: params.opts,
19
+ filename: filePath,
20
+ });
21
+ if (isMatch) {
22
+ // case: import x from './index.ts';
23
+ // import('./index.ts');
24
+ // import x from '
25
+ // import(
26
+ const preSeg = code.substring(0, i.s + offset);
27
+ // ';
28
+ // );
29
+ const tailSeg = code.substring(i.e + offset);
30
+ const quote = isLazyImport ? '"' : '';
31
+ code = `${preSeg}${quote}${replaceValue}${quote}${tailSeg}`;
32
+ offset += replaceValue.length - from.length;
33
+ }
34
+ });
35
+ if (params.cache.has(filePath)) {
36
+ (_b = (_a = params.opts).onCollect) === null || _b === void 0 ? void 0 : _b.call(_a, {
37
+ file: filePath,
38
+ data: params.cache.get(filePath),
39
+ });
40
+ }
41
+ return code;
42
+ };
43
+ }
44
+ exports.default = getAwaitImportHandler;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  export * from './constants';
2
+ export * from './esbuildHandlers/autoCssModules';
3
+ export { esbuildLoader } from './loader/esbuild';
2
4
  export * from './mfsu';
package/dist/index.js CHANGED
@@ -10,5 +10,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
10
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.esbuildLoader = void 0;
13
14
  __exportStar(require("./constants"), exports);
15
+ __exportStar(require("./esbuildHandlers/autoCssModules"), exports);
16
+ // for independent use `esbuild-loader`
17
+ var esbuild_1 = require("./loader/esbuild");
18
+ Object.defineProperty(exports, "esbuildLoader", { enumerable: true, get: function () { return esbuild_1.esbuildLoader; } });
14
19
  __exportStar(require("./mfsu"), exports);
@@ -0,0 +1,5 @@
1
+ import type { LoaderContext } from 'webpack';
2
+ import type { IEsbuildLoaderOpts } from '../types';
3
+ declare function esbuildTranspiler(this: LoaderContext<IEsbuildLoaderOpts>, source: string): Promise<void>;
4
+ export default esbuildTranspiler;
5
+ export declare const esbuildLoader: string;
@@ -0,0 +1,54 @@
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
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.esbuildLoader = void 0;
24
+ const es_module_lexer_1 = require("@umijs/bundler-utils/compiled/es-module-lexer");
25
+ const esbuild_1 = require("@umijs/bundler-utils/compiled/esbuild");
26
+ const path_1 = require("path");
27
+ function esbuildTranspiler(source) {
28
+ var _a;
29
+ return __awaiter(this, void 0, void 0, function* () {
30
+ const done = this.async();
31
+ const options = this.getOptions();
32
+ const { handler = [], implementation } = options, otherOptions = __rest(options, ["handler", "implementation"]);
33
+ const transform = (implementation === null || implementation === void 0 ? void 0 : implementation.transform) || esbuild_1.transform;
34
+ const filePath = this.resourcePath;
35
+ const ext = (0, path_1.extname)(filePath).slice(1);
36
+ const transformOptions = Object.assign(Object.assign({}, otherOptions), { target: (_a = options.target) !== null && _a !== void 0 ? _a : 'es2015', loader: ext !== null && ext !== void 0 ? ext : 'js', sourcemap: this.sourceMap, sourcefile: filePath });
37
+ try {
38
+ let { code, map } = yield transform(source, transformOptions);
39
+ if (handler.length) {
40
+ yield es_module_lexer_1.init;
41
+ handler.forEach((handle) => {
42
+ const [imports, exports] = (0, es_module_lexer_1.parse)(code);
43
+ code = handle({ code, imports, exports, filePath });
44
+ });
45
+ }
46
+ done(null, code, map && JSON.parse(map));
47
+ }
48
+ catch (error) {
49
+ done(error);
50
+ }
51
+ });
52
+ }
53
+ exports.default = esbuildTranspiler;
54
+ exports.esbuildLoader = __filename;
package/dist/mfsu.d.ts CHANGED
@@ -14,8 +14,10 @@ interface IOpts {
14
14
  mode?: Mode;
15
15
  tmpBase?: string;
16
16
  unMatchLibs?: string[];
17
+ runtimePublicPath?: boolean | string;
17
18
  implementor: typeof webpack;
18
19
  buildDepWithESBuild?: boolean;
20
+ depBuildConfig: any;
19
21
  }
20
22
  export declare class MFSU {
21
23
  opts: IOpts;
@@ -25,13 +27,15 @@ export declare class MFSU {
25
27
  depBuilder: DepBuilder;
26
28
  depConfig: Configuration | null;
27
29
  constructor(opts: IOpts);
30
+ asyncImport(content: string): string;
28
31
  setWebpackConfig(opts: {
29
32
  config: Configuration;
30
33
  depConfig: Configuration;
31
- }): void;
34
+ }): Promise<void>;
32
35
  buildDeps(): Promise<void>;
33
36
  getMiddlewares(): ((req: Request, res: Response, next: NextFunction) => void)[];
34
- getBabelPlugins(): (typeof autoExport | (typeof awaitImport | {
37
+ private getAwaitImportCollectOpts;
38
+ getBabelPlugins(): (typeof autoExport | ({
35
39
  onTransformDeps: () => void;
36
40
  onCollect: ({ file, data, }: {
37
41
  file: string;
@@ -49,6 +53,7 @@ export declare class MFSU {
49
53
  remoteName: string | undefined;
50
54
  alias: Record<string, string>;
51
55
  externals: (Function | Record<string, string>)[];
52
- })[])[];
56
+ } | typeof awaitImport)[])[];
57
+ getEsbuildLoaderHandler(): any[];
53
58
  }
54
59
  export {};
package/dist/mfsu.js CHANGED
@@ -13,7 +13,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.MFSU = void 0;
16
+ const bundler_utils_1 = require("@umijs/bundler-utils");
16
17
  const utils_1 = require("@umijs/utils");
18
+ const assert_1 = __importDefault(require("assert"));
17
19
  const fs_1 = require("fs");
18
20
  const path_1 = require("path");
19
21
  const mrmime_1 = require("../compiled/mrmime");
@@ -26,6 +28,8 @@ const constants_1 = require("./constants");
26
28
  const dep_1 = require("./dep/dep");
27
29
  const depBuilder_1 = require("./depBuilder/depBuilder");
28
30
  const depInfo_1 = require("./depInfo");
31
+ const autoExport_2 = __importDefault(require("./esbuildHandlers/autoExport"));
32
+ const awaitImport_2 = __importDefault(require("./esbuildHandlers/awaitImport"));
29
33
  const types_1 = require("./types");
30
34
  const makeArray_1 = require("./utils/makeArray");
31
35
  const buildDepPlugin_1 = require("./webpackPlugins/buildDepPlugin");
@@ -46,67 +50,151 @@ class MFSU {
46
50
  this.depBuilder = new depBuilder_1.DepBuilder({ mfsu: this });
47
51
  this.depInfo.loadCache();
48
52
  }
53
+ // swc don't support top-level await
54
+ // ref: https://github.com/vercel/next.js/issues/31054
55
+ asyncImport(content) {
56
+ return `await import('${(0, utils_1.winPath)(content)}');`;
57
+ // return `(async () => await import('${content}'))();`;
58
+ }
49
59
  setWebpackConfig(opts) {
50
60
  var _a;
51
- const { mfName } = this.opts;
52
- /**
53
- * config
54
- */
55
- // set alias and externals with reference for babel plugin
56
- Object.assign(this.alias, ((_a = opts.config.resolve) === null || _a === void 0 ? void 0 : _a.alias) || {});
57
- this.externals.push(...(0, makeArray_1.makeArray)(opts.config.externals || []));
58
- // entry
59
- const entry = {};
60
- const virtualModules = {};
61
- Object.keys(opts.config.entry).forEach((key) => {
62
- 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;`;
68
- entry[key] = virtualPath;
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ const { mfName } = this.opts;
63
+ /**
64
+ * config
65
+ */
66
+ // set alias and externals with reference for babel plugin
67
+ Object.assign(this.alias, ((_a = opts.config.resolve) === null || _a === void 0 ? void 0 : _a.alias) || {});
68
+ this.externals.push(...(0, makeArray_1.makeArray)(opts.config.externals || []));
69
+ // entry
70
+ const entry = {};
71
+ const virtualModules = {};
72
+ // ensure entry object type
73
+ const entryObject = utils_1.lodash.isString(opts.config.entry)
74
+ ? { default: [opts.config.entry] }
75
+ : opts.config.entry;
76
+ (0, assert_1.default)(utils_1.lodash.isPlainObject(entryObject), `webpack config 'entry' value must be a string or an object.`);
77
+ for (const key of Object.keys(entryObject)) {
78
+ const virtualPath = `./mfsu-virtual-entry/${key}.js`;
79
+ const virtualContent = [];
80
+ let index = 1;
81
+ let hasDefaultExport = false;
82
+ const entryFiles = utils_1.lodash.isArray(entryObject[key])
83
+ ? entryObject[key]
84
+ : [entryObject[key]];
85
+ for (let entry of entryFiles) {
86
+ // ensure entry is a file
87
+ if ((0, fs_1.statSync)(entry).isDirectory()) {
88
+ const realEntry = (0, utils_1.tryPaths)([
89
+ (0, path_1.join)(entry, 'index.tsx'),
90
+ (0, path_1.join)(entry, 'index.ts'),
91
+ ]);
92
+ (0, assert_1.default)(realEntry, `entry file not found, please configure the specific entry path. (e.g. 'src/index.tsx')`);
93
+ entry = realEntry;
94
+ }
95
+ const content = (0, fs_1.readFileSync)(entry, 'utf-8');
96
+ const [_imports, exports] = yield (0, bundler_utils_1.parseModule)({ content, path: entry });
97
+ if (exports.length) {
98
+ virtualContent.push(`const k${index} = ${this.asyncImport(entry)}`);
99
+ for (const exportName of exports) {
100
+ if (exportName === 'default') {
101
+ hasDefaultExport = true;
102
+ virtualContent.push(`export default k${index}.${exportName}`);
103
+ }
104
+ else {
105
+ virtualContent.push(`export const ${exportName} = k${index}.${exportName}`);
106
+ }
107
+ }
108
+ }
109
+ else {
110
+ virtualContent.push(this.asyncImport(entry));
111
+ }
112
+ index += 1;
113
+ }
114
+ if (!hasDefaultExport) {
115
+ virtualContent.push(`export default 1;`);
116
+ }
117
+ virtualModules[virtualPath] = virtualContent.join('\n');
118
+ entry[key] = virtualPath;
119
+ }
120
+ opts.config.entry = entry;
121
+ // plugins
122
+ opts.config.plugins = opts.config.plugins || [];
123
+ // support publicPath auto
124
+ let publicPath = opts.config.output.publicPath;
125
+ if (publicPath === 'auto') {
126
+ publicPath = '/';
127
+ }
128
+ opts.config.plugins.push(...[
129
+ new webpack_virtual_modules_1.default(virtualModules),
130
+ new this.opts.implementor.container.ModuleFederationPlugin({
131
+ name: '__',
132
+ remotes: {
133
+ [mfName]: this.opts.runtimePublicPath
134
+ ? // ref:
135
+ // https://webpack.js.org/concepts/module-federation/#promise-based-dynamic-remotes
136
+ `
137
+ promise new Promise(resolve => {
138
+ const remoteUrlWithVersion = window.publicPath + '${constants_1.REMOTE_FILE_FULL}';
139
+ const script = document.createElement('script');
140
+ script.src = remoteUrlWithVersion;
141
+ script.onload = () => {
142
+ // the injected script has loaded and is available on window
143
+ // we can now resolve this Promise
144
+ const proxy = {
145
+ get: (request) => window['${mfName}'].get(request),
146
+ init: (arg) => {
147
+ try {
148
+ return window['${mfName}'].init(arg);
149
+ } catch(e) {
150
+ console.log('remote container already initialized');
151
+ }
152
+ }
153
+ }
154
+ resolve(proxy);
155
+ }
156
+ // inject this script with the src set to the versioned remoteEntry.js
157
+ document.head.appendChild(script);
158
+ })
159
+ `.trimLeft()
160
+ : `${mfName}@${publicPath}${constants_1.REMOTE_FILE_FULL}`,
161
+ },
162
+ }),
163
+ new buildDepPlugin_1.BuildDepPlugin({
164
+ onCompileDone: () => {
165
+ this.buildDeps().catch((e) => {
166
+ utils_1.logger.error(e);
167
+ });
168
+ },
169
+ }),
170
+ new writeCachePlugin_1.WriteCachePlugin({
171
+ onWriteCache: utils_1.lodash.debounce(() => {
172
+ this.depInfo.writeCache();
173
+ }, 300),
174
+ }),
175
+ ]);
176
+ // ensure topLevelAwait enabled
177
+ utils_1.lodash.set(opts.config, 'experiments.topLevelAwait', true);
178
+ /**
179
+ * depConfig
180
+ */
181
+ this.depConfig = opts.depConfig;
69
182
  });
70
- opts.config.entry = entry;
71
- // plugins
72
- opts.config.plugins = opts.config.plugins || [];
73
- opts.config.plugins.push(...[
74
- new webpack_virtual_modules_1.default(virtualModules),
75
- new this.opts.implementor.container.ModuleFederationPlugin({
76
- name: '__',
77
- remotes: {
78
- // TODO: support runtime public path
79
- [mfName]: `${mfName}@${opts.config.output.publicPath}${constants_1.REMOTE_FILE_FULL}`,
80
- },
81
- }),
82
- new buildDepPlugin_1.BuildDepPlugin({
83
- 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();
92
- },
93
- }),
94
- ]);
95
- /**
96
- * depConfig
97
- */
98
- this.depConfig = opts.depConfig;
99
183
  }
100
184
  buildDeps() {
101
185
  return __awaiter(this, void 0, void 0, function* () {
102
- if (!this.depInfo.shouldBuild())
186
+ if (!this.depInfo.shouldBuild()) {
187
+ utils_1.logger.info('MFSU skip buildDeps');
103
188
  return;
189
+ }
104
190
  this.depInfo.snapshot();
105
191
  const deps = dep_1.Dep.buildDeps({
106
192
  deps: this.depInfo.moduleGraph.depSnapshotModules,
107
193
  cwd: this.opts.cwd,
108
194
  mfsu: this,
109
195
  });
196
+ utils_1.logger.info('MFSU buildDeps');
197
+ utils_1.logger.debug(deps.map((dep) => dep.file).join(', '));
110
198
  yield this.depBuilder.build({
111
199
  deps,
112
200
  });
@@ -126,7 +214,7 @@ class MFSU {
126
214
  }
127
215
  res.setHeader('content-type', (0, mrmime_1.lookup)((0, path_1.extname)(req.path)) || 'text/plain');
128
216
  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');
217
+ const content = (0, fs_1.readFileSync)((0, path_1.join)(this.opts.tmpBase, relativePath));
130
218
  res.send(content);
131
219
  });
132
220
  }
@@ -136,43 +224,51 @@ class MFSU {
136
224
  },
137
225
  ];
138
226
  }
227
+ getAwaitImportCollectOpts() {
228
+ return {
229
+ onTransformDeps: () => { },
230
+ onCollect: ({ file, data, }) => {
231
+ this.depInfo.moduleGraph.onFileChange({
232
+ file,
233
+ // @ts-ignore
234
+ deps: [
235
+ ...Array.from(data.matched).map((item) => ({
236
+ file: item.sourceValue,
237
+ isDependency: true,
238
+ version: dep_1.Dep.getDepVersion({
239
+ dep: item.sourceValue,
240
+ cwd: this.opts.cwd,
241
+ }),
242
+ })),
243
+ ...Array.from(data.unMatched).map((item) => ({
244
+ file: (0, getRealPath_1.getRealPath)({
245
+ file,
246
+ dep: item.sourceValue,
247
+ }),
248
+ isDependency: false,
249
+ })),
250
+ ],
251
+ });
252
+ },
253
+ exportAllMembers: this.opts.exportAllMembers,
254
+ unMatchLibs: this.opts.unMatchLibs,
255
+ remoteName: this.opts.mfName,
256
+ alias: this.alias,
257
+ externals: this.externals,
258
+ };
259
+ }
139
260
  getBabelPlugins() {
261
+ return [autoExport_1.default, [awaitImport_1.default, this.getAwaitImportCollectOpts()]];
262
+ }
263
+ getEsbuildLoaderHandler() {
264
+ const cache = new Map();
265
+ const checkOpts = this.getAwaitImportCollectOpts();
140
266
  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
- ],
267
+ autoExport_2.default,
268
+ (0, awaitImport_2.default)({
269
+ cache,
270
+ opts: checkOpts,
271
+ }),
176
272
  ];
177
273
  }
178
274
  }
@@ -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
  });
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-rc.3",
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",
@@ -21,15 +21,15 @@
21
21
  "dev": "pnpm build -- --watch"
22
22
  },
23
23
  "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"
24
+ "@umijs/bundler-esbuild": "4.0.0-rc.3",
25
+ "@umijs/bundler-utils": "4.0.0-rc.3",
26
+ "@umijs/utils": "4.0.0-rc.3",
27
+ "enhanced-resolve": "5.9.0"
27
28
  },
28
29
  "devDependencies": {
29
30
  "@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.69.1",
33
33
  "webpack-virtual-modules": "0.4.3"
34
34
  },
35
35
  "publishConfig": {