Vue專案效能優化整理
以下方式基於 @vue/cli
快速搭建的互動式專案腳手架
1. 路由懶載入
當打包構建應用時,JavaScript 包會變得非常大,影響頁面載入。如果我們能把不同路由對應的元件分割成不同的程式碼塊,然後當路由被訪問的時候才載入對應元件,這樣就更加高效了。
結合 Vue 的非同步元件和 Webpack 的程式碼分割功能,輕鬆實現路由元件的懶載入。
1 import Vue from 'vue' 2 import Router from 'vue-router' 3 import store from './store' 4 import Home from './views/Home.vue' 5 6 Vue.use(Router) 7 8 const router = new Router({ 9 routes: [ 10 { 11 path: '/', 12 name: 'home', 13 component: Home, 14 }, 15 { 16 path: '/make', 17 name: 'make', 18 component: () => import(/* webpackChunkName: "make" */ './views/Make.vue'), 19 } 20 ], 21 })
2. webpack動態匯入
將statically import(靜態匯入) 改為 dynamic import(動態匯入)進行程式碼拆分
1 import(/* webpackChunkName: "html2canvas" */ 'html2canvas').then( 2 ({ default: html2canvas }) => { 3 html2canvas(document.querySelector('.container'), { 4 scale: window.devicePixelRatio, 5 allowTaint: false, 6 useCORS: true, 7 }).then(canvas => { 8 console.log(canvas.toDataURL('image/jpeg', 0.9)) 9 }) 10 } 11 )
3. 預取/預載入模組(prefetch/preload module)
在宣告 import 時,使用下面這些內建指令,可以讓 webpack 輸出 "resource hint(資源提示)",來告知瀏覽器:
prefetch(預取):將來某些導航下可能需要的資源
preload(預載入):當前導航下可能需要資源
import(/* webpackPrefetch: true */ 'LoginModal'); import(/* webpackPreload: true */ 'ChartingLibrary');
這會生成 <link rel="prefetch" href="login-modal-chunk.js">
login-modal-chunk.js
檔案。
只要父 chunk 完成載入,webpack 就會新增 prefetch hint(預取提示)。
與 prefetch 指令相比,preload 指令有許多不同之處:
- preload chunk 會在父 chunk 載入時,以並行方式開始載入。prefetch chunk 會在父 chunk 載入結束後開始載入。
- preload chunk 具有中等優先順序,並立即下載。prefetch chunk 在瀏覽器閒置時下載。
- preload chunk 會在父 chunk 中立即請求,用於當下時刻。prefetch chunk 會用於未來的某個時刻。
- 瀏覽器支援程度不同。
vue預設開啟,可在vue.config.js中全域性禁用prefetch,再針對指定模組開啟。
chainWebpack: config => { config.plugins.delete('prefetch') },
4. 新增Gzip打包配置(compression-webpack-plugin)
yarn add compression-webpack-plugin -D
configureWebpack: config => { const CompressionPlugin = require('compression-webpack-plugin') config.plugins.push(new CompressionPlugin()) }
5. 新增頁面預渲染(prerender-spa-plugin)
在單頁應用程式中預呈現靜態HTML,可以極大的提高網頁訪問速度,而且配合一些meat外掛,基本可以滿足SEO需求。
預渲染基本上是在啟動無頭瀏覽器,載入應用程式的路由並將結果儲存到靜態HTML檔案中。然後將其與以前使用的任何靜態檔案服務解決方案一起使用,是無需更改程式碼或新增伺服器端渲染的解決方法。
不過,它僅適用於HTML5 history,因為每個預渲染的路由都會生成一個對應的HTML,在hash模式下使用只會有一個HTML。
yarn add prerender-spa-plugin -D
1 configureWebpack: config => { 2 const path = require('path') 3 const PrerenderSPAPlugin = require('prerender-spa-plugin') 4 config.plugins.push( 5 new PrerenderSPAPlugin({ 6 staticDir: path.join(__dirname, 'dist'), 7 routes: ['/'], 8 minify: { 9 collapseBooleanAttributes: true, 10 collapseWhitespace: true, 11 keepClosingSlash: true, 12 decodeEntities: true, 13 sortAttributes: true, 14 }, 15 renderer: new PrerenderSPAPlugin.PuppeteerRenderer({ 16 renderAfterDocumentEvent: 'render-event', 17 renderAfterTime: 5000, 18 // headless: false, 19 }), 20 }) 21 ) 22 } 23 24 new Vue({ 25 router, 26 store, 27 render: h => h(App), 28 mounted() { 29 // 預渲染 renderAfterDocumentEvent. 30 document.dispatchEvent(new Event('render-event')) 31 }, 32 }).$mount('#app')
prerender-spa-plugin 利用了 Puppeteer 的爬取頁面的功能。 Puppeteer 是一個 Chrome官方出品的 headlessChromenode 庫。它提供了一系列的 API, 可以在無 UI 的情況下呼叫 Chrome 的功能, 適用於爬蟲、自動化處理等各種場景。它很強大,所以很簡單就能將執行時的 HTML 打包到檔案中。原理是在 Webpack 構建階段的最後,在本地啟動一個 Puppeteer 的服務,訪問配置了預渲染的路由,然後將 Puppeteer 中渲染的頁面輸出到 HTML 檔案中,並建立路由對應的目錄。
6. 壓縮js,刪除console(terser-webpack-plugin)
yarn add terser-webpack-plugin -D
1 configureWebpack: config => { 2 const TerserPlugin = require('terser-webpack-plugin') 3 config.optimization.minimizer.push( 4 new TerserPlugin({ 5 extractComments: false, 6 terserOptions: { compress: { drop_console: true } }, 7 }) 8 ) 9 }
7. bundle 分析(webpack-bundle-analyzer)
將 bundle 內容展示為便捷的、互動式、可縮放的樹狀圖形式。
yarn add -D webpack-bundle-analyzer
1 configureWebpack: config => { 2 const BundleAnalyzerPlugin = require('webpack-bundle-analyzer') 3 .BundleAnalyzerPlugin 4 config.plugins.push(new BundleAnalyzerPlugin()) 5 }
8. WebP
WebP(發音 weppy),是一種支援有失真壓縮和無失真壓縮的圖片檔案格式,派生自影象編碼格式 VP8。根據 Google 的測試,無失真壓縮後的 WebP 比 PNG 檔案少了 45% 的檔案大小,即使這些 PNG 檔案經過其他壓縮工具壓縮之後,WebP 還是可以減少 28% 的檔案大小。
不過WebP目前在IOS上相容性不好,可以使用JavaScript進行檢測,對支援 WebP 的使用者輸出 WebP 圖片。
1 created() { 2 const htmlClass = document.documentElement.classList 3 this.checkWebpSupport() ? htmlClass.add('webps') : htmlClass.remove('webps') 4 } 5 6 checkWebpSupport() { 7 try { 8 return ( 9 document 10 .createElement('canvas') 11 .toDataURL('image/webp') 12 .indexOf('data:image/webp') === 0 13 ) 14 } catch (err) { 15 return false 16 } 17 }
記一次BUG:
在預設情況下,頁面載入完成執行 this.checkWebpSupport() && document.documentElement.classList.add('webps'),沒有問題。
但使用了prerender-spa-plugin進行預渲染後,因為執行預渲染的瀏覽器是支援WebP的,所有會直接在頁面中加上'webps'類,所以即使瀏覽器不支援WebP,不執行此方法也會有該類名。
9. 網頁效能優化測試(googlespeed)
進行網頁測試,根據優化建議針對性的修改,提高網頁載入速度。
https://www.googlespeed.cn/