本文主要介绍两个插件的使用,DllPlugin 和 DllReferencePlugin,后者配合前者使用。
项目 Github 地址:https://github.com/luxiancan/vue-permission-manage
介绍
打包会输出一个类 dll 包(dll 包源于 windows 的动态链接库),这些代码本身不会执行,主要是提供给我们的业务代码引用。(比如 dll 中有一个工具方法为获取本月日期数组,这个方法本身并不会执行,但是当我们的业务中需要获取本月日期时,就会引用这个方法在我们的业务中执行相关逻辑)。
DllPlugin 可以将特定的类库提前打包然后引入。这种方式可以极大的减少打包类库的次数,只有当类库更新版本才有需要重新打包,并且也实现了将公共代码抽离成单独文件的优化方案。
简单来说就是:
将静态资源文件(运行依赖包)与业务代码源文件分开打包,先使用 DllPlugin 给静态资源打包,再使用 DllReferencePlugin 让源文件引用资源文件。
作用
当我们一个项目引入了多个较大的包以后,这些包本身并不会运行,我们也不会修改这些包的代码,但是每当我们修改了业务代码之后,这些包也会被重新打包。极大的浪费了时间,这时我们就需要使用这个工具预先把静态资源提前打包,以后修改源文件再打包时就不会打包这些静态资源文件了。
开始搬砖
我们以 vue-cli 生成的项目为例:
1.基础安装
## 全局安装 vue-cli 脚手架 和 webpack
cnpm install -g vue-cli webpack-dev-server
## 初始化项目
winpty vue.cmd init webpack vue-permission-manage
cd vue-permission-manage
## 安装基础配置包
cnpm install
## 安装依赖模块(静态资源)
cnpm install vuex axios element-ui echarts -S
安装完成后的目录结构 (此处已经隐藏 node_modules 文件夹):
2.使用依赖及打包测试
我们编辑 main.js,引入我们所安装的静态资源,结果为:
import 'babel-polyfill';
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store/store.js';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import '@/assets/css/normalize.css';
import '@/assets/css/common.scss';
import httpRequest from '@/assets/js/service/http.js';
import '@/assets/js/service/mock.js';
Vue.config.productionTip = false;
Vue.use(ElementUI);
Vue.prototype.$http = httpRequest;
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
});
回到命令窗口,执行打包命令:
## 编译打包
npm run build
截图中可以看见 Time:65164ms,打包花费了65秒,vue 全家桶以及刚才引入的各种包和源代码全部被打包了。(打包时间也跟电脑配置有关,大家的都不一样,可能我的笔记本比较low所以有点慢吧,影响不大,往下走)
我们才引入了5-6个包而已,就已经花费了65秒,如果以后还要加上各种包及静态资源,打包时间肯定会更久。
这就是我们为什么要引入 DllPlugin 的原因!
3.预打包依赖模块
我们知道,我们刚才所引入的 vue 或者 axios 之类的,我们只是使用它们,并不会改变它们的源码,它们本身也不会运行,那么我们就可以把这些模块拆分出来提前打包。
那么如何提前打包它们呢? 我们在根目录的 build 文件夹下创建一个 webpack 配置文件(webpack.dll.conf.js),既然这个文件是 webpack 配置文件,那么它的格式肯定也和 webpack 的其他配置文件一样:
var path = require('path');
var webpack = require('webpack');
/* 将特定的类库提前打包然后引入,不但能够极大减少打包时间,
也实现了将公共代码抽离成单独文件的优化方案,可以很大程度的减小打包之后的文件体积。 */
module.exports = {
// 你想要提前打包的类库的数组。注意 vue 要写成别名
entry: {
// 如果这些类库有版本更新了(一般很少更新),就需要重新执行 npm run dll 打包类库,再执行 npm run build 打包项目上线
// 这里用 vendor 作为 key 值表示后文用到的 [name] ,后续生成的打包文件就为 vendor-manifest.json vendor.dll.js
vendor: ['vue/dist/vue.esm.js', 'vuex', 'axios', 'vue-router', 'element-ui', 'echarts']
},
output: {
path: path.join(__dirname, '../static/js'), // 打包后文件输出的位置,放到项目根目录的 static/js 下
filename: '[name].dll.js', // 打包后的文件名 vendor.dll.js
library: '[name]_library'
// vendor.dll.js 中暴露出的全局变量名,主要是给 DllPlugin 中的 name 使用。
// 所以这里需要和 webpack.DllPlugin 中的 name: '[name]_library', 保持一致。
},
plugins: [
new webpack.DllPlugin({
// manifest.json 生成的文件夹及名字,这里路径写成 .. 代表上一级目录,也就是让它生成在了根目录下
path: path.join(__dirname, '../[name]-manifest.json'),
// 和 output.library 保持一致即可
name: '[name]_library',
// manifest 文件中请求的上下文,默认为本文件的上下文
context: __dirname
}),
// 压缩打包的文件,使用 UglifyJsPlugin 插件压缩代码
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
};
重点:这里引入的 Dllplugin 插件,该插件将生成一个 manifest.json 文件,该文件供 webpack.dll.conf.js 中加入的 DllReferencePlugin 使用,使我们所编写的源文件能正确地访问到我们所需要的静态资源(运行时依赖包)。相关字段的解释已经在代码注释中写明。
编写该 webpack 配置之后,我们就可以预打包资源文件了。
## 以指定的 webpack 配置文件执行打包
webpack --config build/webpack.dll.conf.js
emmm。。。感觉这命令有点难记哎,那我们就将它加入 package.json 里吧
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"lint": "eslint --ext .js,.vue src test/unit",
"dll": "webpack --config build/webpack.dll.conf.js",
"build": "node build/build.js"
},
预打包资源文件:
npm run dll
可以看到 dll 相关的资源文件已经打包成功,此时的目录结构:
可见我们的目录结构中 static 下生成了 js 子目录,打包好的 dll 文件(js/vendor.dll.js)就放在该目录下,除此之外根目录中还生成了 vendor-manifest.json。
现在我们已经不再需要将那些静态资源包跟源文件一起打包了,但是这也需要在源文件的 webpack.base.conf.js 中配置 DllReferencePlugin 使用 vendor-manifest.json 来引用这个 dll。
4.打包源文件
这一步我们只需要改写 vue-cli 为我们生成好的 build/webpack.base.conf.js
即可:
该文件主要是添加了 plugins 配置:
plugins: [
new webpack.DllReferencePlugin({
context: __dirname, // 与 Dllplugin 里的 context 所指向的上下文保持一致,这里都是指向了当前文件的 build 目录
manifest: require('../vendor-manifest.json') // 引入 Dllplugin 所生成的的 manifest
})
],
到这里配置完这个就。。哦还没完别急,我们需要手动在根目录的 index.html 里引入生成的 dll 库
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
<script src="./static/js/vendor.dll.js"></script> <!--引入 vendor.dll.js -->
</body>
好的,激动人心的时刻终于来了!!!我们现在只需要 npm run build
看时间Time:20746ms!!!,比起之前的65秒我们缩短到了20秒左右!时间就是$$,时间就是生命啊!!
往后如果我们只是改动了业务代码,就不需要重新打包那些个各种庞大的类库了。不过还要注意一点,如果相关类库版本更新了,再次执行 npm install 的时候类库源码有更新,此时就需要重新执行一下 npm run dll 再执行 npm run build。为此,我们在 package.json 再加一个命令 dll_build:
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"lint": "eslint --ext .js,.vue src test/unit",
"dll": "webpack --config build/webpack.dll.conf.js",
"build": "node build/build.js",
"dll_build": "npm run dll && npm run build"
},
第一次打包时,或者类库版本更新了,执行 npm run dll_build
就好了~
到这里优化就结束啦,文章有不妥的地方欢迎指出留言哦,觉得不错的话点个赞点个星吧 hhh,github 源码地址在文章开头哦~
参考资料:
webpack 中文文档 | webpack 中文网
webpack进阶——DllPlugin优化打包性能(基于vue-cli)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。