Vue專案首屏開啟速度的優化
Vue專案首屏開啟速度的優化
msfew ☁️sny.is專案的情況
我最近幾個月一直在參與VioLegacy網站的建設. 前端的技術棧是Vue
. 說實話一開始參與的時候我是懵的, 因為沒怎麼用過Vue
, 平常大多是用React
, 後來我邊看邊學邊寫, 同時把樣式的部分所有的活都攬下來了, 這才到現在一直顯得很會寫Vue
.
這幾周大家一直在搞SEO的事情, 我加了幾個<meta>
標籤, 把SEO的評分算是完全拉滿了.
但是一跑Lighthouse
發現, SEO比較差的緣故很可能主要是首頁開啟的效能問題...
原本以為會很低, 沒想到會這麼低. 這麼低的原因有兩個點:
- 我們首頁有十幾張團隊成員的照片
- 我們所用的Vue框架, 是需要載入JS然後注入到HTML裡的
圖片載入導致的效能問題
網站的底部有每個團隊成員的照片, 程式碼結構類似這樣:
<div class="team-member"> <img class="round-image" src="@/images/VL-XXXXX.jpg" alt="VL-Edward.jpg" loading="lazy" /> <h4>XXXX XXX XXX</h4> <p>XXX XXXXX, 2020</p> <p>University of XXX, 2021</p> </div>
像這樣的部分還有十幾個, 而且由於都是自發上傳的照片, 有些相機拍攝的照片特別大. 這絕對是一個網站載入時的大隱患.
懶載入Lazy Loading
在img
標籤內, 加上loading="lazy"
, 這樣可以讓圖片只有在視窗內的時候才載入.
這樣能夠減少不需要的載入時間.
但是由於我們的程式碼中, 已經將圖片進行了分批展示, 所以優化效果不明顯
圖片大小壓縮
之前提到一些相機拍攝的照片很大, 所以我直接想到了用tinypng來壓縮圖片的大小.
png是無損的圖片格式, 可以無失真壓縮; jpg是有損的, 壓縮時可能會受到一些小破壞. 同時也可以手動修改圖片尺寸來減少圖片大小.
直接把十幾張圖片拖進去壓縮後下載替換即可. 這一步讓我們網站的圖片總大小減少了50%. 但是還是優化不明顯.
JS載入導致的效能問題
經過圖片資源大小的優化, 我們發現好像並沒有什麼用. 大頭依然是JS的載入.
Prerender?
Vue
的團隊成員做過一個預先渲染的外掛. 這個外掛配置很方便, 可以預先渲染一些檔案, 然後提高載入速度.
Prerender
與SSR
不同.
SSR
是使用者進入網址後, 把JS先送到伺服器渲染完HTML再給客戶端; Prerender
是構建時通過一個無頭瀏覽器去渲染出HTML.
SSR
會增加伺服器的壓力, 配置麻煩; Prerender
會很大拖慢構建的速度, 就連渲染一個網址也需要十秒左右的時間.
由於我們的需求只是渲染首頁, 所以我選擇了Prerender
.
經過簡單的配置, 生成了一個充滿內容的HTML檔案, 但是一執行, 怎麼還是需要載入那麼多JS. 於是我看了下生成的檔案, 發現裡面資料都是缺失的, 而且樣式也是. 問題大了.
因為Prerender
還有一個問題是不怎麼適用於動態資料很多的頁面... 如果想要把動態資料也帶上, 需要給根元件設定一個定時器, 讓它把資料拿完再渲染. 那麼可能就意味著, 開發時每次構建都得額外等個5秒等資料, 這就有點得不償失了, 甚至還不如咬咬牙上SSR
.
Code Splitting
之後我搜索了一些優化相關的內容, 發現可以通過修改router
來做到元件的按需載入.
我清晰地記得之前有看到過我們的router
, 因為它是長這樣的.
import Official from '../views/Official.vue'
import LogIn from '../views/LogIn.vue'
import SignUp from '../views/SignUp.vue'
import StudentSignUp from '../views/SignUp/StudentSignUp.vue'
import AlumniSignUp from '../views/SignUp/AlumniSignUp.vue'
import Verification from '../views/Verification.vue'
import Main from '../views/Main.vue'
import Home from '../views/Main/Home.vue'
import MyWishesDetail from '../views/Main/MyWishesDetail.vue'
import WishList from '../views/Main/WishList.vue'
import WishListSenior from '../views/Main/WishListSenior.vue'
import WishCompany from '../views/Main/WishCompany.vue'
import Opportunities from '../views/Main/Opportunities.vue'
import Messages from '../views/Main/Messages.vue'
import OppDetail from '../views/Main/OppDetail.vue'
import FAQ from '../views/Main/FAQ.vue'
import AccountSettings from '../views/Main/AccountSettings.vue'
import Dashboard from '../views/Main/Dashboard.vue'
import PostOppDetail from '../views/Main/PostOppDetail.vue'
import PostNewOpp from '../views/Main/PostNewOpp.vue'
import EditPostOpp from '../views/Main/EditPostOpp.vue'
import AdminPage from '../views/Main/AdminPage.vue'
import Report from '../views/Main/Report.vue'
我不會用router
, 但是我大受震撼. 這會導致一個很可怕的問題, 就是一開始載入到router
的時候, 會把所有的東西都import
過來, 形成的bundle會巨大.
為了優化這個情況, 可以這樣做:
const routes = [
{
path: '/',
name: 'Official',
component: () => import('../views/Official.vue')
}
......
把每個import
修改成這樣, 就可以做到通過一個回撥函式, 按需import外部檔案來載入, 大大減少Bundle的大小.
React的router
優化 也類似.
優化成果
通過我們強硬的手段, 網站效能從❤️提高到了 , 從37提高到了52, 提升了40%. 渲染時間從4.6s到2.6s, 減少了77%.
網站的效能大大提高, 使用者的互動也將大大提升.
課代表總結:
- 懶載入
img
標籤. - 用tinypng來壓縮圖片的大小.
- 通過修改
router
來懶載入元件. - 使用
Prerender
或者SSR
.