详解基于DllPlugin和DllReferencePlugin的webpack构建优化
本文详细解析如何利用Webpack的DllPlugin和DllReferencePlugin插件优化Vue项目的构建速度。通过预编译核心依赖库(vendor_library),分离业务代码与第三方库,显著减少重复编译时间。同时结合BundleAnalyzerPlugin分析包体积,并探讨按需加载策略对构建耗时与最终文件大小的影响,提供从配置到实战的完整优化方案。
项目背景与构建痛点
本项目基于vue-cli webpack2模板构建,集成了vue、vue-router、axios、muse-ui以及iview等依赖。目前单次构建耗时约40秒,这一速度令人难以接受。虽然在常规Web开发中构建时间并非核心关注点,但在开发Hybrid App时,频繁的构建需求使得优化速度变得至关重要。
项目结构划分与预编译策略
通常,我们可以将项目结构划分为三个主要部分。
| 分类 | 说明 | 变动频率 |
|---|---|---|
| vendor_library | 核心库 | 低 |
| vendor | 一般项目依赖 | 中等 |
| code | 业务逻辑 | 高 |
首先是vendor_library,包含vue、vue-router、axios等变动频率极低的文件。这些核心库非常适合利用DllPlugin和DllReferencePlugin进行预编译处理。
其次是vendor和code部分,这部分代码在开发阶段每次构建都需要重新编译。但在完成特定开发任务后,需要评估是否将某些vendor依赖移入vendor_library以进一步优化。
包体积分析与按需加载优化
接下来介绍BundleAnalyzerPlugin插件的使用。
BundleAnalyzerPlugin是一个用于分析Webpack生成包体组成,并以可视化方式反馈给开发者的工具。

Vue项目默认已集成该插件。执行npm run build --report命令后,即可查看当前项目的依赖情况及包体组成,从而据此做出相应的调整。
以下是主要的优化方向。
实施按需加载策略。
muse-ui和iview均提供了按需加载的支持,只需按照官方文档进行相应配置即可。
| 分类 | 耗时 | muse-ui | iview |
|---|---|---|---|
| before | 13256ms | 234KB | 337KB |
| after | 43211ms | 79KB | 75KB |
先来看优化后的结果。虽然被称为“优化后”,但构建时间反而延长了。这符合预期,因为之前直接引用的是dist目录下的文件,现在改为从src目录获取源码,增加了编译过程。
然而,文件体积的减少令人欣慰,具体效果取决于项目中模块的使用程度。在本项目中,仅使用了iview的四个控件,从结果看,按需加载在减小体积方面更为划算。虽然这并非时间上的优化,但由于DllPlugin解决了构建耗时问题,使得按需加载的优势得以充分发挥。
DllPlugin原理与优势解析
DllPlugin和DllReferencePlugin用于预编译资源模块。
Dll的概念借鉴自Windows系统的动态链接库。一个dll包本质上是纯依赖库,本身不可运行,仅供应用程序引用。
在打包dll时,Webpack会将所有包含的库建立索引,并写入一个manifest文件。引用dll的代码(即dll user)在打包时,只需读取该manifest文件即可。
这样做有以下几个好处:
Dll打包后独立存在,只要其包含的库没有增减或升级,其hash值就不会变化。因此,线上的dll代码无需随应用版本频繁更新。
当App部分代码修改后,只需编译App代码。只要dll中包含的库未增减或升级,就不需要重新打包dll,从而大幅提高每次编译的速度。
如果拥有多个项目且使用了相同的依赖库,它们可以共用同一个dll。
简而言之,我们可以将项目中公共且基本不会变动的模块(如前文所述的vendor_library)进行预编译。在后续项目构建过程中,直接引用预编译好的dll,无需再次编译。
这也是为什么按需加载能发挥更好效果的原因。在正常构建流程中,使用按需加载会导致每次构建时间比全量加载更长。而使用DllPlugin后,核心库只需编译一次,后续直接引用,从而抵消了按需加载带来的额外编译开销。
先来看一下改进后的结果。
| 分类 | 耗时 |
|---|---|
| before | 57192ms |
| after | 7890ms |
构建速度是否快到飞起?
DllPlugin实战配置步骤
DllPlugin和DllReferencePlugin的具体使用方法。
新建webpack.dll.conf.js文件。
//webpack.dll.conf.js
process.env.NODE_ENV = 'production'
const path = require('path');
var utils = require('./utils')
var vueLoaderConfig = require('./vue-loader.conf')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const webpack = require('webpack');
//vue项目默认有一个static目录.我就把导出目录放在了static/dll/目录下
const srcPath = path.join(__dirname, '../static/dll/');
//需要编译的模块
const vendors = ['vue/dist/vue.esm.js',
'vue-router',
'vue-localstorage',
'material-design-icons/iconfont/material-icons.css',
'iview/dist/styles/iview.css',
'iview/src/components/tag/tag.vue'
'muse-ui/src/appBar'
];
webpackConfig = {
entry: {
vendor: vendors
},
resolve: {
extensions: ['.js', '.vue', '.json']
},
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /iview.src.*?js$/,
loader: 'babel-loader'
},
{
test: /muse-ui.src.*?js$/,
loader: 'babel-loader'
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: "css-loader"
})
},
{
test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
publicPath: './',
limit: 1000,
name: 'fonts/[name].[ext]'
}
}]
},
output: {
path: srcPath, // 输出的路径
filename: '[name].dll.js', // 输出的文件,将会根据entry命名为vendor.dll.js
library: '[name]_library' // 暴露出的全局变量名
},
plugins: [
new ExtractTextPlugin({
filename: '[name].dll.css'
}),
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true
}
}),
new webpack.optimize.UglifyJsPlugin({ // uglifjs压缩
compress: {
warnings: false
}
}),
new webpack.DllPlugin({
path: path.join(srcPath, '[name]-mainfest.json'), // 描述依赖对应关系的json文件
name: '[name]_library',
context: __dirname // 执行的上下文环境,对之后DllReferencePlugin有用
})
]
}
if (process.env.npm_config_report) {
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig;
这本质上是一个正常的构建配置文件,根据项目需求修改即可。唯一区别在于plugins中多了一个DllPlugin,它会生成一个描述依赖对应关系的json文件。
static目录结构如下。
|____dll
| |____fonts
| |____vendor-mainfest.json
| |____vendor.dll.css
| |____vendor.dll.js
根据构建结果修改模板index.html。
//head 标签
<link type="text/css" rel="stylesheet" href="./static/dll/vendor.dll.css" rel="external nofollow" >
//body 标签
<script src="./static/dll/vendor.dll.js"></script>
修改webpack.base.conf.js。
plugins: [
...,
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('../static/dll/vendor-mainfest.json') // 指向生成的json文件
})
]
执行构建命令。
webpack --config ./build/webpack.dll.conf.js
你也可以将该语句放入npm run脚本中。'build:dll:report'是为了优化dll依赖关系而添加的额外命令。前文已提及,我们可以借助BundleAnalyzerPlugin插件查看当前包的依赖情况和包体组成。
//package.json
"scripts":{
"build:dll": "webpack --config ./build/webpack.dll.conf.js",
"build:dll:report": "npm run build:dll --report"
}
npm run build …看看这次的构建时间吧
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
怎么在React或Vue前端中使用Cube.js Client获取数据
2026-11-03 09:24:09
Vue.js 新手入门:怎么使用 Vite 快速搭建第一个项目
2026-11-02 10:30:55
Vue 项目中封装 heatmap.js:生命周期管理与内存释放
2026-11-02 09:17:40
uni-app 自定义组件开发与通信机制详解
2026-11-01 02:03:46
Vue.js 项目中 Mock 数据的三种实现方案
2026-10-31 17:23:18
