微前端架构中为何构建时频繁生成重复的moduleId?
摘要:在我们的 vue-mfe 微前端项目中,出现了重复的 moduleId。第一次我们的解决办法是使用增大 hash-module-ids 的 hashDigestLength 到 8 位,vue-cli3 默认是 4 位,Webpack 默认
在我们的 vue-mfe 微前端项目中,出现了重复的 moduleId。第一次我们的解决办法是使用增大 hash-module-ids 的 hashDigestLength 到 8 位,vue-cli3 默认是 4 位,Webpack 默认也是 4 位。但是随着 SubApp 资源的增多,还是出现了重复。于是不得不排查了下生成重复的 moduleId 的原因:
案例
在construction SubApp 的 portal.entry.js 中使用了 import commonService from './service/commonService',而在material SubApp portal.entry.js 中也存在相同路径的引用import commonService from './service/commonService'。
然后在 construction 和material 两个 SubApp 之间就出现了冲突,比如说先加载construction,那么material加载的commonService就是先前被加载的moduleCache[modueId]。
Q1: 为什么会出现相同的 modueId 在不同的 webpack 构建上下文中?
因为 webpack hashModuleId 的构建方式是基于当前相对路径生成 moduleId,分别看下文档和代码:
文档:
This plugin will cause hashes to be based on the relative path of the module, generating a four character string as the module id. Suggested for use in production.
代码:
apply(compiler) {
const options = this.options;
compiler.hooks.compilation.tap("HashedModuleIdsPlugin", compilation => {
const usedIds = new Set();
compilation.hooks.beforeModuleIds.tap(
"HashedModuleIdsPlugin",
modules => {
for (const module of modules) {
if (module.id === null && module.libIdent) {
// 这就是相对路径位置,调用 module.libIdent 方法
const id = module.libIdent({
context: this.options.context || compiler.options.context
});
const hash = createHash(options.hashFunction);
hash.update(id);
const hashId = /** @type {string} */ (hash.digest(
options.hashDigest
));
let len = options.hashDigestLength;
while (usedIds.has(hashId.substr(0, len))) len++;
module.id = hashId.substr(0, len);
usedIds.add(module.id);
}
}
}
);
});
}
而调用 module.libIdent 方法返回是这样的字符串:
有 loader 的会加上 loader 路径: css:./node_modules/css-loader/index.js?!./node_modules/postcss-loader/src/index.js?!./src/components/virtual-table/table.css",
js: ./node_modules/css-loader/lib/css-base.js
而在我们的 SubApp 项目中因为两个路径一致,则生成的 hashId 就成了一样一样的了。
