项目打包优化之DllPlugin

dll-plugin

DllPlugin 插件配置实践node

做用

DLLPlugin 和 DLLReferencePlugin 用某种方法实现了拆分 bundles,同时还大大提高了构建的速度。jquery

  • DllPlugin: 将第三方依赖与项目分离,将全部第三方库代码单独打成dll文件,项目每次打包只须要打包本项目代码。
  • DllReferencePlugin: 找到项目中所用到的第三方依赖在dll中的位置。

用法

工程目录webpack

### 目录结构以下:
  dll-plugin                                       # 工程名
  |   |--- dist                               # 打包后生成的目录文件             
  |   |--- node_modules                       # 全部的依赖包
  |   |--- src                                # 存放全部js文件
  |   | |-- pageOne.js  
  |   | |-- pageTwo.js                        # js入口文件
  |   |--- webpack.config.js                  # webpack配置文件
  |   |--- webpack.dll.config.js              # 打包第三方依赖的库文件
  |   |--- README.md
  |   |--- package.json
复制代码

首先咱们须要在项目下建立一个单独的打包dll文件的配置文件webpack.dll.config.jsweb

const path = require('path');
const webpack = require('webpack');
const library = '[name]_dll_lib';

module.exports = {
	mode: 'development',
  // 入口, 接收多个参数做为多个入口
  entry: {
    // dll文件中包含的第三方库列表
    jquery: ['jquery'],
    echarts: ['echarts']
  },
  output: {
    // 文件名称
    filename: 'dll/[name].dll.js',
    // 文件输出目录
    path: path.resolve(__dirname, 'dist'),
    // 存放dll文件的全局变量名称,须要注意命名冲突
    library: library
  },
  plugins: [
    new webpack.DllPlugin({
      // manifest文件中的name属性值, 需与output.library保持一致
      name: library,
      // mainfest文件输出路径和文件名称
      path: path.join(__dirname, 'dist', 'dll/[name].manifest.json')
    })
  ]
}
复制代码

接下来须要在webpack.config中使用的manifestnpm

module.exports = {

  /***** other options ******/

  plugins: [
    // 告诉webpack使用了哪些第三方库代码
    new DllReferencePlugin({
      // manifest文件中请求的上下文,
      context: __dirname,
      // jquery 映射到json文件上去
      manifest: require('./dist/jquery.manifest.json')
    }),
    new DllReferencePlugin({
      // echarts 映射到json文件上去
      manifest: require('./dist/echarts.manifest.json')
    })
  ]
}
复制代码

package.json 中添加打包命令json

"scripts": {
  "build:dll": "webpack --config webpack.dll.config.js",
},
复制代码

运行npm run build:dll, 运行完成以后,会在dist/dll目录下生成 echarts.dll.js, echarts.manifest.json,jquery.dll.js, jquery.manifest.json 文件echarts

dll文件

在src/pageOne.js入口文件中引入jquery和echarts库, src/pageTwo.js文件中不引入任何依赖ide

const jquery = require('jquery');
const echarts = require('echarts');

console.log("Hello World from pageOne main file!");
复制代码

执行打包命令 npm run build 函数

使用dll打包时间
使用dll打包文件大小

发现打包的时间是668ms, pageOne和pageTwo打包出来的大小仅相差了3kb, 显然第三方库代码没有打包到项目文件里。再来对比一下使用dll和不使用dll的状况优化

不使用dll打包时间
不适用dll打包文件大小

打包时间变成了1781ms, 增长了近两倍, 打包大小变为3683KB, 将jquery和echarts第三方库代码打包进了pageOne中。

结论

使用DllPlugin分离bundle,构建速度和工程文件大小优化明显。

原理

了解dll-plugin的做用和用法后,再来看看它是怎么实现的。

先看一下打包生成的dll文件, echarts.dll.js:

var echarts_dll_lib = (function(modules) {
  // ... 此处省略 webpackBootstrap 函数代码
}({
  "./node_modules/echarts/index.js": (function(module, exports, __webpack_require__) {
    // ID为./node_modules/echarts/index.js模块对应的代码
  }),
  "./node_modules/echarts/lib/CoordinateSystem.js": (function(module, exports, __webpack_require__) {
    // ID为./node_modules/echarts/lib/CoordinateSystem.js模块对应的代码
  }),
  // ......
}));
复制代码

DllPlugin 将echarts依赖导出成了一个函数,并将echarts_dll_lib挂载到window全局对象中, 能够看到dll为echarts中的各个模块都分配了一个Id。

再看echarts.manifest.json:

{
  "name":"echarts_dll_lib",
  "content": {
    "./node_modules/echarts/lib/util/animation.js": {
      "id": "./node_modules/echarts/lib/util/animation.js",
      "buildMeta":{"providedExports":true}
    },
    // .....
    "./node_modules/echarts/index.js": {
      "id":"./node_modules/echarts/index.js",
      "buildMeta": {"providedExports":true}
    },
    // ......
  }
}
复制代码

echarts.manifest.json 文件能够清楚的看到与其对应的dll.js文件中包含了哪些模块,以及每一个模块的路径和ID。

经过manifest寻找到依赖

在webpackConfig中配置DllReferencePlugin引入manifest, 当项目中引入echarts模块时,会经过路径匹配到manifest中的对应模块id, 再经过模块id和name属性, 找到挂载再window上的对应的模块代码。

相关文章
相关标签/搜索