詳解使用vue-admin-template的優(yōu)化歷程
前言
公司有好幾個(gè)項(xiàng)目都有后臺(tái)管理系統(tǒng),為了方便開發(fā),所以選擇了 vue 中比較火的后臺(tái)模板 作為基礎(chǔ)模板進(jìn)行開發(fā)。但是,開始用的時(shí)候,作者并沒有對此進(jìn)行優(yōu)化,到項(xiàng)目上線的時(shí)候,才發(fā)現(xiàn),打包出來的文件都十分之大,就一個(gè) vendor 就有 770k 的體積(下圖是基礎(chǔ)模板,什么都沒加打包后的文件信息):

通過 webpack-bundle-analyzer 進(jìn)行分析可得,體積主要來源于餓了么UI(體積為 500k),因?yàn)闆]對其進(jìn)行部分引入拆分組件,導(dǎo)致 webpack 把整個(gè)組件庫都打包進(jìn)去了。其次就是 vue 本身,體積也達(dá)到了 80k 之大。

所以,對其進(jìn)行打包優(yōu)化,是一件刻不容緩的事情。
優(yōu)化
優(yōu)化主要目的有:
- 加快資源加載速度,減少用戶等待的時(shí)間和首頁白屏?xí)r間,提高用戶體驗(yàn)。
- 加快打包速度,不要將時(shí)間浪費(fèi)在等待打包上。
解決第一個(gè)問題,很多人都會(huì)想到資源文件放在 CDN 上就好了,沒錯(cuò),這次我們就是通過 CDN 來解決加載問題。
CDN - 提高加載速度
像 vue, element ui 這些比較成熟的框架/組件庫,一般都有免費(fèi)、高速、公共的 cdn 供開發(fā)者使用,鑒于大部分用戶均在國內(nèi),所以這次使用了 bootcdn 這個(gè)庫。該庫熱門資源比較齊全,各個(gè)版本都有,而且國內(nèi)訪問速度很快,簡直是開發(fā)者的福音。
在 index.html 中引入 vue 和 餓了么組件。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>vue-admin-template</title> <!-- 同時(shí)也要引入對應(yīng)版本的 css --> <link rel="external nofollow" rel="stylesheet"> </head> <body> <div id="app"></div> <!-- built files will be auto injected --> <!-- 先引入 Vue --> <script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script> <!-- 引入組件庫 --> <script src="https://cdn.bootcss.com/element-ui/2.3.2/index.js"></script> <script src="https://cdn.bootcss.com/element-ui/2.3.2/locale/zh-CN.min.js"></script> </body> </html>
因?yàn)橐蕾囀菑耐獠恳氲?,所以需要告?webpack 在打包時(shí),依賴的來源。
修改 webpack.base.conf.js:
module.exports = {
...
externals: {
vue: 'Vue',
'element-ui':'ELEMENT'
}
}
再一次打包,確實(shí)能極大的壓縮了打包的體積,從 700k 驟減至 130k:

但是隨之而來的就有問題了:

明明我在本地開發(fā),但是由于引入了線上的生產(chǎn)版本的 vue 文件,因此 vue-dev-tools 就不能進(jìn)行調(diào)試。
因此,我們需要再次調(diào)整一下 webpack 的配置,webpack.base.conf.js,而且 webpack 注入的 js 總是在最后面的,因此,我們需要 html-webpack-include-assets-plugin 幫忙在注入 app.js 后,再注入相對應(yīng)的組件庫 :
const HtmlWebpackIncludeAssetsPlugin = require('html-webpack-include-assets-plugin')
const externals = {
// 因?yàn)榇虬鼤r(shí),還沒注入,所以這里要去掉。
// 'element-ui':'ELEMENT'
}
// 生產(chǎn)環(huán)境中使用生產(chǎn)環(huán)境的 vue
// 開發(fā)環(huán)境繼續(xù)使用本地 node_modules 中的 vue
if (process.env.NODE_ENV === 'production') {
externals['vue'] = 'Vue'
// 如發(fā)現(xiàn)打包時(shí)依舊將 element-ui 打包進(jìn)入 vendor,可以在打包時(shí)將其加入外部依賴。
externals['element-ui'] = 'ELEMENT'
}
// 生產(chǎn)環(huán)境默認(rèn)注入 vue
// 開發(fā)環(huán)境中不注入
const defaultJS = process.env.NODE_ENV === 'production' ? [{ path: 'https://cdn.bootcss.com/vue/2.4.2/vue.min.js', type: 'js' }] : []
const plugins = [
new HtmlWebpackIncludeAssetsPlugin({
assets: defaultJS.concat([
{ path: 'https://cdn.bootcss.com/element-ui/2.3.2/index.js', type: 'js' },
{ path: 'https://cdn.bootcss.com/element-ui/2.3.2/locale/zh-CN.min.js', type: 'js' },
]),
// 是否在 webpack 注入的 js 文件后新增?true 為 append, false 為 prepend。
// 生產(chǎn)環(huán)境中,這些 js 應(yīng)該先加載。
append: process.env.NODE_ENV !== 'production',
publicPath: '',
})
]
module.exports = {
...
externals,
plugins,
...
}
OK,這時(shí)候,既能兼顧打包后的體積大小,也能在開發(fā)模式中使用 vue-dev-tool 進(jìn)行調(diào)試。
DLL - 提高打包速度
經(jīng)常打包的前端會(huì)發(fā)現(xiàn),很多時(shí)候,我們?yōu)榱诵迯?fù)某些bug(如 promise 在 ie Safari 下的 bug),而新引入了一個(gè) polyfill,然而,打包完后發(fā)現(xiàn),vendor 的 hash 值變了,而整個(gè) vendor 只新加了一個(gè) es6-promise 的依賴,但是付出的代價(jià)就是,需要拋棄之前打包好的 vendor,用戶重新訪問時(shí),需要再一次拉取一個(gè)全新的 vendor,這個(gè)代價(jià)就有點(diǎn)大了。
這時(shí)候,使用 dllPlugin 打包就有優(yōu)勢了。它可以將一些基礎(chǔ)依賴模塊統(tǒng)一先打包起來,當(dāng)正式打包時(shí),則可以略過這些模塊,不再重復(fù)打包進(jìn)去 vendor,提高打包速度的同時(shí)也能減少 vendor 的體積。
如,后臺(tái)管理系統(tǒng)基礎(chǔ)模塊基本有以下幾個(gè):
- axios: ajax 請求。
- vuex: 全局狀態(tài)管理。
- js-cookie: 前端處理 cookie
- vue-router: 路由管理。
這四個(gè)基礎(chǔ)模塊幾乎是必須的,那么可以先提取出來。
step 1 打包基礎(chǔ)模塊
先在 build 文件夾下新建一個(gè)用于打包 dll 的配置文件 webpack.dll.conf.js:
const webpack = require('webpack');
const path = require('path');
const vueLoaderConfig = require('./vue-loader.conf')
const utils = require('./utils')
function resolve(dir) {
return path.join(__dirname, '..', dir)
}
const vendor = [
// 'vue/dist/vue.runtime.esm.js', // 由于 vue 在生產(chǎn)環(huán)境中使用的是 cdn 引入,所以也無需提前打包進(jìn) dll
// 'raven-js', // 前端監(jiān)控,若無此需求,可以忽略。
'es6-promise', // 修復(fù) promise 中某些 bug。
'vue-router',
'js-cookie',
'axios',
'vuex',
];
const webpackConfig = {
context: __dirname,
output: {
path: path.join(__dirname, '../static/js/'),
filename: '[name].dll.js',
library: '[name]_[hash]',
},
entry: {
vendor
},
plugins: [
new webpack.DllPlugin({
context: __dirname,
path: path.join(__dirname, '.', '[name]-manifest.json'),
name: '[name]_[hash]',
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true,
// parallel: true
})
],
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
}
};
module.exports = webpackConfig
然后在 package.json 中加入一條命令:
{
"scripts": {
...
"build:dll": "webpack --config build/webpack.dll.conf.js",
...
}
}
執(zhí)行 yarn build:dll 或者 npm run build:dll 即可完成打包 dll。執(zhí)行完成后:
yarn build:dll
yarn run v1.5.1
$ webpack --config build/webpack.dll.conf.js
Hash: f6894dff019b2e0734af
Version: webpack 3.10.0
Time: 1295ms
Asset Size Chunks Chunk Names
vendor.dll.js 62.6 kB 0 [emitted] vendor
[8] dll vendor 12 bytes {0} [built]
+ 32 hidden modules
✨ Done in 1.89s.
同時(shí),可以在 build 目錄下,找到各個(gè)模塊對應(yīng)關(guān)系文件 vendors-manifest.json 和 static/js 下的 vendor.dll.js。
step 2 頁面中引入 vendor
打包后的 dll 文件需要手動(dòng)在 index.html 引入:
<div id="app"></div> <!-- built files will be auto injected --> <script src="static/js/vendors.dll.js"></script>
step 3 告訴 webpack 使用 dllPlugin 進(jìn)行打包
修改 build/webpack.prod.conf.js:
module.exports = {
plugins: [
...
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./vendor-manifest.json')
}),
...
]
}
再次打包:
$ yarn build:report
yarn run v1.5.1
$ npm_config_report=true node build/build.js
Hash: b4ff51852866ed865cfd
Version: webpack 3.10.0
Time: 6532ms
Asset Size Chunks Chunk Names
static/js/manifest.42b9584a653aec2b9c5e.js 1.5 kB 5 [emitted] manifest
static/img/404.a57b6f3.png 98.1 kB [emitted]
static/js/1.9e4133a25808e2101dd3.js 1 kB 1 [emitted]
static/js/2.2a8a8e01c51473fab882.js 4.34 kB 2 [emitted]
static/js/vendor.c7b076ef3341d4711402.js 39.4 kB 3 [emitted] vendor
static/js/app.6d52c7a5bf1bacb5cc85.js 21.4 kB 4 [emitted] app
static/js/0.cbc645864aab28ae8055.js 15.3 kB 0 [emitted]
static/css/app.1b30f8eba210e245a5f96d7bf0d6fb6c.css 7.6 kB 4 [emitted] app
favicon.ico 67.6 kB [emitted]
index.html 986 bytes [emitted]
static/js/vendor.dll.js 62.6 kB [emitted]
Build complete.
Tip: built files are meant to be served over an HTTP server.
Opening index.html over file:// won't work.
發(fā)現(xiàn) vendor 現(xiàn)在只有 40k 的體積,減少了一半的體積,而且打包速度也快了 2s,而相對于最開始的基礎(chǔ)模板,打包速度快了 12s,這是很讓人欣慰。
后記
使用了 cdn 和 dll 打包后,無論是打包速度還是頁面加載的速度都有很大的提升。因此將此次優(yōu)化記錄下來,并傳上了 GitHub 中。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue移動(dòng)端時(shí)彈出側(cè)邊抽屜菜單效果
這篇文章主要介紹了vue移動(dòng)端時(shí)彈出側(cè)邊抽屜菜單,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06
vue+element-ui?校驗(yàn)開始時(shí)間與結(jié)束時(shí)間的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue+element-ui?校驗(yàn)開始時(shí)間與結(jié)束時(shí)間的代碼實(shí)現(xiàn),最主要的需求是開始時(shí)間不能早于當(dāng)前時(shí)間,感興趣的朋友跟隨小編一起看看吧2024-07-07
Vue實(shí)現(xiàn)驗(yàn)證碼登錄的方法實(shí)例
最近在自己寫頁面,然后寫登錄注冊UI的時(shí)候需要一個(gè)驗(yàn)證碼組件,去搜一下沒找到什么合適的,于是自己寫一個(gè),這篇文章主要給大家介紹了關(guān)于Vue實(shí)現(xiàn)驗(yàn)證碼登錄的相關(guān)資料,需要的朋友可以參考下2022-03-03
如何封裝了一個(gè)vue移動(dòng)端下拉加載下一頁數(shù)據(jù)的組件
這篇文章主要介紹了如何封裝了一個(gè)vue移動(dòng)端下拉加載下一頁數(shù)據(jù)的組件,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01
Vue3中實(shí)現(xiàn)微信掃碼登錄的步驟和代碼示例
在 Vue 3 中實(shí)現(xiàn)微信掃碼登錄,涉及到前端生成二維碼、監(jiān)聽微信回調(diào)以及與后端的交互,本文給大家介紹了一個(gè)詳細(xì)的實(shí)現(xiàn)步驟和代碼示例,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-07-07
詳解vue的數(shù)據(jù)劫持以及操作數(shù)組的坑
這篇文章主要介紹了vue的數(shù)據(jù)劫持以及操作數(shù)組的坑,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04

