mpvue微信小程序分包中的公共库打包方案
优化效果
优化前
优化后
1. 发现问题
可以看到优化前每个页面都有400kb, 都依赖了echarts.min.js这个库, 之所以没有打包进vendor.js是因为已经优化过了. 下面的count > 10这里只有4个页面用了,所以没打进去.
new webpack.optimize.CommonsChunkPlugin({
name: 'common/vendor',
minChunks: function (module, count) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf('node_modules') >= 0
) || count > 10
}
}),
但是随着用到echarts组件的页面越来越多,pagesCharts这个分包会越来越大,最后超过2M上限.
2. 查找问题
之前也发现过这个问题,一开始以为是mpvue不支持打包分包里的公共库,后来知道可以使用CommonsChunkPlugin插件把公共库再拆分.然后有了下面的webpack配置
new webpack.optimize.CommonsChunkPlugin({
name: 'common/vendor',
minChunks: function (module, count) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf('node_modules') >= 0
) || count > 3 // 这里不是10,因为要把echarts.min.js打进来给pagesCharts/pagesCharts提取公共包
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'pagesCharts/pagesCharts',
chunks: ['common/vendor'], // 从这些分包中提取公共库
minChunks: function (module, count) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf('echarts') >= 0
)
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'common/manifest',
chunks: Infinity,
}),
3. 还是有问题
通过上面的配置打包后,mpvue打出来的发布文件中每个page.js中都引入了3个包
require("../../common/manifest.js")
require("../pagesCharts.js")
require("../../common/vendor.js")
打开微信小程序调试会报主包文件不能引入分包文件大致这样的错. 现在只要把生成这段引入代码的代码找出来修改一下应该就可以了,但是找这段代码我找了好久,直到今天早上才找到.
4. 修改 MpvuePlugin 代码
代码在这个插件中
const MpvuePlugin = require('webpack-mpvue-asset-plugin')
修改else if (!(/^\.map$/.test(extname)))
这个判断下的代码如下
const path = require('path')
const upath = require('upath')
const relative = require('relative')
const getRelativePath = (filePath) => {
if (!/^\.(\.)?\//.test(filePath)) {
filePath = `./${filePath}`
}
return filePath
}
const emitHandle = (compilation, callback) => {
Object.keys(compilation.entrypoints).forEach(key => {
const { chunks } = compilation.entrypoints[key]
const entryChunk = chunks.pop()
entryChunk.files.forEach(filePath => {
const assetFile = compilation.assets[filePath]
const extname = path.extname(filePath)
let content = assetFile.source()
chunks.reverse().forEach(chunk => {
chunk.files.forEach(subFile => {
if (path.extname(subFile) === extname && assetFile) {
let relativePath = upath.normalize(relative(filePath, subFile))
// 百度小程序 js 引用不支持绝对路径,改为相对路径
if (extname === '.js') {
relativePath = getRelativePath(relativePath)
}
if (/^(\.wxss)|(\.ttss)|(\.acss)|(\.css)$/.test(extname)) {
relativePath = getRelativePath(relativePath)
content = `@import "${relativePath}";\n${content}`
} else if (!(/^\.map$/.test(extname))) {
// 其他包不引入图表分包的公共库
if (filePath.includes('pagesCharts')) {
content = `require("${relativePath}")\n${content}`
} else {
if (relativePath.includes('pagesCharts.js')) {
} else {
content = `require("${relativePath}")\n${content}`
}
}
}
}
})
assetFile.source = () => content
})
})
})
callback()
}
function MpvuePlugin() {}
MpvuePlugin.prototype.apply = compiler => compiler.plugin('emit', emitHandle)
module.exports = MpvuePlugin