前言
hello,我們又見了~~嘻嘻。本次主要來說說這個打包優化的問題。一個vue專案從開發到上線必須得經歷打包過程,一個專案的打包優化與否都決定了你這個專案的執行速度以及使用者體驗。本次主要是針對vue.config,js
的配置進行優化。專案地址
開發環境與生產環境
開發環境與生產環境的配置也是開發中的必不可少的一環。本專案是由vue-cli3
開發,vue-cli3
深度整合了webpack
,如果不熟悉vue-cli3
可以先去官網看看相關配置。
開發環境
在專案根目錄下新建.env.development
檔案表明是開發環境。
VUE_APP_CURRENTMODE ="development" //當前的環境
VUE_APP_LOGOUT_URL="http://localhost:3000/" //開發環境的地址
複製程式碼
生產環境
在專案根目錄下新建.env.production
檔案表明是生產環境。
VUE_APP_CURRENTMODE ="development" //當前的環境
VUE_APP_LOGOUT_URL="xxx" //生產環境的地址
複製程式碼
當然你也可以自己建立一個測試環境.env.test
,同樣可以像上邊一樣配置。
環境運用
那麼接下來我們怎麼用它呢?這裡不得不說一下的是package.json
裡面的兩個命令serve
,build
,其實對應的是全命令是vue-cli-service serve --mode development
,vue-cli-service build --mode production
,如果你想要在構建命令中使用開發環境變數,那麼可以加入
"dev-build": "vue-cli-service build --mode development"
複製程式碼
接下來在vue.config.js
運用它。
config.plugin('define').tap(args => {
args[0]['process.env'].VUE_APP_LOGOUT_URL = JSON.stringify(process.env.VUE_APP_LOGOUT_URL)
console.log(args[0])
return args;
});
複製程式碼
這裡有必要說下,這段程式碼是寫在chainWebpack
配置項下面。這段程式碼其實運用了兩個webpack
外掛webpack-chain
允許配置鏈式操作,以及webpack.DefinePlugin
。
- webpack-chain:嘗試通過提供可鏈式或順流式的 API 建立和修改webpack 配置。瞭解更多
- webpack.DefinePlugin:它的作用是定義全域性常量,是常量。即在模組用它定義的全域性常量,那麼你就不能改變它。也就是說我定義了一個
process.env.VUE_APP_LOGOUT_URL
常量,在src
資料夾下面都可以使用。瞭解更多
分包(code splitting)
首先思考,我們引入的第三方包與我們的業務程式碼一起打包會產生什麼問題?
顧名思義,我們的業務程式碼變動比較頻繁,而我們引入的第三方包基本上不會變動。瀏覽器會有快取,沒有變動的檔案會直接從快取中讀取,這也間接的優化了網站的訪問速速。
接下來配置vue.config.js
,
分割第三方庫
//程式碼分割
config.optimization.minimize(true);
config.optimization.splitChunks({
chunks: 'all',
cacheGroup:{
//vue2-editor單獨打一個包
vueEdior: {
name: 'vueEdior',
test: /[\\/]node_modules[\\/]vue2-editor[\\/]/,
priority: 10 // 優先順序要大於 vendors 不然會被打包進 vendors
},
//其餘的第三方包打進vendor
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
}
}
})
複製程式碼
分割共用檔案
元件是vue專案的重要組成部分。相當一部分元件都可以公用,在不同的檔案中引入,因此我們可以將這部分公用的元件直接分割出來。
config.optimization.minimize(true);
config.optimization.splitChunks({
chunks: 'all',
cacheGroup:{
vueEdior: {
name: 'vueEdior',
test: /[\\/]node_modules[\\/]vue2-editor[\\/]/,
priority: 10 // 優先順序要大於 vendors 不然會被打包進 vendors
},
public: {
name: 'public',
test: resolve('src/components'),
minSize: 0, //表示在壓縮前的最小模組大小,預設值是 30kb
minChunks: 2, // 最小公用次數
priority: 5, // 優先順序
reuseExistingChunk: true // 公共模組必開啟
},
//其餘的第三方包打進vendor
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
}
}
})
複製程式碼
打包完後會發現dist/static/js
,多了一個vueEditor
和public
檔案,這就表明分割完成。
map檔案處理和別名設定(alias)
map檔案
我們可以進一步優化,打包預設生成map檔案,從而導致包的體積過大,這時我們需要設定一個屬性來關閉它。
productionSourceMap: false
複製程式碼
別名設定
alias
運用的好處在於不用一級級的去找,而是直接鎖定位置,從而減少檔案搜尋時間。
//設定別名
config.resolve.alias
.set('@', resolve('src'))
.set('@api', resolve('src/api/api'))//介面地址
.set('@assets', resolve('src/assets'))
複製程式碼
gzip壓縮與去console外掛
如果上面的方式都編寫了,檔案依舊過大,這個時候不得不考慮程式碼壓縮和去掉console外掛了,可以說為了優化專案,“無所不用其極”。
gzip壓縮
首先安裝開始安裝
cnpm install compression-webpack-plugin --save-dev
複製程式碼
然後在configureWebpack
裡面配置它
const CompressionWebpackPlugin = require('compression-webpack-plugin')
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' +
['js', 'css'].join('|') +
')$',
),
threshold: 10240,
minRatio: 0.8,
}),
複製程式碼
值得注意的是gzip
壓縮檔案需要後端來配合支援,如果後端沒有支援那麼專案載入的依舊是沒有壓縮的檔案。
去console外掛
首先安裝
cnpm install uglifyjs-webpack-plugin --save-dev
複製程式碼
然後在configureWebpack
裡面配置它
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false,
drop_debugger: true,
drop_console: true,
},
},
sourceMap: false,
parallel: true,
}),
複製程式碼
cdn引入
有的同學說後端沒有支援gzip
壓縮載入,那怎麼辦?那只有涼拌咯~~~。
這裡給大家介紹一個cdn引入的方式,有的第三方外掛太大,導致單獨分包後還是挺大的,這個時候可以考慮用cdn的方式引入檔案。
無外掛引入cdn
首先我們不讓webpack打包用cdn引入的檔案
//對一些不經常改動的庫,可以通過cdn引入,webpack不對他們打包
let externals = {
'vue': 'Vue',
'axios': 'axios',
'element-ui': 'ELEMENT',
'vue-router': 'VueRouter',
'vuex': 'Vuex',
'echarts': 'echarts',
'vue2-editor': 'VueEditor'
}
複製程式碼
然後配置cdn
const cdn = {
css: [
//element-ui css
'https://unpkg.com/element-ui/lib/theme-chalk/index.css'
],
js: [
//vue
'https://unpkg.com/vue@2.6.10/dist/vue.min.js',
//axios
'http://cdn.staticfile.org/axios/0.19.0-beta.1/axios.min.js',
//vuex
'https://unpkg.com/vuex@3.1.0/dist/vuex.min.js',
//vue-router
'https://unpkg.com/vue-router@3.0.6/dist/vue-router.min.js',
//element
'https://unpkg.com/element-ui@2.7.2/lib/index.js',
//echarts
'https://cdn.jsdelivr.net/npm/echarts@4.2.1/dist/echarts.min.js',
//vue2-editor
"https://unpkg.com/vue2-editor@2.6.6/dist/vue2-editor.js"
]
}
複製程式碼
接下來在chainWebpack
配置
process.env.VUE_APP_CURRENTMODE === 'production') {
config.externals(externals)//忽略打包
config.plugin('html')
.tap(args => {
args[0].cdn = cdn;
return args
})
}
複製程式碼
這裡需要解釋的是config.plugin('html')
其實是運用了html-webpack-plugin
外掛在其例項化的options
掛載cdn
物件,然後通過ejs
模板語法,讀取相關cdn。
緊接著我們需要在public/index.html
中讀取相關cdn
<% if (process.env.VUE_APP_CURRENTMODE === 'production') { %>
<% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
<link rel="stylesheet" href="<%=css%>" as="style">
<% } %>
<% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%=js%>"></script>
<% } %>
<% } %>
複製程式碼
至此cdn引入完成
外掛引入cdn
由於手動引入cdn太過麻煩,而且擔心版本變化,每次都需要手動去更改,所以為了更好的開發體驗,引入了自動匹配cdn外掛,webpack-cdn-plugin
。接下來開始安裝
cnpm install webpack-cdn-plugin --save
複製程式碼
例項化外掛
const cdnPlugin = require('webpack-cdn-plugin')
複製程式碼
接下來開始在configureWebpack
中引用
new cdnPlugin({
modules: [
{ name: 'vue', var: 'Vue', path: 'dist/vue.min.js' },
{ name: 'axios', var: 'axios', path: 'dist/axios.min.js' },
{ name: 'vuex', var: 'Vuex', path: 'dist/vuex.min.js' },
{ name: 'element-ui', var: 'ELEMENT', path: 'lib/index.js', style: 'lib/theme-chalk/index.css' },
{ name: 'echarts', var: 'echarts', path: 'dist/echarts.min.js' },
{ name: 'vue2-editor', var: 'VueEditor', path: 'dist/vue2-editor.js' },
{ name: 'vue-router', var: 'VueRouter', path: 'dist/vue-router.min.js' },
],
publicPath: '/node_modules'
})
複製程式碼
- name:外掛名
- var :專案中例項化的名字
- path:路徑名稱
- style:css路徑名稱
更多瞭解請參考官方文件。
總體來說引入第三方cdn
確實能帶來不錯的效果,但是有可能不穩定,因此建議大家在實際開發中自己去申請一個專屬的cdn
域名,將網站所要用到庫直接上傳上去。
結語
本期的打包優化就到這裡啦!感覺有很多廢話。哈哈~~,最後感謝大家閱讀,如果有問題以及錯誤請及時指正。