mirror of
http://36.133.248.69:3088/admin/RentWeAppFront.git
synced 2026-03-08 09:52:26 +08:00
259 lines
10 KiB
JavaScript
259 lines
10 KiB
JavaScript
const GraphHelpers = require('webpack/lib/GraphHelpers');
|
||
const { normalizePath } = require('@dcloudio/uni-cli-shared');
|
||
const getSplitChunks = require('@dcloudio/vue-cli-plugin-uni/lib/split-chunks');
|
||
const path = require('path');
|
||
|
||
const mainPath = normalizePath(path.resolve(process.env.UNI_INPUT_DIR, 'main.'));
|
||
const mainPkgName = 'mainPkg';
|
||
|
||
function getAllEntryPointOfChunkGroup (chunkGroup, entryPointSet) {
|
||
if (chunkGroup.isInitial()) {
|
||
return entryPointSet.add(chunkGroup);
|
||
}
|
||
|
||
const parentChunkGroups = [...chunkGroup.parentsIterable];
|
||
parentChunkGroups.forEach(parentChunkGroup => getAllEntryPointOfChunkGroup(parentChunkGroup, entryPointSet));
|
||
}
|
||
|
||
function getChunkToEntryPointsMap (allChunks) {
|
||
const chunkToEntryPointsMap = new Map();
|
||
allChunks.forEach(chunkItem => {
|
||
const chunkGroups = [...chunkItem.groupsIterable];
|
||
const tmpEntryPointSet = new Set();
|
||
chunkToEntryPointsMap.set(chunkItem, tmpEntryPointSet);
|
||
chunkGroups.forEach(chunkGroup => {
|
||
getAllEntryPointOfChunkGroup(chunkGroup, tmpEntryPointSet);
|
||
});
|
||
});
|
||
return chunkToEntryPointsMap;
|
||
}
|
||
|
||
function baseTest (module) {
|
||
if (module.type === 'css/mini-extract') {
|
||
return false;
|
||
}
|
||
if (module.resource) {
|
||
const resource = normalizePath(module.resource);
|
||
if (
|
||
resource.indexOf('.vue') !== -1 ||
|
||
resource.indexOf('.nvue') !== -1 ||
|
||
resource.indexOf(mainPath) === 0 // main.js
|
||
) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
class SplitHandler {
|
||
constructor (chunks = [], compilation, cacheGroups, chunkFilter, removeModuleFromChunkFilter = () => true) {
|
||
this.chunks = chunks || [];
|
||
this.chunkFilter = chunkFilter;
|
||
this.cacheGroups = cacheGroups;
|
||
this.compilation = compilation;
|
||
this.removeModuleFromChunkFilter = removeModuleFromChunkFilter;
|
||
|
||
this.chunksInfoMap = new Map();
|
||
}
|
||
|
||
addModuleToChunksInfoMap (module, chunks, newChunkName) {
|
||
let info = this.chunksInfoMap.get(newChunkName);
|
||
if (!info) {
|
||
info = {
|
||
modules: new Set(),
|
||
chunks: new Set(),
|
||
};
|
||
this.chunksInfoMap.set(newChunkName, info);
|
||
}
|
||
info.modules.add(module);
|
||
chunks.forEach(chunk => info.chunks.add(chunk));
|
||
}
|
||
|
||
checkTest (module, test) {
|
||
if (typeof test === 'function') {
|
||
if (test(module, module.getChunks())) {
|
||
return true;
|
||
}
|
||
} else if (test instanceof RegExp) {
|
||
if (module.nameForCondition && test.test(module.nameForCondition())) {
|
||
return true;
|
||
}
|
||
for (const chunk of module.getChunks()) {
|
||
if (chunk.name && test.test(chunk.name)) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
getHitCacheGroups (module) {
|
||
const hitCacheGroups = [];
|
||
const cacheGroups = this.cacheGroups;
|
||
for (const key of Object.keys(cacheGroups)) {
|
||
const cacheInfo = cacheGroups[key];
|
||
if (!cacheInfo) {
|
||
continue;
|
||
}
|
||
if (this.checkTest(module, cacheInfo.test)) {
|
||
hitCacheGroups.push({ newChunkName: cacheInfo.name, priority: cacheInfo.priority || 0 });
|
||
}
|
||
}
|
||
if (hitCacheGroups.length) {
|
||
return hitCacheGroups.sort((b, a) => a.priority - b.priority)[0];
|
||
}
|
||
return null;
|
||
}
|
||
|
||
start () {
|
||
const allModulesSet = new Set();
|
||
this.chunks.forEach(chunk => {
|
||
chunk.getModules().forEach(module => allModulesSet.add(module));
|
||
});
|
||
this.splitHandler([...allModulesSet]);
|
||
}
|
||
|
||
filter (module) {
|
||
// 获取chunks和this.chunks的交集部分
|
||
const filterOne = this.chunks.filter(targetChunk => module.chunksIterable.has(targetChunk)) || [];
|
||
// 处理uniapp提供的过滤,见split-chunks文件
|
||
return filterOne.filter(this.chunkFilter);
|
||
}
|
||
|
||
splitHandler (allModulesUsedByIndependent) {
|
||
// 遍历独立分包中用到的模块,测试其所在的cacheGroup
|
||
// 每个模块在这里至多会生成或加入到一个newChunk中
|
||
for (const module of allModulesUsedByIndependent) {
|
||
const hitGroup = this.getHitCacheGroups(module);
|
||
if (!hitGroup) {
|
||
continue;
|
||
}
|
||
this.addModuleToChunksInfoMap(module, this.filter(module), hitGroup.newChunkName);
|
||
}
|
||
|
||
// 遍历 chunksInfoMap
|
||
for (const [chunkName, newChunkInfo] of this.chunksInfoMap) {
|
||
const newChunk = this.compilation.addChunk(chunkName);
|
||
newChunk.chunkReason = 'split chunk for independent';
|
||
for (const module of newChunkInfo.modules) {
|
||
GraphHelpers.connectChunkAndModule(newChunk, module);
|
||
[...newChunkInfo.chunks].forEach(chunk => {
|
||
if (this.removeModuleFromChunkFilter(chunk)) {
|
||
chunk.removeModule(module);
|
||
chunk.split(newChunk);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
class SplitIndependentChunksPlugin {
|
||
generateCacheGroups () {
|
||
const cacheGroups = {};
|
||
Object.keys(process.UNI_SUBPACKAGES).forEach(root => {
|
||
const pkgInfo = process.UNI_SUBPACKAGES[root];
|
||
if (pkgInfo.independent) {
|
||
cacheGroups[root] = {
|
||
[root + '/commonsVendor']: {
|
||
test: /[\\/]node_modules[\\/]/,
|
||
minSize: 0,
|
||
minChunks: 1,
|
||
name: normalizePath(path.join(root, 'common/library')),
|
||
priority: 2,
|
||
chunks: 'all',
|
||
},
|
||
[root + '/commons']: {
|
||
priority: 1,
|
||
name: normalizePath(path.join(root, 'common/vendor')),
|
||
test: (module) => {
|
||
if (!baseTest(module)) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
},
|
||
};
|
||
}
|
||
});
|
||
|
||
const splitChunkConfig = getSplitChunks();
|
||
cacheGroups[mainPkgName] = splitChunkConfig.cacheGroups;
|
||
return { cacheGroups, chunkFilter: splitChunkConfig.chunks };
|
||
}
|
||
|
||
apply (compiler) {
|
||
compiler.hooks.thisCompilation.tap('SplitIndependentChunksPlugin', compilation => {
|
||
compilation.hooks.optimizeChunksAdvanced.tap('SplitIndependentChunksPlugin', chunks => {
|
||
try {
|
||
const independentPkgRoot = Object.values(process.UNI_SUBPACKAGES).filter(rootInfo => rootInfo.independent).map(rootInfo => rootInfo.root);
|
||
const allPkgRootMap = {};
|
||
const mainPkgChunks = [];
|
||
for (const chunk of chunks) {
|
||
const chunkName = chunk.name;
|
||
if (!chunkName) {
|
||
continue;
|
||
}
|
||
const root = independentPkgRoot.find(root => chunkName.startsWith(root));
|
||
if (!root) {
|
||
mainPkgChunks.push(chunk);
|
||
continue;
|
||
}
|
||
if (!allPkgRootMap[root]) {
|
||
allPkgRootMap[root] = [];
|
||
}
|
||
allPkgRootMap[root].push(chunk);
|
||
}
|
||
|
||
const { cacheGroups, chunkFilter } = this.generateCacheGroups(compiler);
|
||
// 找出chunk所有的entryPoint
|
||
const chunkToEntryPointsMap = getChunkToEntryPointsMap(compilation.chunks);
|
||
const allChunksUsedByIndependentMap = {};
|
||
for (const pkgRoot in allPkgRootMap) {
|
||
if (!allChunksUsedByIndependentMap[pkgRoot]) {
|
||
allChunksUsedByIndependentMap[pkgRoot] = new Set();
|
||
}
|
||
|
||
for (const [chunkItem, entryPointSet] of chunkToEntryPointsMap) {
|
||
const filter = entryPoint => entryPoint.name.startsWith(pkgRoot);
|
||
const referenceByPkgRoot = [...entryPointSet].find(filter);
|
||
// 当前chunk中存在模块被该独立分包下面的页面引用
|
||
// uniapp的entry: main.js + page.vue
|
||
if (referenceByPkgRoot) {
|
||
allChunksUsedByIndependentMap[pkgRoot].add(chunkItem);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 先分离独立分包
|
||
for (const pkgRoot in allPkgRootMap) {
|
||
const chunksOfIndependentPkg = allPkgRootMap[pkgRoot];
|
||
// 需要将独立分包中用到外部js模块拆分一份到 pkgRoot/vendor.js 中
|
||
const allChunksUsedByIndependent = [...allChunksUsedByIndependentMap[pkgRoot]];
|
||
// 收集独立分包下面的所有chunks:包内chunks + 包外chunks(主要引用的包外组件)
|
||
const outSideChunks = [];
|
||
allChunksUsedByIndependent.forEach(chunkItem => {
|
||
if (!chunksOfIndependentPkg.includes(chunkItem)) {
|
||
outSideChunks.push(chunkItem);
|
||
}
|
||
});
|
||
|
||
new SplitHandler([...allChunksUsedByIndependent], compilation, cacheGroups[pkgRoot], chunkFilter, (chunk) => {
|
||
if (outSideChunks.includes(chunk)) {
|
||
return false;
|
||
}
|
||
return true;
|
||
}).start();
|
||
}
|
||
// 再分离普通分包和主包
|
||
new SplitHandler(mainPkgChunks, compilation, cacheGroups[mainPkgName], chunkFilter).start();
|
||
} catch (e) {
|
||
console.error('independent.error', 'SplitIndependentChunksPlugin', e);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
module.exports = SplitIndependentChunksPlugin;
|