利用DllPlugin性能优化

介绍

在用 Webpack 打包的时候,对于一些不经常更新的第三方库,比如 react,lodash,vue 我们希望能和自己的代码分离开,Webpack 社区有两种方案
CommonsChunkPlugin
DLLPlugin
对于 CommonsChunkPlugin,webpack 每次打包实际还是需要去处理这些第三方库,只是打包完之后,能把第三方库和我们自己的代码分开。而 DLLPlugin 则是能把第三方代码完全分离开,即每次只打包项目自身的代码。Dll这个概念是借鉴了Windows系统的dll,一个dll包,就是一个纯纯的依赖库,它本身不能运行,是用来给你的app引用的

使用

添加配置文件

要使用 DLLPlugin,需要额外新建一个配置文件webpack.dll.js,该配置文件用来打包生成第三方库。
webpack.dll.js

const webpack = require('webpack')
const path = require('path')
module.exports = {
  mode: 'production',
  entry: {
    vendor: ['lodash'],
    react: ['react']
  },
  output: {
    filename: '[name].dll.js',
    path: path.resolve(__dirname, './dll'),
    library: '[name]',
    // libraryTarget: 'umd' // 将入口文件的返回值以什么类型的方式导出,umd比较全,包括amd、cmd、window
  },
  plugins: [
    new webpack.DllPlugin({
      name: '[name]',
      path: path.join(__dirname, './dll/[name].manifest.json')
    })
  ]
}

然后运行 命令行运行"webpack --config webpack-dll.js"
生成打包后的文件
利用DllPlugin性能优化
接下来就是,这么在业务代码里使用打包好的第三方模块的事情了。

修改配置文件webpack-common.js

关键代码如下:

const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
....
  plugins: [
    new AddAssetHtmlWebpackPlugin({//将打包好的dll文件挂载到html中
      filepath: path.resolve(__dirname, './dll/react.dll.js')
    }),
    new AddAssetHtmlWebpackPlugin({
      filepath: path.resolve(__dirname, './dll/vendor.dll.js')
    }),
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, './dll/vendor-manifest.json')
    }),
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, './dll/react-manifest.json')
    })
  ],

浏览器控制台,可以看到第三方模块,已经作为全局变量,引入到了入口文件中。
利用DllPlugin性能优化
但是每次在webpack.dll.js新加第三方模块,都要在webpack-common.js里添加DllReferencePlugin等,比较麻烦,我们可以用node写一个文件循环,自己读取文件数量,自动修改plugin
关键代码如下:

const fs = require('fs')
const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
const plugins = [
  new HtmlWebpackPlugin({
    template: './src/index.html'
  }),
  new CleanWebpackPlugin(),
  new BundleAnalyzerPlugin(),
  new webpack.ProvidePlugin({
    _: 'lodash'
  }),
]
files.forEach(file => {
  if (/.*\.dll.js/.test(file)) {
    plugins.push(new AddAssetHtmlWebpackPlugin({//将打包好的dll文件挂载到html中
      filepath: path.resolve(__dirname, '../dll', file)
    }))
  }
  if (/.*\.manifest.json/.test(file)) {
    plugins.push(new webpack.DllReferencePlugin({//分析第三方模块是否已经在dll文件里,如果里面有就不用再node_modules在分析打包了
      manifest: path.resolve(__dirname, '../dll', file)
    }))
  }
})

总结整体流程

通过dllPlugin生成manifets.json和vendor.js,vendor.js会自执行返回一个加载函数vendor(名字可配置),通过闭包将模块存储在内存中,注意vendor是一个全局变量。
webpack通过DllReferencePlugin在打包的时候分析业务代码中使用了哪些第三方模块,哪些模块是不需要打包进业务代码中,而是去vendor.js中获取。
vendor中获取的模块是通过调用全局函数vendor(id)来进行引入。

补充

CommonsChunkPlugin 插件每次打包的时候还是会去处理一些第三方依赖库,只是它能把第三方库文件和我们的代码分开掉,生成一个独立的js文件。但是它还是不能提高打包的速度。

DLLPlugin 它能把第三方库代码分离开,并且每次文件更改的时候,它只会打包该项目自身的代码。所以打包速度会更快。

DLLPlugin 这个插件是在一个额外独立的webpack设置中创建一个只有dll的bundle,也就是说我们在项目根目录下除了有webpack.config.js,还会新建一个webpack.dll.config.js文件。webpack.dll.config.js作用是把所有的第三方库依赖打包到一个bundle的dll文件里面,还会生成一个名为 manifest.json文件。
该manifest.json的作用是用来让 DllReferencePlugin 映射到相关的依赖上去的。

DllReferencePlugin 这个插件是在webpack.config.js中使用的,该插件的作用是把刚刚在webpack.dll.config.js中打包生成的dll文件引用到需要的预编译的依赖上来。什么意思呢?就是说在webpack.dll.config.js中打包后比如会生成 vendor.dll.js文件和vendor-manifest.json文件,vendor.dll.js文件包含所有的第三方库文件,vendor-manifest.json文件会包含所有库代码的一个索引,当在使用webpack.config.js文件打包DllReferencePlugin插件的时候,会使用该DllReferencePlugin插件读取vendor-manifest.json文件,看看是否有该第三方库。vendor-manifest.json文件就是有一个第三方库的一个映射而已。

所以说 第一次使用 webpack.dll.config.js 文件会对第三方库打包,打包完成后就不会再打包它了,然后每次运行 webpack.config.js文件的时候,都会打包项目中本身的文件代码,当需要使用第三方依赖的时候,会使用 DllReferencePlugin插件去读取第三方依赖库。所以说它的打包速度会得到一个很大的提升。

上一篇:webpack4配置优化


下一篇:Qt Installer Framework翻译(7-2)