Webpack的DllPlugin和DLLReferencePlugin应用

简介: 介绍使用 DllPlugin和DLLReferencePlugin 的应用

一:作用
Webpack官网中对这两个插件的介绍:DLLPlugin 和 DLLReferencePlugin 能实现了拆分 bundles,同时还大大提升了构建的速度。实际上就是可以事先将常用的基础模块(如React、react-dom)等抽离出来,打包到一个个单独的动态链接库(dll)中去,后面再打包业务代码时若遇到需要导入的模块存在于前面打包好的某个动态链接库中时,就跳过相关的依赖的打包,直接使用动态链接库中的代码,以此来缩短webpack构建时间,提升构建速度。

二:项目背景
当前所在项目是一个集成了很多事项服务的一户通App,其中包含门户主系统以及根据不同的事项拆分出的多个系统,一个事项对应一个前端工程。为提高加载速度,增强用户体验,考虑将H5构建产物打进离线包,但因事项数量会不断增加,将所有事项打入离线包会导致离线包大小不断膨胀。虽然将事项全部代码打入离线包不可行,但各个事项工程有公共的依赖,如React、antd-mobile、项目组内封装的公共的组件库、jsApi、以及ahooks、query-string等,可以考虑将公共依赖从bundles中拆分出来,只将公共依赖加入离线包,能最高性价比地控制离线包大小,并能减少加载事项服务时的网络延迟,提高加载速度。

三:使用介绍
Webpack 内置了对动态链接库的支持,需要通过 2 个内置插件访问。DllPlugin:在一个额外的webpack配置中设置,用于将指定模块抽离,打包出动态链接库文件;DLLReferencePlugin:用于在webpack主配置文件中配置如何引入已经打包好的动态链接库文件。

下面以基本的 Demo 为例,介绍 DllPlugin和DLLReferencePlugin的使用。
第一步:构建出动态链接库文件
假设项目中需要将react、react-dom、antd、ahooks拆分出来,打包成动态链接库文件。我们首先需要新建一个webpack配置文件,因为动态链接库相关产物需要由一份独立的构建输出。
1.1 在根目录下新建Webpack配置文件vendors.webpack.config.js,配置主要内容如下:

const webpack = require('webpack');
const path = require('path');

module.exports = {
mode: 'production',
entry: {
  // 把 React 相关模块的放到一个单独的动态链接库
  react: ['react', 'react-dom'],
  antd: ['antd'],
  vendors: ['ahooks'],
},
output: {
  // 输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称,
  // 也就是 entry 中配置的 react 、 antd 和 vendors
  path: path.join(__dirname, 'dist'),
  filename: `[name].dll.js`,
  // 存放动态链接库的全局变量名称
  library: '[name]_dll',
},
plugins: [
  new webpack.DllPlugin({
    path: path.join(__dirname, `dist/[name].manifest.json`),
    name: '[name]_dll',
  }),
],
};

1.2 执行构建命令

npx webpack --config vendors.webpack.config.js

1.3 构建产物

├── dist
  ├── antd.dll.js
  ├── antd.manifest.json
  ├── react.dll.js
  ├── react.manifest.json
  ├── vendors.dll.js
  └── vendors.manifest.json

其中包含三个动态链接库文件,分别是antd.dll.js、react.dll.js、vendors.dll.js,以 react.dll.js 文件为例,其文件内容大致如下:

var react_dll = (function(e) {
// ... 
}({
0: function(e, t, n) {
  // 模块 ID 为 0 的模块对应的代码
},
141: function(e, t, n) {
  // 模块 ID 为 141 的模块对应的代码
},
// ... 此处省略剩下的模块对应的代码 
}));

产物中react_dll.js中包含了模块的代码,模块存放在一个对象中,用对象的key作为 ID。 并且还通过 
react_dll 变量把自己暴露在了全局中,也就是可以通过 window.react_dll(ID) 可以访问到它里面包含的模块。
再看另一种产物 *.manifest.json, 以react.manifest.json为例子:

{
"name": "react_dll",
"content": {
  "./node_modules/react/index.js": { "id": 0, "buildMeta": { "providedExports": true } },
  "./node_modules/react-dom/index.js": { "id": 43, "buildMeta": { "providedExports": true } },
  "./node_modules/object-assign/index.js": {
    "id": 141,
    "buildMeta": { "providedExports": true }
  },
  "./node_modules/react/cjs/react.production.min.js": {
    "id": 201,
    "buildMeta": { "providedExports": true }
  },
  "./node_modules/react-dom/cjs/react-dom.production.min.js": {
    "id": 369,
    "buildMeta": { "providedExports": true }
  },
  "./node_modules/scheduler/index.js": { "id": 370, "buildMeta": { "providedExports": true } },
  "./node_modules/scheduler/cjs/scheduler.production.min.js": {
    "id": 371,
    "buildMeta": { "providedExports": true }
  }
}
}

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

第二步:在主webpack文件中使用动态链接库文件
2.1 在根目录下Webpack主配置文件webpack.config.js,配置主要内容如下:

const path = require('path');
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');

module.exports = {
entry: {
  main: './main.js'
},
output: {
  filename: '[name].js',
  path: path.resolve(__dirname, 'dist'),
},
plugins: [
  // 告诉 Webpack 使用了哪些动态链接库
  new DllReferencePlugin({
    manifest: require('./dist/antd.manifest.json'),
  }),
  new DllReferencePlugin({
    manifest: require('./dist/react.manifest.json'),
  }),
  new DllReferencePlugin({
    manifest: require('./dist/vendors.manifest.json'),
  }),
],
};

2.2 结合umi使用的场景及构建产物(即在umi中实现2.1的webpack配置)

import { defineConfig } from 'umi';

export default defineConfig({
// ... umi其他配置
chainWebpack(config, { webpack }) {
  config.plugin('DllReferencePlugin-0').use(
    new webpack.DllReferencePlugin({
      manifest: require(`./dist/antd.manifest.json`),
    }),
  );
  config.plugin('DllReferencePlugin-1').use(
    new webpack.DllReferencePlugin({
      manifest: require(`./dist/react.manifest.json`),
    }),
  );
  config.plugin('DllReferencePlugin-2').use(
    new webpack.DllReferencePlugin({
      manifest: require(`./dist/vendors.manifest.json`),
    }),
  );
},
});

产物:

 DONE  Compiled successfully in 34147ms 
 File                         Size                   Gzipped
 dist/umi.d7332489.js         2.0 MB                 691.9 KB
 dist/umi.26e98a26.css        185.3 KB               33.3 KB

效果对比:
若是去掉DllPlugin和DLLReferencePlugin相关的配置,构建出的产物:

 DONE  Compiled successfully in 58566ms 
 File                         Size                   Gzipped
 dist/umi.e3d6af5a.js         3.2 MB                 1.0 MB
 dist/umi.26e98a26.css        185.3 KB               33.3 KB

可见使用DllPlugin和DLLReferencePlugin后在线包构建产物的体积已经减少50%,时间上也加快了40%,上面的例子只是提取了react、antd-mobile等4个公共依赖,若是抽取全部的公共依赖,这个效果会更好。

第三步:在index.html中引入*.dll.js
最后我们需要在index.html中引入*.dll.js以及umi.js才能使项目正常运转。可以使用umi中的addHTMLHeadScripts配置,其他方法在此就不再详细介绍。
最终生成的index.html:
20211210163627.jpg

相关文章
|
前端开发 JavaScript 开发者
深入了解Webpack:现代JavaScript应用的打包利器
【10月更文挑战第11天】 深入了解Webpack:现代JavaScript应用的打包利器
|
前端开发 JavaScript
《Webpack5 核心原理与应用实践》学习笔记-> 构建微前端应用
《Webpack5 核心原理与应用实践》学习笔记-> 构建微前端应用
346 1
|
JavaScript 前端开发 API
Vue+Webpack+css预处理开发单页应用
Vue+Webpack+css预处理开发单页应用
333 0
Vue+Webpack+css预处理开发单页应用
|
JavaScript API
webpack 插件应用
webpack 插件应用
223 0
|
JavaScript 前端开发 API
webpack构建自定义vue应用
在上一篇中我们利用webpack从0到1搭建了一篇最基本的react应用,而vue在团队项目里也是用得非常之多,我们如何不依赖vue-cli脚手架搭建一个自己的vue工程化项目呢?
328 0
webpack构建自定义vue应用
|
前端开发 JavaScript
webpack构建自定义react应用
在上一篇文章中我们用webpack与webpack-cli搭建了最简单的前端应用,通常在项目中我们会用vue或者react,我们看下如何利用我们自己搭的工程来适配react
266 0
webpack构建自定义react应用
|
缓存 JavaScript 前端开发
分享:ThinkPHP和Webpack前后端结合构建SEO多页应用的一个思路
分享:ThinkPHP和Webpack前后端结合构建SEO多页应用的一个思路
368 0
分享:ThinkPHP和Webpack前后端结合构建SEO多页应用的一个思路
|
缓存 编解码 JSON
从0到1使用Webpack5 + React + TS构建标准化应用
本篇文章主要讲解如何从一个空目录开始,建立起一个基于webpack + react + typescript的标准化前端应用。
从0到1使用Webpack5 + React + TS构建标准化应用
Day13 - 闭包应用6 - 构建器打包webpack
Day13 - 闭包应用6 - 构建器打包webpack
260 0
|
移动开发 前端开发 API
【前端】webpack 搭建 React 应用环境(二)
webpack 搭建 React 应用环境(二)
236 0
【前端】webpack 搭建 React 应用环境(二)