@umijs/mfsu 4.0.0-beta.6 → 4.0.0-rc.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 SysGears
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ (function(){"use strict";var e={636:function(e,t,r){var i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const a=i(r(622));const s=r(570);let n=45e6;function checkActivation(e){if(!e._compiler){throw new Error("You must use this plugin only after creating webpack instance!")}}function getModulePath(e,t){return a.default.isAbsolute(e)?e:a.default.join(t.context,e)}function createWebpackData(e){return t=>{if(t._data){const r=t._currentLevel;const i=t._levels[r];return{result:e,level:i}}return[null,e]}}function getData(e,t){if(e._data instanceof Map){return e._data.get(t)}else if(e._data){return e.data[t]}else if(e.data instanceof Map){return e.data.get(t)}else{return e.data[t]}}function setData(e,t,r){const i=r(e);if(e._data instanceof Map){e._data.set(t,i)}else if(e._data){e.data[t]=i}else if(e.data instanceof Map){e.data.set(t,i)}else{e.data[t]=i}}function getStatStorage(e){if(e._statStorage){return e._statStorage}else if(e._statBackend){return e._statBackend}else{throw new Error("Couldn't find a stat storage")}}function getFileStorage(e){if(e._readFileStorage){return e._readFileStorage}else if(e._readFileBackend){return e._readFileBackend}else{throw new Error("Couldn't find a readFileStorage")}}function getReadDirBackend(e){if(e._readdirBackend){return e._readdirBackend}else if(e._readdirStorage){return e._readdirStorage}else{throw new Error("Couldn't find a readDirStorage from Webpack Internals")}}class VirtualModulesPlugin{constructor(e){this._compiler=null;this._watcher=null;this._staticModules=e||null}writeModule(e,t){if(!this._compiler){throw new Error(`Plugin has not been initialized`)}checkActivation(this);const r=t?t.length:0;const i=Date.now();const a=new Date(i);const o=new s.VirtualStats({dev:8675309,nlink:0,uid:1e3,gid:1e3,rdev:0,blksize:4096,ino:n++,mode:33188,size:r,blocks:Math.floor(r/4096),atime:a,mtime:a,ctime:a,birthtime:a});const l=getModulePath(e,this._compiler);if(process.env.WVM_DEBUG)console.log(this._compiler.name,"Write virtual module:",l,t);let c=this._watcher&&this._watcher.watchFileSystem;while(c&&c.wfs){c=c.wfs}let u=this._compiler.inputFileSystem;while(u&&u._inputFileSystem){u=u._inputFileSystem}u._writeVirtualFile(l,o,t);if(c&&(c.watcher.fileWatchers.size||c.watcher.fileWatchers.length)){const t=c.watcher.fileWatchers instanceof Map?Array.from(c.watcher.fileWatchers.values()):c.watcher.fileWatchers;for(const r of t){if(r.path===l){if(process.env.DEBUG)console.log(this._compiler.name,"Emit file change:",l,i);delete r.directoryWatcher._cachedTimeInfoEntries;r.directoryWatcher.setFileTime(e,i,false,false,null);r.emit("change",i,null)}}}}apply(e){this._compiler=e;const afterEnvironmentHook=()=>{let t=e.inputFileSystem;while(t&&t._inputFileSystem){t=t._inputFileSystem}if(!t._writeVirtualFile){const e=t.purge;t.purge=()=>{e.apply(t,[]);if(t._virtualFiles){Object.keys(t._virtualFiles).forEach((e=>{const r=t._virtualFiles[e];t._writeVirtualFile(e,r.stats,r.contents)}))}};t._writeVirtualFile=(e,r,i)=>{const o=getStatStorage(t);const l=getFileStorage(t);const c=getReadDirBackend(t);t._virtualFiles=t._virtualFiles||{};t._virtualFiles[e]={stats:r,contents:i};setData(o,e,createWebpackData(r));setData(l,e,createWebpackData(i));const u=e.split(/[\\/]/);let d=u.length-1;const _=u[0]?1:0;while(d>_){const e=u.slice(0,d).join(a.default.sep)||a.default.sep;try{t.readdirSync(e)}catch(t){const i=Date.now();const a=new s.VirtualStats({dev:8675309,nlink:0,uid:1e3,gid:1e3,rdev:0,blksize:4096,ino:n++,mode:16877,size:r.size,blocks:Math.floor(r.size/4096),atime:i,mtime:i,ctime:i,birthtime:i});setData(c,e,createWebpackData([]));setData(o,e,createWebpackData(a))}let i=getData(getReadDirBackend(t),e);i=i[1]||i.result;const l=u[d];if(i.indexOf(l)<0){const r=i.concat([l]).sort();setData(getReadDirBackend(t),e,createWebpackData(r))}else{break}d--}}}};const afterResolversHook=()=>{if(this._staticModules){for(const[e,t]of Object.entries(this._staticModules)){this.writeModule(e,t)}this._staticModules=null}};const watchRunHook=(t,r)=>{this._watcher=t.compiler||t;const i=e.inputFileSystem._virtualFiles;const a=e.fileTimestamps;if(i&&a&&typeof a.set==="function"){Object.keys(i).forEach((e=>{a.set(e,+i[e].stats.mtime)}))}r()};if(e.hooks){e.hooks.afterEnvironment.tap("VirtualModulesPlugin",afterEnvironmentHook);e.hooks.afterResolvers.tap("VirtualModulesPlugin",afterResolversHook);e.hooks.watchRun.tapAsync("VirtualModulesPlugin",watchRunHook)}else{e.plugin("after-environment",afterEnvironmentHook);e.plugin("after-resolvers",afterResolversHook);e.plugin("watch-run",watchRunHook)}}}e.exports=VirtualModulesPlugin},570:function(e,t,r){var i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:true});t.VirtualStats=void 0;const a=i(r(619));class VirtualStats{constructor(e){for(const t in e){if(!Object.prototype.hasOwnProperty.call(e,t)){continue}this[t]=e[t]}}_checkModeProperty(e){return(this.mode&a.default.S_IFMT)===e}isDirectory(){return this._checkModeProperty(a.default.S_IFDIR)}isFile(){return this._checkModeProperty(a.default.S_IFREG)}isBlockDevice(){return this._checkModeProperty(a.default.S_IFBLK)}isCharacterDevice(){return this._checkModeProperty(a.default.S_IFCHR)}isSymbolicLink(){return this._checkModeProperty(a.default.S_IFLNK)}isFIFO(){return this._checkModeProperty(a.default.S_IFIFO)}isSocket(){return this._checkModeProperty(a.default.S_IFSOCK)}}t.VirtualStats=VirtualStats},619:function(e){e.exports=require("constants")},622:function(e){e.exports=require("path")}};var t={};function __nccwpck_require__(r){var i=t[r];if(i!==undefined){return i.exports}var a=t[r]={exports:{}};var s=true;try{e[r].call(a.exports,a,a.exports,__nccwpck_require__);s=false}finally{if(s)delete t[r]}return a.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var r=__nccwpck_require__(636);module.exports=r})();
@@ -0,0 +1 @@
1
+ {"name":"webpack-virtual-modules","author":"SysGears INC","license":"MIT"}
@@ -18,8 +18,10 @@ export default function (): {
18
18
  opts: IOpts;
19
19
  }): void;
20
20
  };
21
- CallExpression(path: Babel.NodePath<t.CallExpression>, { opts }: {
22
- opts: IOpts;
23
- }): void;
21
+ CallExpression: {
22
+ exit(path: Babel.NodePath<t.CallExpression>, { opts }: {
23
+ opts: IOpts;
24
+ }): void;
25
+ };
24
26
  };
25
27
  };
@@ -21,10 +21,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
22
  const t = __importStar(require("@umijs/bundler-utils/compiled/babel/types"));
23
23
  const checkMatch_1 = require("./checkMatch");
24
- const parseSpecifiers_1 = require("./parseSpecifiers");
25
- function isCSS(val) {
26
- return /\.(css|less|sass|scss|stylus|styl)(\?.+?)?$/.test(val);
27
- }
28
24
  function default_1() {
29
25
  return {
30
26
  pre() {
@@ -46,9 +42,6 @@ function default_1() {
46
42
  visitor: {
47
43
  Program: {
48
44
  exit(path, { opts }) {
49
- var _a;
50
- const topDeclarations = [];
51
- const bottomDeclarations = [];
52
45
  let index = path.node.body.length - 1;
53
46
  while (index >= 0) {
54
47
  const node = path.node.body[index];
@@ -64,25 +57,8 @@ function default_1() {
64
57
  opts,
65
58
  path,
66
59
  });
67
- if (isMatch || isCSS(node.source.value)) {
68
- path.node.body.splice(index, 1);
69
- const { properties, namespaceIdentifier } = (0, parseSpecifiers_1.parseSpecifiers)(node.specifiers);
70
- const id = t.objectPattern(properties);
71
- const init = t.awaitExpression(t.callExpression(t.import(), [
72
- t.stringLiteral(isMatch ? replaceValue : node.source.value),
73
- ]));
74
- if (namespaceIdentifier) {
75
- topDeclarations.unshift(t.variableDeclaration('const', [
76
- t.variableDeclarator(namespaceIdentifier, init),
77
- properties.length &&
78
- t.variableDeclarator(id, namespaceIdentifier),
79
- ].filter(Boolean)));
80
- }
81
- else {
82
- topDeclarations.unshift(t.variableDeclaration('const', [
83
- t.variableDeclarator(id, init),
84
- ]));
85
- }
60
+ if (isMatch) {
61
+ node.source.value = replaceValue;
86
62
  }
87
63
  }
88
64
  // export * from 'x';
@@ -93,28 +69,9 @@ function default_1() {
93
69
  value: node.source.value,
94
70
  opts,
95
71
  path,
96
- isExportAll: true,
97
72
  });
98
73
  if (isMatch) {
99
- const members = ((_a = opts.exportAllMembers) === null || _a === void 0 ? void 0 : _a[node.source.value]) || [];
100
- if (members.length) {
101
- const id = t.identifier(`__all_exports_${node.source.value.replace(/([@\/\-])/g, '_')}`);
102
- const init = t.awaitExpression(t.callExpression(t.import(), [
103
- t.stringLiteral(replaceValue),
104
- ]));
105
- topDeclarations.unshift(t.variableDeclaration('const', [
106
- t.variableDeclarator(id, init),
107
- ]));
108
- // replace node with export const { a, b, c } = __all_exports
109
- // a, b, c was declared from opts.exportAllMembers
110
- path.node.body[index] = t.exportNamedDeclaration(t.variableDeclaration('const', [
111
- t.variableDeclarator(t.objectPattern(members.map((m) => t.objectProperty(t.identifier(m), t.identifier(m)))), id),
112
- ]));
113
- }
114
- // 有些 export * 只是为了类型
115
- else {
116
- path.node.body[index] = t.expressionStatement(t.numericLiteral(1));
117
- }
74
+ node.source.value = replaceValue;
118
75
  }
119
76
  }
120
77
  // export { x } from 'x';
@@ -127,56 +84,31 @@ function default_1() {
127
84
  path,
128
85
  });
129
86
  if (isMatch) {
130
- const { properties, defaultIdentifier } = (0, parseSpecifiers_1.parseSpecifiers)(node.specifiers);
131
- const id = t.objectPattern(properties);
132
- const init = t.awaitExpression(t.callExpression(t.import(), [t.stringLiteral(replaceValue)]));
133
- topDeclarations.unshift(t.variableDeclaration('const', [
134
- t.variableDeclarator(id, init),
135
- ]));
136
- node.source = null;
137
- node.specifiers = node.specifiers.filter((specifier) => {
138
- if (t.isExportSpecifier(specifier) &&
139
- t.isIdentifier(specifier.local) &&
140
- t.isIdentifier(specifier.exported)) {
141
- specifier.local = specifier.exported;
142
- }
143
- return !(t.isExportSpecifier(specifier) &&
144
- t.isIdentifier(specifier.exported) &&
145
- specifier.exported.name === 'default');
146
- });
147
- if (!node.specifiers.length) {
148
- path.node.body.splice(index, 1);
149
- }
150
- if (defaultIdentifier) {
151
- bottomDeclarations.push(t.exportDefaultDeclaration(t.identifier(defaultIdentifier)));
152
- }
87
+ node.source.value = replaceValue;
153
88
  }
154
89
  }
155
90
  index -= 1;
156
91
  }
157
- path.node.body = [
158
- ...topDeclarations,
159
- ...path.node.body,
160
- ...bottomDeclarations,
161
- ];
162
92
  },
163
93
  },
164
- CallExpression(path, { opts }) {
165
- const { node } = path;
166
- if (t.isImport(node.callee) &&
167
- node.arguments.length === 1 &&
168
- node.arguments[0].type === 'StringLiteral') {
169
- const { isMatch, replaceValue } = (0, checkMatch_1.checkMatch)({
170
- // @ts-ignore
171
- cache: this.cache,
172
- value: node.arguments[0].value,
173
- opts,
174
- path,
175
- });
176
- if (isMatch) {
177
- node.arguments[0] = t.stringLiteral(replaceValue);
94
+ CallExpression: {
95
+ exit(path, { opts }) {
96
+ const { node } = path;
97
+ if (t.isImport(node.callee) &&
98
+ node.arguments.length === 1 &&
99
+ node.arguments[0].type === 'StringLiteral') {
100
+ const { isMatch, replaceValue } = (0, checkMatch_1.checkMatch)({
101
+ // @ts-ignore
102
+ cache: this.cache,
103
+ value: node.arguments[0].value,
104
+ opts,
105
+ path,
106
+ });
107
+ if (isMatch) {
108
+ node.arguments[0] = t.stringLiteral(replaceValue);
109
+ }
178
110
  }
179
- }
111
+ },
180
112
  },
181
113
  },
182
114
  };
@@ -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(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 {
@@ -66,7 +72,7 @@ function checkMatch({ value, path, opts, isExportAll, depth, cache, }) {
66
72
  replaceValue = `${remoteName}/${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.d.ts CHANGED
@@ -23,4 +23,8 @@ export declare class Dep {
23
23
  cwd: string;
24
24
  mfsu: MFSU;
25
25
  }): Dep[];
26
+ static getDepVersion(opts: {
27
+ dep: string;
28
+ cwd: string;
29
+ }): string;
26
30
  }
package/dist/dep/dep.js CHANGED
@@ -13,9 +13,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.Dep = void 0;
16
+ const utils_1 = require("@umijs/utils");
16
17
  const assert_1 = __importDefault(require("assert"));
17
18
  const enhanced_resolve_1 = __importDefault(require("enhanced-resolve"));
18
19
  const fs_1 = require("fs");
20
+ const path_1 = require("path");
19
21
  const constants_1 = require("../constants");
20
22
  const trimFileContent_1 = require("../utils/trimFileContent");
21
23
  const getExposeFromContent_1 = require("./getExposeFromContent");
@@ -38,7 +40,7 @@ class Dep {
38
40
  this.file = opts.file;
39
41
  this.version = opts.version;
40
42
  this.cwd = opts.cwd;
41
- this.shortFile = this.file.replace(this.cwd, '$CWD$');
43
+ this.shortFile = this.file;
42
44
  this.normalizedFile = this.shortFile.replace(/\//g, '_').replace(/:/g, '_');
43
45
  this.filePath = `${constants_1.MF_VA_PREFIX}${this.normalizedFile}.js`;
44
46
  this.mfsu = opts.mfsu;
@@ -88,5 +90,19 @@ export * from '${this.file}';
88
90
  return new Dep(Object.assign(Object.assign({}, opts.deps[file]), { cwd: opts.cwd, mfsu: opts.mfsu }));
89
91
  });
90
92
  }
93
+ static getDepVersion(opts) {
94
+ // @ts-ignore
95
+ if (!!process.binding('natives')[opts.dep]) {
96
+ return '*';
97
+ }
98
+ const dep = (0, path_1.isAbsolute)(opts.dep)
99
+ ? opts.dep
100
+ : (0, path_1.join)(opts.cwd, 'node_modules', opts.dep);
101
+ const pkg = utils_1.pkgUp.sync({
102
+ cwd: dep,
103
+ });
104
+ (0, assert_1.default)(pkg, `package.json not found for ${opts.dep}`);
105
+ return require(pkg).version;
106
+ }
91
107
  }
92
108
  exports.Dep = Dep;
@@ -63,11 +63,8 @@ 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 }),
67
+ inlineStyle: true,
71
68
  });
72
69
  utils_1.logger.event(`[mfsu] compiled with esbuild successfully in ${+new Date() - date} ms`);
73
70
  opts.onBuildComplete();
@@ -101,6 +98,7 @@ class DepBuilder {
101
98
  writeMFFiles(opts) {
102
99
  return __awaiter(this, void 0, void 0, function* () {
103
100
  const tmpBase = this.opts.mfsu.opts.tmpBase;
101
+ utils_1.fsExtra.mkdirpSync(tmpBase);
104
102
  // expose files
105
103
  for (const dep of opts.deps) {
106
104
  const content = yield dep.buildExposeContent();
@@ -147,7 +145,7 @@ class DepBuilder {
147
145
  webpack: this.opts.mfsu.opts.implementor,
148
146
  }));
149
147
  const exposes = opts.deps.reduce((memo, dep) => {
150
- 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);
151
149
  return memo;
152
150
  }, {});
153
151
  depConfig.plugins.push(new this.opts.mfsu.opts.implementor.container.ModuleFederationPlugin({
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,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/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,10 +13,14 @@ 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");
22
+ // @ts-ignore
23
+ const webpack_virtual_modules_1 = __importDefault(require("../compiled/webpack-virtual-modules"));
20
24
  const autoExport_1 = __importDefault(require("./babelPlugins/autoExport"));
21
25
  const awaitImport_1 = __importDefault(require("./babelPlugins/awaitImport/awaitImport"));
22
26
  const getRealPath_1 = require("./babelPlugins/awaitImport/getRealPath");
@@ -24,6 +28,8 @@ const constants_1 = require("./constants");
24
28
  const dep_1 = require("./dep/dep");
25
29
  const depBuilder_1 = require("./depBuilder/depBuilder");
26
30
  const depInfo_1 = require("./depInfo");
31
+ const autoExport_2 = __importDefault(require("./esbuildHandlers/autoExport"));
32
+ const awaitImport_2 = __importDefault(require("./esbuildHandlers/awaitImport"));
27
33
  const types_1 = require("./types");
28
34
  const makeArray_1 = require("./utils/makeArray");
29
35
  const buildDepPlugin_1 = require("./webpackPlugins/buildDepPlugin");
@@ -42,53 +48,153 @@ class MFSU {
42
48
  this.opts.cwd = this.opts.cwd || process.cwd();
43
49
  this.depInfo = new depInfo_1.DepInfo({ mfsu: this });
44
50
  this.depBuilder = new depBuilder_1.DepBuilder({ mfsu: this });
51
+ this.depInfo.loadCache();
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('${content}');`;
57
+ // return `(async () => await import('${content}'))();`;
45
58
  }
46
59
  setWebpackConfig(opts) {
47
60
  var _a;
48
- const { mfName } = this.opts;
49
- /**
50
- * config
51
- */
52
- // set alias and externals with reference for babel plugin
53
- Object.assign(this.alias, ((_a = opts.config.resolve) === null || _a === void 0 ? void 0 : _a.alias) || {});
54
- this.externals.push(...(0, makeArray_1.makeArray)(opts.config.externals || []));
55
- opts.config.plugins = opts.config.plugins || [];
56
- opts.config.plugins.push(...[
57
- new this.opts.implementor.container.ModuleFederationPlugin({
58
- name: '__',
59
- remotes: {
60
- // TODO: support runtime public path
61
- [mfName]: `${mfName}@${opts.config.output.publicPath}${constants_1.REMOTE_FILE_FULL}`,
62
- },
63
- }),
64
- new buildDepPlugin_1.BuildDepPlugin({
65
- onCompileDone: () => {
66
- this.buildDeps().catch((e) => {
67
- utils_1.logger.error(e);
68
- });
69
- },
70
- }),
71
- new writeCachePlugin_1.WriteCachePlugin({
72
- onWriteCache: () => {
73
- this.depInfo.writeCache();
74
- },
75
- }),
76
- ]);
77
- /**
78
- * depConfig
79
- */
80
- this.depConfig = opts.depConfig;
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;
182
+ });
81
183
  }
82
184
  buildDeps() {
83
185
  return __awaiter(this, void 0, void 0, function* () {
84
- if (!this.depInfo.shouldBuild())
186
+ if (!this.depInfo.shouldBuild()) {
187
+ utils_1.logger.info('MFSU skip buildDeps');
85
188
  return;
189
+ }
86
190
  this.depInfo.snapshot();
87
191
  const deps = dep_1.Dep.buildDeps({
88
192
  deps: this.depInfo.moduleGraph.depSnapshotModules,
89
193
  cwd: this.opts.cwd,
90
194
  mfsu: this,
91
195
  });
196
+ utils_1.logger.info('MFSU buildDeps');
197
+ utils_1.logger.debug(deps.map((dep) => dep.file).join(', '));
92
198
  yield this.depBuilder.build({
93
199
  deps,
94
200
  });
@@ -108,7 +214,7 @@ class MFSU {
108
214
  }
109
215
  res.setHeader('content-type', (0, mrmime_1.lookup)((0, path_1.extname)(req.path)) || 'text/plain');
110
216
  const relativePath = req.path.replace(new RegExp(`^${publicPath}`), '/');
111
- 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));
112
218
  res.send(content);
113
219
  });
114
220
  }
@@ -118,38 +224,51 @@ class MFSU {
118
224
  },
119
225
  ];
120
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
+ }
121
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();
122
266
  return [
123
- autoExport_1.default,
124
- [
125
- awaitImport_1.default,
126
- {
127
- onTransformDeps: () => { },
128
- onCollect: ({ file, data, }) => {
129
- this.depInfo.moduleGraph.onFileChange({
130
- file,
131
- deps: [
132
- ...Array.from(data.matched).map((item) => ({
133
- file: item.sourceValue,
134
- isDependency: true,
135
- })),
136
- ...Array.from(data.unMatched).map((item) => ({
137
- file: (0, getRealPath_1.getRealPath)({
138
- file,
139
- dep: item.sourceValue,
140
- }),
141
- isDependency: false,
142
- })),
143
- ],
144
- });
145
- },
146
- exportAllMembers: this.opts.exportAllMembers,
147
- unMatchLibs: this.opts.unMatchLibs,
148
- remoteName: this.opts.mfName,
149
- alias: this.alias,
150
- externals: this.externals,
151
- },
152
- ],
267
+ autoExport_2.default,
268
+ (0, awaitImport_2.default)({
269
+ cache,
270
+ opts: checkOpts,
271
+ }),
153
272
  ];
154
273
  }
155
274
  }
@@ -30,7 +30,8 @@ export declare class ModuleGraph {
30
30
  toJSON(): {
31
31
  roots: string[];
32
32
  fileModules: Record<string, {
33
- importModules: string[];
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;
@@ -65,9 +72,10 @@ class ModuleGraph {
65
72
  });
66
73
  this.fileToModules.forEach((value, key) => {
67
74
  fileModules[key] = {
68
- importModules: Array.from(value.importedModules).map((item) => item.file),
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,7 +1,14 @@
1
1
  {
2
2
  "name": "@umijs/mfsu",
3
- "version": "4.0.0-beta.6",
3
+ "version": "4.0.0-rc.1",
4
4
  "description": "@umijs/mfsu",
5
+ "homepage": "https://github.com/umijs/umi-next/tree/master/packages/mfsu#readme",
6
+ "bugs": "https://github.com/umijs/umi-next/issues",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/umijs/umi-next"
10
+ },
11
+ "license": "MIT",
5
12
  "main": "dist/index.js",
6
13
  "types": "dist/index.d.ts",
7
14
  "files": [
@@ -13,36 +20,34 @@
13
20
  "build:deps": "pnpm esno ../../scripts/bundleDeps.ts",
14
21
  "dev": "pnpm build -- --watch"
15
22
  },
16
- "repository": {
17
- "type": "git",
18
- "url": "https://github.com/umijs/umi-next"
19
- },
20
- "authors": [
21
- "chencheng <sorrycc@gmail.com> (https://github.com/sorrycc)"
22
- ],
23
- "license": "MIT",
24
- "bugs": "https://github.com/umijs/umi-next/issues",
25
- "homepage": "https://github.com/umijs/umi-next/tree/master/packages/mfsu#readme",
26
- "publishConfig": {
27
- "access": "public"
28
- },
29
23
  "dependencies": {
30
- "@umijs/bundler-esbuild": "4.0.0-beta.6",
31
- "@umijs/bundler-utils": "4.0.0-beta.6",
32
- "@umijs/utils": "4.0.0-beta.6"
24
+ "@umijs/bundler-esbuild": "4.0.0-rc.1",
25
+ "@umijs/bundler-utils": "4.0.0-rc.1",
26
+ "@umijs/utils": "4.0.0-rc.1"
33
27
  },
34
28
  "devDependencies": {
35
29
  "@types/express": "4.17.13",
36
30
  "enhanced-resolve": "5.8.3",
37
31
  "mrmime": "1.0.0",
38
- "webpack": "5.61.0"
32
+ "webpack": "5.64.4",
33
+ "webpack-virtual-modules": "0.4.3"
39
34
  },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "authors": [
39
+ "chencheng <sorrycc@gmail.com> (https://github.com/sorrycc)"
40
+ ],
40
41
  "compiledConfig": {
41
42
  "deps": [
42
- "mrmime"
43
+ "mrmime",
44
+ "webpack-virtual-modules"
43
45
  ],
44
46
  "externals": {
45
47
  "mrmime": "$$LOCAL"
46
- }
48
+ },
49
+ "excludeDtsDeps": [
50
+ "webpack-virtual-modules"
51
+ ]
47
52
  }
48
53
  }