媒介
公司有好幾個項目都有背景治理體系,為了輕易開闢,所以挑選了 vue 中比較火的 背景模板 作為基礎模板舉行開闢。然則,最先用的時刻,作者並沒有對此舉行優化,到項目上線的時刻,才發明,打包出來的文件都非常之大,就一個 vendor 就有 770k 的體積(下圖是基礎模板,什麼都沒加打包后的文件信息):
經由過程 webpack-bundle-analyzer
舉行剖析可得,體積重要泉源於 餓了么UI(體積為 500k),因為沒對其舉行部份引入拆分組件,致使 webpack 把全部組件庫都打包進去了。其次就是 vue 自身,體積也達到了 80k 之大。
所以,對其舉行打包優化,是一件迫在眉睫的事變。
優化
優化重要目標有:
- 加速資本加載速率,削減用戶守候的時候和首頁白屏時候,進步用戶體驗。
- 加速打包速率,不要將時候糟蹋在守候打包上。
處置懲罰第一個題目,許多人都邑想到資本文件放在 CDN 上就好了,沒錯,此次我們就是經由過程 CDN 來處置懲罰加載題目。
CDN – 進步加載速率
像 vue, element ui 這些比較成熟的框架/組件庫,平常都有免費、高速、大眾的 cdn 供開闢者運用,鑒於大部份用戶均在國內,所以此次運用了 bootcdn 這個庫。該庫熱門資本比較完全,各個版本都有,而且國內接見速率很快,簡直是開闢者的福音。
在 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>
<!-- 同時也要引入對應版本的 css -->
<link href="https://cdn.bootcss.com/element-ui/2.3.2/theme-chalk/index.css" 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>
因為依靠是從外部引入的,所以須要示知 webpack 在打包時,依靠的泉源。
修正 webpack.base.conf.js
:
module.exports = {
...
externals: {
vue: 'Vue',
'element-ui':'ELEMENT'
}
}
再一次打包,確切能極大的緊縮了打包的體積,從 700k 驟減至 130k:
然則隨之而來的就有題目了:
明顯我在當地開闢,然則因為引入了線上的臨盆版本的 vue 文件,因而 vue-dev-tools 就不能舉行調試。
因而,我們須要再次調解一下 webpack 的設置,webpack.base.conf.js
,而且 webpack 注入的 js 總是在末了面的,因而,我們須要 html-webpack-include-assets-plugin
幫助在注入 app.js
后,再注入相對應的組件庫 :
const HtmlWebpackIncludeAssetsPlugin = require('html-webpack-include-assets-plugin')
const externals = {
// 因為打包時,還沒注入,所以這裏要去掉。
// 'element-ui':'ELEMENT'
}
// 臨盆環境中運用臨盆環境的 vue
// 開闢環境繼承運用當地 node_modules 中的 vue
if (process.env.NODE_ENV === 'production') {
externals['vue'] = 'Vue'
// 如發明打包時照舊將 element-ui 打包進入 vendor,能夠在打包時將其到場外部依靠。
externals['element-ui'] = 'ELEMENT'
}
// 臨盆環境默許注入 vue
// 開闢環境中不注入
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。
// 臨盆環境中,這些 js 應當先加載。
append: process.env.NODE_ENV !== 'production',
publicPath: '',
})
]
module.exports = {
...
externals,
plugins,
...
}
OK,這時刻,既能統籌打包后的體積大小,也能在開闢形式中運用 vue-dev-tool 舉行調試。
DLL – 進步打包速率
常常打包的前端會發明,許多時刻,我們為了修復某些bug(如 promise 在 ie Safari 下的 bug),而新引入了一個 polyfill,但是,打包完后發明,vendor 的 hash 值變了,而全部 vendor 只新加了一個 es6-promise
的依靠,然則支付的價值就是,須要揚棄之前打包好的 vendor,用戶從新接見時,須要再一次拉取一個全新的 vendor,這個價值就有點大了。
這時刻,運用 dllPlugin 打包就有上風了。它能夠將一些基礎依靠模塊一致先打包起來,當正式打包時,則能夠略過這些模塊,不再反覆打包進去 vendor,進步打包速率的同時也能削減 vendor 的體積。
如,背景治理體系基礎模塊基礎有以下幾個:
- axios: ajax 要求。
- vuex: 全局狀況治理。
- js-cookie: 前端處置懲罰 cookie。
- vue-router: 路由治理。
這四個基礎模塊幾乎是必需的,那末能夠先提取出來。
step 1 打包基礎模塊
先在 build
文件夾下新建一個用於打包 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 在臨盆環境中運用的是 cdn 引入,所以也無需提早打包進 dll
// 'raven-js', // 前端監控,若無此需求,能夠疏忽。
'es6-promise', // 修復 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",
...
}
}
實行 yarn build:dll
或許 npm run build:dll
即可完成打包 dll。實行完成后:
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.
同時,能夠在 build
目錄下,找到各個模塊對應關聯文件 vendors-manifest.json
和 static/js
下的 vendor.dll.js
。
step 2 頁面中引入 vendor
打包后的 dll 文件須要手動在 index.html
引入:
<div id="app"></div>
<!-- built files will be auto injected -->
<script src="static/js/vendors.dll.js"></script>
step 3 通知 webpack 運用 dllPlugin 舉行打包
修正 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.
發明 vendor 如今只要 40k 的體積,削減了一半的體積,而且打包速率也快了 2s,而相對於最最先的基礎模板,打包速率快了 12s,這是很讓人欣喜。
跋文
運用了 cdn 和 dll 打包后,無論是打包速率照樣頁面加載的速率都有很大的提拔。因而將此次優化記錄下來,並傳上了 GitHub 中。