mpvue微信小程序分包中的公共库打包方案

1,255 阅读1分钟

mpvue微信小程序分包中的公共库打包方案

优化效果

优化前 0.png

优化后

企业微信截图_16209638234958.png

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

5. 再编译(完美解决)