---
title: 如何優化LCP
tags: google speed
description: View the slide with "Slide Mode".
---
# 如何優化LCP!
---
## 網站核心指標三劍客
> Google 定義出衡量網站使用者體驗最重要的三個指標 – <font color="#f00">LCP, FID, CLS</font>
---

[圖片參考網址](https://www.darrenhuang.com/core-web-vitals-lcp-fid-cls.html)
---
## 什麼是LCP
LCP 改為評斷整個頁面載入完成後,佔用使用者 viewport 面積最大的元件,可能是一整個文章區塊或是一張大的 Cover 圖片的載入時間,來作為網頁真正地載入完成的判定。
- Largest Contentful Paint
- 最大內容繪製
- 網頁中最大元素的載入速度 :heart:
---

[圖片參考網址](https://web.dev/lcp/)
---
### LCP 會偵測那些項目?
- 圖片
- svg 向量圖片
- 影片 (預覽大圖)
- 透過 url() 的 CSS 功能載入背景圖片的元素
包含文字的區塊級元素 (block-level elements) 或行內元素 (inline elements)
---
### 如何改進 LCP
---
- 減少伺服器回應時間
1. 針對主機進行優化 (效能太差或是頻寬不足)
2. 讓第三方的資源提早載入
3. 預加載圖片資源 (使用<link rel="preload" />)
- 加快資源載入的時間
1. 最小化css
2. 使用較小的圖像 + WebP 壓縮/ 使用響應式圖片
3. 延遲加載其他非 LCP 圖像
4. 將文字檔案進行壓縮
---
##### 減少伺服器回應時間
:::info
針對主機進行優化 (效能太差或是頻寬不足)
讓第三方的資源提早載入
:::
---
**讓第三方的資源提早載入**
- 預先載入重要資源
有時候,在css或者js中聲明或者使用的一個重要資源
可能比你預期的要晚獲取,比如字體文件。
如果你明確的知道某個資源需要提高優先級,可以使用<link rel="preload">。
```javascript=
<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 渲染時間保持不變。
---
:::info
最小化css
使用響應式圖片
將文字檔案進行壓縮
:::
---
**最小化css**
使用開發者工具中的Coverage能夠找到頁面未使用的css。
步驟:
chrome開啟開發者模式
=> 找到 Command menu https://developer.chrome.com/docs/devtools/command-menu/
=> 會在下方看到coverage
=> 在source裡面選取某個檔案,點擊下方Coverage的重新加載頁面的按鈕
=> 就可以發現code coverage
[步驟參考網址](https://developer.chrome.com/docs/devtools/coverage)

上圖中紅色表示未使用的代碼,綠色表示使用過的代碼。
這樣我們就可以在將文件傳送到用戶瀏覽器之前從文件中刪除未使用的代碼。
這有助於提高 Web 性能。
---
**使用響應式圖片**
- 用 picture 的scrset取代RWD不同大小螢幕顯示的圖片
- 使用 lazy load 延遲加載,藉由使用者剛好滑到圖片位置時,才顯示圖片的方式,達到節省資源、加速網頁速度的效果。
(推薦套件:[react-lazy-load-image-component](https://www.npmjs.com/package/react-lazy-load-image-component))
---
**將文字檔案進行壓縮**
可以用gzip 壓縮檔案
詳細做法:
https://stackoverflow.com/questions/56186336/how-to-compress-the-files-using-gzip-in-react-app
---
#### 避免使用客戶端渲染(CSR)
:::info
若必須使用 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 的網頁載入時間變長,嚴重影響使用者體驗。
<font color="#0080FF">Code Splitting</font> 就是為了要解決單一 JS Bundle 過於肥大的問題,
將原本單一的 bundle 切分成數個小 chunk,可以搭配平行載入,
或者是有需要時才載入某些特定的 chink,
又或是對一些不常變動的 chunk 個別做快取,來達到載入效能的優化。
---
**Webpack打包重複的modules**
在首次進入網頁的時候一樣會下載重複的modules,
但是在前往其他頁面的時候,就不會重複的去 bundle.js載相同的modules.
舉例來說 react 和 react-dom 套件合計約為 130 KB,如果把它們獨立打包在每次 app 更新時就可以省下 130 KB 的傳輸。
對於不常更新的第三方套件來說,這種處理方式實作上簡單也能達到不錯的效果(第三⽅套件 / node_modules,不太會變動)。
(<font color="#f00">參考:[webpack-bundle-analyzer](https://github.com/vercel/next.js/tree/canary/examples/analyze-bundles)</font>可以幫助知道哪些套件是肥貓)
https://github.com/webpack-contrib/webpack-bundle-analyzer
```javascript=
// .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](https://papan01.com/archives/2019-12-20-code-splitting)
[參考資料2](https://www.ucamc.com/e-learning/javascript/357-webpack%E5%A6%82%E4%BD%95code-splitting%E6%8B%86%E5%88%86%E4%BB%A3%E7%A2%BCsplitchunks)
基礎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實例。
```javascript=
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)
```javascript=
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 透過 <Suspense /> 的幫助,原本頁面可以分割成數個 Component,以 Component 作爲單位來進行 streaming Sever Side Rendering 跟 hydration,提升畫面呈現速度跟可互動速度
[參考文章](https://jason-memo.dev/posts/react-18/)
---
### 參考網址
- https://web.dev/lcp/
- https://awoo.ai/zh-hant/blog/core-web-vitals-guide/
- https://segmentfault.com/a/1190000023558047
- https://itnext.io/hunting-for-unused-css-and-javascript-57e8d9bc2a67
- https://s.itho.me/modernweb/2020/Slides/d502.pdf
- https://medium.com/starbugs/%E4%BB%8A%E6%99%9A-%E6%88%91%E6%83%B3%E4%BE%86%E9%BB%9E-web-%E5%89%8D%E7%AB%AF%E6%95%88%E8%83%BD%E5%84%AA%E5%8C%96%E5%A4%A7%E8%A3%9C%E5%B8%96-e1a5805c1ca2
- https://github.com/brickspert/blog/issues/1
- https://gist.github.com/naoisegolden/17626c669aef6c53a64c642b3640d785
- https://thekevinwang.com/2021/03/15/reduce-first-load-js/
- https://medium.com/ne-digital/how-to-reduce-next-js-bundle-size-68f7ac70c375
- https://developers.google.com/web/updates/2018/08/web-performance-made-easy
- https://medium.com/tokopedia-engineering/getting-content-painted-under-2-seconds-on-the-mobile-web-7b3bbaca32cb
---
### Thank you! :sheep:
You can find me on
- GitHub :
https://github.com/kai4idps
- Linkedin me :
https://www.linkedin.com/in/kai-cc-a445221b5/
- Blog:
https://chekai7.github.io/c.c.k