vue-cli4 打包优化之 DllPlugin 和 DLLReferencePlugin

2020-05-02 更新
近期发现 dll 已经落后了,随着 webpack 4 的优化,dll 带来的提升已经不太明显。所以据说 vue-cli 和 create-react-app 曾经采用过的 dll 优化,现在也已经不再使用。现在有一个更好的方式,就是在开发模式下采用 hard-source-webpack-plugin。不用额外的 dll 配置,不用生成多余文件,也不用考虑注入问题。开发模式下二次构建的速度会有所提升,production 模式则根据实际业务和文件大小来调整配置了。

const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
const IS_DEV = process.env.NODE_ENV === 'development'
module.exports = {
	configureWebpack() {
		const devPlugins = [
			/**
			 * 缓存加速二次构建速度
			 */
			new HardSourceWebpackPlugin(),
			new HardSourceWebpackPlugin.ExcludeModulePlugin([
			  {
			    test: /mini-css-extract-plugin[\\/]dist[\\/]loader/
			  }
			])
		]
		if(IS_DEV) {
			return {
				plugins: devPlugins
			}
		}
	}
}

DLLPlugin 和 DLLReferencePlugin 用某种方法实现了拆分 bundles,同时还大大提升了构建的速度。一般用来将常用的库,例如 vue,vuex 抽离出来,后续构建过程跳过这些库。既能加快打包速度,又能充分利用缓存。

首先安装如下三个包,缺一不可。

yarn add webpack-cli add-asset-html-webpack-plugin clean-webpack-plugin -D

项目根目录创建 webpack.dll.config.js,写入如下代码:

const path = require('path')
const webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

// dll文件存放的目录
const dllPath = 'public/vendor'

module.exports = {
  entry: {
    // 需要提取的库文件
    vendor: ['vue', 'vue-router', 'vuex', 'axios']
  },
  output: {
    path: path.join(__dirname, dllPath),
    filename: '[name].dll.js',
    // vendor.dll.js中暴露出的全局变量名
    // 保持与 webpack.DllPlugin 中名称一致
    library: '[name]_[hash]'
  },
  plugins: [
    // 清除之前的dll文件
    new CleanWebpackPlugin(),
    // 设置环境变量
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('production')
      }
    }),
    // manifest.json 描述动态链接库包含了哪些内容
    new webpack.DllPlugin({
      path: path.join(__dirname, dllPath, '[name]-manifest.json'),
      // 保持与 output.library 中名称一致
      name: '[name]_[hash]',
      context: process.cwd()
    })
  ]
}

package.json 里的 scripts 添加如下代码:

"dll": "webpack -p --progress --config ./webpack.dll.config.js",

运行 npm run dll 可以看到在 public 目录下生成了一个 vendor 目录,里面有两个文件:
vendor.dll.js 动态链接库文件包含了大量模块的代码,通过 vendor_f1555695fd34524aee6f 变量把自己暴露在了全局中,也就是可以通过 window.vendor_f1555695fd34524aee6f 可以访问到它里面包含的模块

var vendor_f1555695fd34524aee6f=...

vendor-manifest.json 清楚地描述了与其对应的 dll.js 文件中包含了哪些模块,以及每个模块的路径和 ID

{"name":"vendor_f1555695fd34524aee6f","content": {...}}

这里生成了 vendor.dll.js,可以直接手动在 index.html 引入,但是也可以通过 webpack 插件自动注入 index.html。代码如下:
vue.config.js

const webpack = require('webpack')
const CompressionPlugin = require('compression-webpack-plugin')
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')
const path = require('path')
const resolve = url => path.resolve(__dirname, url)
const IS_PROD = process.env.NODE_ENV === 'production'
module.exports = {
  configureWebpack(config) {
    const plugins = [
      ...
    ]
    if (IS_PROD) {
      // 有几个 dll.js,这里就响应 new 几个 webpack.DllReferencePlugin
      plugins = plugins.concat([
        new webpack.DllReferencePlugin({
          context: process.cwd(),
          manifest: require('./public/vendor/vendor-manifest.json')
        }),
        // 将 dll 注入到 生成的 html 模板中
        new AddAssetHtmlPlugin({
          // dll文件位置
          filepath: resolve('./public/vendor/*.js'),
          // dll 引用路径
          publicPath: './vendor',
          // dll最终输出的目录
          outputPath: './vendor'
        })
      ])
    }
    return {
      plugins
    }
  },
}

总结:

  1. 安装相关包
  2. 配置 webpack.dll.config.js 使用 dllplugin 打出 dll.js
  3. 配置 vue.config.js 用 DllReferencePlugin 通过引用 dll 的 manifest 文件来把依赖的名称映射到模块的 id 上
  4. AddAssetHtmlPlugin 将 dll.js 文件自动注入 index.html 中

你可能感兴趣的:(前端)