Vite 效能篇:掌握這些優化策略,一起縱享絲滑!

語言: CN / TW / HK

highlight: atom-one-dark theme: cyanosis


很多兄弟都在使用 Vite 了,但如果你是前端 leader 或者是團隊核心的話,不得不可考慮的一個問題就是效能優化。Vite 在開發環境效能已經非常不錯了,生產環境應該如何優化呢?其實優化方式和 Webpack 差不多,只不過 Vite 打包時用的是 Rollup 。那麼還等什麼,一起學起來!

分包策略

預設情況下,瀏覽器重複請求相同名稱的靜態資源時,會直接使用快取的資源。利用這個機制我們可以將不會經常更新的程式碼單獨打包成一個 JS 檔案,這樣就可以減少 HTTP 請求,同時降低伺服器壓力。以 lodash 為例:

js npm i lodash 安裝 lodash ,然後在 main.js 中寫入以下程式碼:

```js // src/main.js import { cloneDeep } from 'lodash'

const obj = cloneDeep({}) ``` 打包結果:

專案程式碼和依賴模組打包成了一個 JS 檔案。接著我們來配置分包,修改底層的 Rollup 配置:

```js // vite.config.js import { defineConfig } from 'vite'

export default defineConfig({ build: { rollupOptions: { output: { manualChunks: id => { // 將 node_modules 中的程式碼單獨打包成一個 JS 檔案 if(id.includes('node_modules')) { return 'vendor' } } } } } }) ```

打包結果如下:

image.png

可以看到依賴模組已經單獨生成一個 JS 檔案了。這樣我們即使修改了 main.js 中的程式碼重新打包,依賴檔案 vendor.528a7280.js 也不會發生變化的,對於這個檔案,瀏覽器也不會再次發起請求。如果依賴模組很多的話,效能是不是有很大的提升呢?

treeshaking

treeshaking 也被稱為 “搖樹優化”。簡單來講,就是在保證程式碼執行結果不變的前提下,去除無用的程式碼。Vue3中,許多 ApI 的引入都支援 treeshaking 優化。也就是說只打包你用到的 API,忽略那些沒有用到的。

Vue3 會預設使用 Rollup 進行 treeshaking ,不需要額外進行配置。但有一個條件,必須是 ES6 module 模組才行。還是上面那個例子:

```js // src/main.js import { cloneDeep } from 'lodash'

const obj = cloneDeep({}) ```

72aeca16b1d067872d84cb9c77caf0e.png

由於 lodash 是使用 CommonJS 規範的模組,所以無法進行 treeshaking ,Vue 會把整個 lodash 依賴打包進來。整個依賴檔案的大小是 78.64 KB

然後我們使用 ESM 版的 loadsh 對比一下:

js npm i lodash-es ```js // src/main.js import { cloneDeep } from 'lodash-es'

const obj = cloneDeep({}) ``` 打包結果如下:

image.png

可以看到依賴體積瞬間變成了 13.23 KB ,是不是一下小了很多。所以我們在選擇第三方庫時,要儘可能使用 ESM 版本,可以提升不少效能!

gzip 壓縮

gzip 是一種使用非常普遍的壓縮格式。使用 gzip 壓縮可以大幅減小程式碼體積,提升網路效能。開啟 gzip 也比較簡單,使用一個外掛就可以了:

js npm i vite-plugin-compression

```js // vite.config.js import { defineConfig } from 'vite' import viteCompression from 'vite-plugin-compression'

export default defineConfig({ plugins: [viteCompression()] }) ``` 打包結果如下:

image.png

可以看到經過 gzip 壓縮後,vendor.6fd516d3.js 檔案從 13.23 KB 降到了 4.62KB,檔案體積縮小了近 2/3 ,是不是很 nice。接下來就是後端同學的工作了:當請求靜態資源時,如果發現有對應的 gzip 的檔案,直接把 gzip 內容返給前端,並且設定一個響應頭 content-encoding: gzip

完整邏輯是,我們需要把瀏覽器支援的壓縮型別傳給服務端,在請求頭中設定 accept-encoding: gzip, deflate, br,只不過這一步瀏覽器通常幫我們都做了。然後服務端根據瀏覽器支援的型別,設定響應頭 content-encoding: gzip ,告訴瀏覽器以何種方式進行解壓。

注意:因為瀏覽器解壓也需要時間,所以程式碼體積不是很大的話不建議使用 gzip 壓縮。

cdn 加速

內容分發網路(Content Delivery Network,簡稱 CDN)就是讓使用者從最近的伺服器請求資源,提升網路請求的響應速度。通常我們請求依賴模組使用 CDN ,而請求專案程式碼依然使用自己的伺服器。還是以 lodash 為例:

```js // src/main.js import _ from 'lodash'

const obj = _.cloneDeep({}) ```

使用 CDN 也比較簡單,一個外掛就可以搞定:

js npm i vite-plugin-cdn-import -D

```js // vite.config.js import { defineConfig } from 'vite' import viteCDNPlugin from 'vite-plugin-cdn-import'

export default defineConfig({ plugins: [ viteCDNPlugin({ // 需要 CDN 加速的模組 modules: [ { name: 'lodash', var: '_', path: http://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js } ] }) ] }) `` 構建成功後,Vite 會自動幫我們將 cdn 資源通過script標籤插入到html` 中:

image.png

這樣請求 lodash 資源就會產生加速 buff ,而且專案體積也會大大減小!

圖片壓縮

根據專案對清晰度的要求,我們可以使用 vite-plugin-imagemin 外掛,對圖片進行適當壓縮:

js npm i vite-plugin-imagemin -D

```js // vite.config.js import { defineConfig } from 'vite' import viteImagemin from 'vite-plugin-imagemin'

export default defineConfig({ plugins: [ viteImagemin({ gifsicle: { optimizationLevel: 7, interlaced: false }, optipng: { optimizationLevel: 7 }, mozjpeg: { quality: 20 }, pngquant: { quality: [0.8, 0.9], speed: 4 }, svgo: { plugins: [ { name: 'removeViewBox' }, { name: 'removeEmptyAttrs', active: false } ] } }) ] }) ``` 不同格式的檔案配置也不一樣,具體可以參考 github :vite-plugin-imagemin

構建分析

分析依賴模組的大小佔比,可以讓我們更有針對性的進行體積優化。我們通常使用 rollup-plugin-visualizer 外掛進行構建分析,方法也比較簡單:

js npm install rollup-plugin-visualizer -D

```js // vite.config.js import { defineConfig } from 'vite' import { visualizer } from 'rollup-plugin-visualizer';

export default defineConfig({ plugins: [ // 將 visualizer 外掛放到最後 visualizer() ] }) ``npm run build,構建成功之後會在根目錄下生成一個stats.html,開啟頁面即可以看到分析結果。我們還可以通過左上角的排除包含` 輸入框對依賴模組進行篩選。同時滑鼠移入各模組,可以看到詳細的分析資料:

vite分析.png

小結

ok,今天的分享就是這些。如果你的專案已經在用 Vite ,不妨試驗一下以上方案,看看專案會不會變得更加絲滑。又到年底了,今年能挺過來的都不容易。最後祝大家都能拿到滿意的年終獎~😋