@umijs/mfsu 4.0.0-beta.13 → 4.0.0-beta.17

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.
@@ -12,6 +12,9 @@ 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 isUmiLocalDev(path) {
16
+ return RE_UMI_LOCAL_DEV.test(path);
17
+ }
15
18
  function checkMatch({ value, path, opts, isExportAll, depth, cache, }) {
16
19
  var _a, _b;
17
20
  let isMatch;
@@ -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)({
@@ -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();
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(),
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,10 +27,11 @@ 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
37
  getBabelPlugins(): (typeof autoExport | (typeof awaitImport | {
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");
@@ -46,72 +48,151 @@ class MFSU {
46
48
  this.depBuilder = new depBuilder_1.DepBuilder({ mfsu: this });
47
49
  this.depInfo.loadCache();
48
50
  }
51
+ // swc don't support top-level await
52
+ // ref: https://github.com/vercel/next.js/issues/31054
53
+ asyncImport(content) {
54
+ return `await import('${content}');`;
55
+ // return `(async () => await import('${content}'))();`;
56
+ }
49
57
  setWebpackConfig(opts) {
50
58
  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;
69
- });
70
- opts.config.entry = entry;
71
- // plugins
72
- opts.config.plugins = opts.config.plugins || [];
73
- // support publicPath auto
74
- let publicPath = opts.config.output.publicPath;
75
- if (publicPath === 'auto') {
76
- publicPath = '/';
59
+ return __awaiter(this, void 0, void 0, function* () {
60
+ const { mfName } = this.opts;
61
+ /**
62
+ * config
63
+ */
64
+ // set alias and externals with reference for babel plugin
65
+ Object.assign(this.alias, ((_a = opts.config.resolve) === null || _a === void 0 ? void 0 : _a.alias) || {});
66
+ this.externals.push(...(0, makeArray_1.makeArray)(opts.config.externals || []));
67
+ // entry
68
+ const entry = {};
69
+ const virtualModules = {};
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)) {
76
+ const virtualPath = `./mfsu-virtual-entry/${key}.js`;
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] = yield (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');
116
+ entry[key] = virtualPath;
117
+ }
118
+ opts.config.entry = entry;
119
+ // plugins
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
+ opts.config.plugins.push(...[
127
+ new webpack_virtual_modules_1.default(virtualModules),
128
+ new this.opts.implementor.container.ModuleFederationPlugin({
129
+ name: '__',
130
+ remotes: {
131
+ [mfName]: this.opts.runtimePublicPath
132
+ ? // ref:
133
+ // https://webpack.js.org/concepts/module-federation/#promise-based-dynamic-remotes
134
+ `
135
+ promise new Promise(resolve => {
136
+ const remoteUrlWithVersion = window.publicPath + '${constants_1.REMOTE_FILE_FULL}';
137
+ const script = document.createElement('script');
138
+ script.src = remoteUrlWithVersion;
139
+ script.onload = () => {
140
+ // the injected script has loaded and is available on window
141
+ // we can now resolve this Promise
142
+ const proxy = {
143
+ get: (request) => window['${mfName}'].get(request),
144
+ init: (arg) => {
145
+ try {
146
+ return window['${mfName}'].init(arg);
147
+ } catch(e) {
148
+ console.log('remote container already initialized');
77
149
  }
78
- opts.config.plugins.push(...[
79
- new webpack_virtual_modules_1.default(virtualModules),
80
- new this.opts.implementor.container.ModuleFederationPlugin({
81
- name: '__',
82
- remotes: {
83
- // TODO: support runtime public path
84
- [mfName]: `${mfName}@${publicPath}${constants_1.REMOTE_FILE_FULL}`,
85
- },
86
- }),
87
- new buildDepPlugin_1.BuildDepPlugin({
88
- onCompileDone: () => {
89
- this.buildDeps().catch((e) => {
90
- utils_1.logger.error(e);
91
- });
92
- },
93
- }),
94
- new writeCachePlugin_1.WriteCachePlugin({
95
- onWriteCache: () => {
96
- this.depInfo.writeCache();
97
- },
98
- }),
99
- ]);
100
- /**
101
- * depConfig
102
- */
103
- this.depConfig = opts.depConfig;
150
+ }
151
+ }
152
+ resolve(proxy);
153
+ }
154
+ // inject this script with the src set to the versioned remoteEntry.js
155
+ document.head.appendChild(script);
156
+ })
157
+ `.trimLeft()
158
+ : `${mfName}@${publicPath}${constants_1.REMOTE_FILE_FULL}`,
159
+ },
160
+ }),
161
+ new buildDepPlugin_1.BuildDepPlugin({
162
+ onCompileDone: () => {
163
+ this.buildDeps().catch((e) => {
164
+ utils_1.logger.error(e);
165
+ });
166
+ },
167
+ }),
168
+ new writeCachePlugin_1.WriteCachePlugin({
169
+ onWriteCache: utils_1.lodash.debounce(() => {
170
+ this.depInfo.writeCache();
171
+ }, 300),
172
+ }),
173
+ ]);
174
+ // ensure topLevelAwait enabled
175
+ utils_1.lodash.set(opts.config, 'experiments.topLevelAwait', true);
176
+ /**
177
+ * depConfig
178
+ */
179
+ this.depConfig = opts.depConfig;
180
+ });
104
181
  }
105
182
  buildDeps() {
106
183
  return __awaiter(this, void 0, void 0, function* () {
107
- if (!this.depInfo.shouldBuild())
184
+ if (!this.depInfo.shouldBuild()) {
185
+ utils_1.logger.info('MFSU skip buildDeps');
108
186
  return;
187
+ }
109
188
  this.depInfo.snapshot();
110
189
  const deps = dep_1.Dep.buildDeps({
111
190
  deps: this.depInfo.moduleGraph.depSnapshotModules,
112
191
  cwd: this.opts.cwd,
113
192
  mfsu: this,
114
193
  });
194
+ utils_1.logger.info('MFSU buildDeps');
195
+ utils_1.logger.debug(deps.map((dep) => dep.file).join(', '));
115
196
  yield this.depBuilder.build({
116
197
  deps,
117
198
  });
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umijs/mfsu",
3
- "version": "4.0.0-beta.13",
3
+ "version": "4.0.0-beta.17",
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,9 +21,9 @@
21
21
  "dev": "pnpm build -- --watch"
22
22
  },
23
23
  "dependencies": {
24
- "@umijs/bundler-esbuild": "4.0.0-beta.13",
25
- "@umijs/bundler-utils": "4.0.0-beta.13",
26
- "@umijs/utils": "4.0.0-beta.13"
24
+ "@umijs/bundler-esbuild": "4.0.0-beta.17",
25
+ "@umijs/bundler-utils": "4.0.0-beta.17",
26
+ "@umijs/utils": "4.0.0-beta.17"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/express": "4.17.13",