跳至主要内容

如何優化 LCP!


網站核心指標三劍客

Google 定義出衡量網站使用者體驗最重要的三個指標 – LCP, FID, CLS


網站使用體驗三大核心指標 圖片參考網址


什麼是LCP

LCP 改為評斷整個頁面載入完成後,佔用使用者 viewport 面積最大的元件,可能是一整個文章區塊或是一張大的 Cover 圖片的載入時間,來作為網頁真正地載入完成的判定。

  • Largest Contentful Paint
  • 最大內容繪製
  • 網頁中最大元素的載入速度 ❤️

LCP範例 圖片參考網址


LCP 會偵測那些項目?

  • 圖片
  • svg 向量圖片
  • 影片 (預覽大圖)
  • 透過 url() 的 CSS 功能載入背景圖片的元素 包含文字的區塊級元素 (block-level elements) 或行內元素 (inline elements)

如何改進 LCP


  • 減少伺服器回應時間
  1. 針對主機進行優化 (效能太差或是頻寬不足)
  2. 讓第三方的資源提早載入
  3. 預加載圖片資源 (使用)
  • 加快資源載入的時間
  1. 最小化 css
  2. 使用較小的圖像 + WebP 壓縮/ 使用響應式圖片
  3. 延遲加載其他非 LCP 圖像
  4. 將文字檔案進行壓縮

減少伺服器回應時間
信息

針對主機進行優化 (效能太差或是頻寬不足) 讓第三方的資源提早載入


讓第三方的資源提早載入

  • 預先載入重要資源

有時候,在 css 或者 js 中聲明或者使用的一個重要資源 可能比你預期的要晚獲取,比如字體文件。 如果你明確的知道某個資源需要提高優先級,可以使用

<link rel="preload" as="script" href="script.js">
<link rel="preload" as="style" href="style.css">
<link rel="preload" as="image" href="img.png">
<link rel="preload" as="video" href="vid.webm" type="video/webm">
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

加快資源載入的時間

大部分網站的最大元素都是圖片,如果能加速這些圖片的加載,能有效改善 LCP

-> .png /.jpg -> .webp(已壓縮圖片)

如果 LCP 是圖像,渲染時間是圖像加載後立即繪製的時間。這意味著圖像的漸進加載無助於減少 LCP。

如果 LCP 是文本元素, 則考慮最早的字體加載。 所以字體可以更新,而 LCP 渲染時間保持不變。


信息

最小化 css 使用響應式圖片 將文字檔案進行壓縮


最小化 css 使用開發者工具中的 Coverage 能夠找到頁面未使用的 css。

步驟: chrome 開啟開發者模式 => 找到 Command menu https://developer.chrome.com/docs/devtools/command-menu/ => 會在下方看到 coverage => 在 source 裡面選取某個檔案,點擊下方 Coverage 的重新加載頁面的按鈕 => 就可以發現 code coverage 步驟參考網址

image alt

上圖中紅色表示未使用的代碼,綠色表示使用過的代碼。

這樣我們就可以在將文件傳送到用戶瀏覽器之前從文件中刪除未使用的代碼。 這有助於提高 Web 性能。


使用響應式圖片

  • 用 picture 的 scrset 取代 RWD 不同大小螢幕顯示的圖片
  • 使用 lazy load 延遲加載,藉由使用者剛好滑到圖片位置時,才顯示圖片的方式,達到節省資源、加速網頁速度的效果。 (推薦套件:react-lazy-load-image-component)

將文字檔案進行壓縮

可以用 gzip 壓縮檔案

詳細做法: https://stackoverflow.com/questions/56186336/how-to-compress-the-files-using-gzip-in-react-app


避免使用客戶端渲染(CSR)

信息

若必須使用 CSR ,建議優化 JavaScript ,避免渲染時使用太多資源 盡量在伺服器端完成頁面渲染,讓用戶端取得已渲染好的內容


如果你的 bundle 的 js 文件過大,會影響 LCP。如果不做優化,用戶可能長時間無法看到頁面,也無法交互,直到 js 全部下載執行完

  1. 使用 SSR
  2. (Code-Splitting)透過 Webpack 打包重複在各個 componets 的 modules
  3. (Code-Splitting)Code-Splitting
  4. Suspense SSR (React 18)

Code-Splitting

當專案成長到一定程度時,程式 bundle size 仍然會變得過於肥大, 導致 client side 的網頁載入時間變長,嚴重影響使用者體驗。

Code Splitting 就是為了要解決單一 JS Bundle 過於肥大的問題, 將原本單一的 bundle 切分成數個小 chunk,可以搭配平行載入, 或者是有需要時才載入某些特定的 chink, 又或是對一些不常變動的 chunk 個別做快取,來達到載入效能的優化。

Webpack 打包重複的 modules

在首次進入網頁的時候一樣會下載重複的 modules, 但是在前往其他頁面的時候,就不會重複的去 bundle.js 載相同的 modules.

舉例來說 react 和 react-dom 套件合計約為 130 KB,如果把它們獨立打包在每次 app 更新時就可以省下 130 KB 的傳輸。 對於不常更新的第三方套件來說,這種處理方式實作上簡單也能達到不錯的效果(第三⽅套件 / node_modules,不太會變動)。

(參考:webpack-bundle-analyzer可以幫助知道哪些套件是肥貓) https://github.com/webpack-contrib/webpack-bundle-analyzer

// .webpack.config
optimization: {
splitChunks: {
cacheGroups: {
// Split vendor code to its own chunk(s)
vendors: {
name: 'vendor',
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
chunks: 'all',
},
},
},
},
...

參考資料 1 參考資料 2

基礎 webpack 設定:https://gist.github.com/gaearon/ca6e803f5c604d37468b0091d9959269 https://github.com/brickspert/blog/issues/1

P.S. Next.js 把基本會用到的 Webpack 都包好了,如果要增加功能的話可以到 next.config.js 設定


在 webpack.config.js 中加入 resolve.alies,能將 Webpack 在任何的 package 引用路由到單個路由指定路徑。

舉個例子,如果在依賴包中發現了重复的 Lodash,下面的配置將把所有的 Lodash 導入渲染為./node_modules/lodash 中找到的 Lodash 實例。

alias: {
lodash: path.resolve(__dirname, 'node_modules/lodash'),
}

http://www.febeacon.com/webpack-plugins-docs-cn/routes/duplicate-package-checker-webpack-plugin.html


Code-Splitting

透過 Dynamic Imports 來延遲下載,可以先顯示某些頁面,然後元件可以再慢慢延遲加載,或者是要用到使用者點擊後,某段程式碼時才透過網路載入 JS bundle (比如:lodash 或是 moment)

import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(import('../components/hello'))

export default const Home = () =>
return (
<div>
<Header />
<DynamicComponent /> // 延遲下載
<p>HOME PAGE is here!</p>
</div>
)
------
useEffect(() => {
import(/* webpackChunkName: "lodash" */ 'lodash').then(({ default: _ }) => {
setHeader(_.join([str, 'code', 'spliting'], ' '));
});
}, [header, str]);

How to Reduce Next.js Bundle Size

https://medium.com/ne-digital/how-to-reduce-next-js-bundle-size-68f7ac70c375


Suspense SSR

過去 Server Side Rendering 頁面都會面臨到三個效能上的瓶頸

必須先拉取所有需要 api 資料才能開始組 html 必須 load 完所有的 js 才能 hydration 必須 hydration 所有的 Component 畫面才可以互動

而在 React 18 透過

的幫助,原本頁面可以分割成數個 Component,以 Component 作爲單位來進行 streaming Sever Side Rendering 跟 hydration,提升畫面呈現速度跟可互動速度 參考文章


參考資料