大家好,我是貓小白,本文基於vue2,全文閲讀大約需要3分鐘。
談到webpack優化大部分人可能都看膩了,無非就那幾招嘛,我之前也是看過許多類似的文章,但都沒有自己真正上手過,下面是我用公司的項目真實操練下來的,首屏加載速度提升很大(刷刷的),希望能幫到你。
廢話不多説,先看看對比成果!
| 類型 | 優化前 | 優化後 |
|---|---|---|
| js文件大小 | 24MB | 3MB |
| 主頁首屏顯示 | 9s | 1s |
這簡直太誇張了,提升了8倍?可以想象以前是多慢,要等半天啊。蠻王這個真男人都開大2次了~
可以看到,優化前後首屏加載速度有質的提升,之前一直想優化我們項目的首屏加載時間,有緩存還好,沒有緩存屏幕白屏都要等待7、8s。特別是有的客户第一次打開這個系統,那7、8秒猶如過了一個世紀,非常尷尬。那麼我做了那些常規操作呢?
1.生產環境關閉productionSourceMap、css sourceMap
眾所周知,SourceMap就是當頁面出現某些錯誤,能夠定位到具體的某一行代碼,SourceMap就是幫你建立這個映射關係的,方便代碼調試。在生產環境中我們完全沒必要開啓這個功能(誰在生產環境調試代碼?不會是你吧)
如下配置:
const isProduction = process.env.NODE_ENV === 'production' // 判斷是否是生產環境
module.exports = {
productionSourceMap: !isProduction, //關閉生產環境下的SourceMap映射文件
css: {
sourceMap: !isProduction, // css sourceMap 配置
loaderOptions: {
...其它代碼
}
},
...其它代碼
}
此時再npm run build 打包,就會發現速度快了很多,體積瞬間只有幾兆了!
2.分析大文件,找出內鬼
安裝 npm install webpack-bundle-analyzer -D 插件,打包後會生產一個本地服務,清楚的展示打包文件的包含關係和大小。
vue.config.js 配置:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
...其它
configureWebpack: [
plugins: [
new BundleAnalyzerPlugin() // 分析打包大小使用默認配置
]
},
...其它
}
自動彈出一個服務,清晰的展示打包後js的文件大小:
通過圖中可以發現:
- element-ui和ant-design佔了近1/4的大小:
1.53MB。 - exceljs也是個大東西有:
1.3MB - echarts.js文件也接近
1MB - moment.js也有
700KB
打包後js文件一共就5MB,這五個哥們就佔了4M左右。不分析好還,一分析嚇得夠嗆~
不要虛!找到刺了,一個一個來拔掉就好了。相信我拔掉的過程是很爽的。
一個一個解決,拔刺
1.把必須要用的第三方js通過cdn的方式引用
分析發現,elementui、echarts是必須使用的,打包又耗時且頁面加載也較慢得很。可以通過cdn直接引入,方便且速度快。
1.element-ui是我們項目用的主要框架,所以這個肯定是少不了,但是項目裏面ant-design為什麼會存在呢,原來是發現有個頁面使用了antd的進度條組件,因為elementui的進度條不太好看。但是沒想到這樣把整個antd都導進來了。
方案:
- 捨棄
antd組件,自己去找一個類似的vue插件或者乾脆自己實現一個。(這個方法短時間無法完成,且不想去動以前代碼,暫不考慮) - 使用
antd部分加載。只加載想要的進度條組件,可以減少文件體積(這個方法簡單粗暴,就是犧牲一些文件大小)。
我們使用方案2,根據antd官方的文檔配置部分組件的引入。
安裝 npm install babel-plugin-import -D
1 main.js導入需要的組件 Step
import { Steps } from 'ant-design-vue';
Vue.component(Steps.name, Steps);
Vue.component(Steps.Step.name, Steps.Step);
2 babel.config.js 加上配置:
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
//以下是按需加載的配置++++
plugins: [
[
"import",
{
libraryName: "ant-design-vue",
libraryDirectory: "es",
style: true
}
]
]
}
此時再分析,antd已經小了很多。
2.使用cdn加載第三方js。
我們項目裏面第三方js很多,有些打包下來會很大,而且加載速度較慢。我們把這些js分離出來,通過cdn的方式在html中的script標籤中直接使用,一方面減少打包體積,一方面提高了加載速度。
這裏推薦一個免費的cdn: BootCDN。也可以使用自己購買的付費cdn服務,我們到網站搜索自己項目需要的js。例如:vue
注意,一定要選擇自己項目對應的版本,否則會出現各種奇怪的問題
我的項目使用的是 "vue": "^2.6.12", (package.json)
第一步:配置vue.config.js,讓webpack不打包這些js,而是通過script標籤加入。
const isProduction = process.env.NODE_ENV === 'production' // 判斷是否是生產環境
//正式環境不打包公共js
let externals = {}
//儲存cdn的文件
let cdn = {
css: [
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.0/theme-chalk/index.min.css' // element-ui css 樣式表
],
js: []
}
//正式環境才需要
if (isProduction) {
externals = { //排除打包的js
vue: 'Vue',
'element-ui': 'ELEMENT',
echarts: 'echarts',
}
cdn.js = [
'https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js', // vuejs
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.6.0/index.js', // element-ui js
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.6.0/locale/zh-CN.min.js',
'https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.min.js',
]
}
module.exports = {
//...其它配置
configureWebpack: {
//常用的公共js 排除掉,不打包 而是在index添加cdn,
externals,
//...其它配置
},
chainWebpack: config => {
//...其它配置
// 注入cdn變量 (打包時會執行)
config.plugin('html').tap(args => {
args[0].cdn = cdn // 配置cdn給插件
return args
})
}
//...其它配置
}
第二步:html模板中加入定義好的cdn變量使用的代碼
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>web</title>
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- 引入樣式 -->
<% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
<link rel="stylesheet" href="<%=css%>" >
<% } %>
<!-- 引入JS -->
<% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%=js%>"></script>
<% } %>
</head>
<body style="font-size:14px">
<div id="app"></div>
</body>
</html>
可以發現cdn.js中,我把vue、echarts、element-ui這三個大頭加入了。在externals對象中左側是npm包的名稱,右側是在代碼中暴露的全局變量。注意element-ui對應的是 ELEMENT。
沒有ant-design-vue是因為我們上面使用了部分加載的方式,如果使用cdn這種方式是加載全部的代碼,有點浪費。
沒有使用exclejs,是因為exceljs在我的業務代碼中不是直接引用的,而是一個叫table2excel間接依賴的。所以就算我通過上面的方法排除掉它,在打包的時候還是會通過table2excel的依賴找到它並打包。
那這種不可避免的情況,該如何優化,讓加載速度不受影響呢?
答案是通過懶加載的方式:
1.script標籤中註釋掉 import Table2Excel from "table2excel.js";
2.下載的方法中:
download(){
//使用import().then()方式
import("table2excel.js").then((Table2Excel) => {
new Table2Excel.default("#table").export('filename') //多了一層default
})
}
這樣在進入系統時,不會加載Table2Excel 和exceljs,當需要時才會去加載,第一次會慢一點,後面就不需要加載了,會變快。
3 moment.js的優化
我們發現monentjs在項目中有使用來對時間格式化,但是使用頻率並不高,完全可以自己實現一個format方法,或者使用只有6kb的day.js.
但這裏我們暫不替換,把moment變得瘦小一些即可,刪除掉除中文以外的語言包。
第一步:vue.config.js
...其它配置
chainWebpack: config => {
config.plugin('ignore')
//忽略/moment/locale下的所有文件
.use(new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/))
}
...其它配置
第二步:main.js
import moment from 'moment'
//手動引入所需要的語言包
import 'moment/locale/zh-cn';
// 指定使用的語言
moment.locale('zh-cn');
這次我們看看moment打包後多大:
只有174kb了。不過,有一説一還是day.js香~
做完上面這些動作我們的js文件總大小:3.04MB ,其中包含 1.3MB的懶加載js,剩下的1.7MB左右的js基本上不會對頁面造成很大的卡頓。
還有進步空間?
1.通過 compression-webpack-plugin 插件把代碼壓縮為gzip。但是!需要服務器支持
webpack端 vue.config.js配置如下:
//打包壓縮靜態文件插件
const CompressionPlugin = require("compression-webpack-plugin")
//...其它配置
module.exports = {
//...其它配置
chainWebpack: config => {
//生產環境開啓js\css壓縮
if (isProduction) {
config.plugin('compressionPlugin').use(new CompressionPlugin({
test: /\.(js)$/, // 匹配文件名
threshold: 10240, // 對超過10k的數據壓縮
minRatio: 0.8,
deleteOriginalAssets: true // 刪除源文件
}))
}
}
//...其它配置
}
打包大小由3MB到860KB,感覺起飛了~
服務器端配置這裏就不詳細説明了可以谷百: nginx開啓靜態壓縮 找到答案。
最後貼上優化前後的無緩存下的首屏加載時間對比(chrome瀏覽器),絕對包真:
優化前項目網站首屏加載數據:9.17s
優化後項目網站首屏加載數據:1.24s
這些都是在工作之餘,自己抽時間去查閲各位大佬的帖子,雖然都是些耍欄了的技術,但是真的要在自己項目中實施還是需要一些時間和精力,大多數都是為了完成功能快速迭代而忽略掉了做程序原本的目的,就是要讓用户有一個良好的使用體驗。
肯請各位大佬,不要忘了給我點贊、評論、收藏 。
往期精彩:
1.什麼是迭代器(iterator)?Generator和它有什麼關聯
2.微信小程序UI組件、圖表、自定義bar這些坑都幫你踩了