SKILL.md
readonlyread-only
name
web-performance-optimization
description
最佳化網站與網頁應用程式的效能,包括載入速度、Core Web Vitals、打包大小、快取策略及執行時期效能
網頁效能最佳化
概述
協助開發者最佳化網站與網頁應用程式的效能,以提升使用者體驗、SEO 排名與轉換率。此技能提供系統化的方法來測量、分析並改善載入速度、執行時期效能及 Core Web Vitals 指標。
何時使用此技能
- 當網站或應用程式載入緩慢時
- 當要針對 Core Web Vitals(LCP、FID、CLS)進行最佳化時
- 當要減少 JavaScript 打包大小時
- 當要改善可互動時間(TTI)時
- 當要最佳化圖片與資源時
- 當要實作快取策略時
- 當要除錯效能瓶頸時
- 當要準備效能稽核時
運作方式
步驟 1:測量當前效能
我會協助你建立基準指標:
- 執行 Lighthouse 稽核
- 測量 Core Web Vitals(LCP、FID、CLS)
- 檢查打包大小
- 分析網路瀑布圖
- 找出效能瓶頸
步驟 2:找出問題
分析效能問題:
- 大型 JavaScript 打包
- 未最佳化的圖片
- 阻擋渲染的資源
- 伺服器回應時間過慢
- 缺少快取標頭
- 版面位移
- 阻塞主執行緒的長時間任務
步驟 3:排定最佳化優先順序
專注於高影響力的改善:
- 關鍵渲染路徑最佳化
- 程式碼分割與延遲載入
- 圖片最佳化
- 快取策略
- 第三方腳本最佳化
步驟 4:實作最佳化
套用效能改善:
- 最佳化資源(圖片、字型、CSS、JS)
- 實作程式碼分割
- 加入快取標頭
- 延遲載入非關鍵資源
- 最佳化關鍵渲染路徑
步驟 5:驗證改善成果
測量變更的影響:
- 重新執行 Lighthouse 稽核
- 比較前後指標
- 監控真實使用者指標(RUM)
- 在不同裝置與網路上測試
範例
範例 1:最佳化 Core Web Vitals
## 效能稽核結果
### 當前指標(最佳化前)
- **LCP(最大內容繪製):** 4.2s ❌(應小於 2.5s)
- **FID(首次輸入延遲):** 180ms ❌(應小於 100ms)
- **CLS(累計版面位移):** 0.25 ❌(應小於 0.1)
- **Lighthouse 分數:** 62/100
### 發現的問題
1. **LCP 問題:** 主視覺圖片(2.5MB)載入緩慢
2. **FID 問題:** 大型 JavaScript 打包(850KB)阻塞主執行緒
3. **CLS 問題:** 未指定尺寸的圖片導致版面位移
### 最佳化計畫
#### 修正 LCP(最大內容繪製)
**問題:** 主視覺圖片為 2.5MB 且載入緩慢
**解決方案:**
\`\`\`html
<!-- 最佳化前:未最佳化的圖片 -->
<img src="/hero.jpg" alt="Hero">
<!-- 最佳化後:使用現代格式 -->
<picture>
<source srcset="/hero.avif" type="image/avif">
<source srcset="/hero.webp" type="image/webp">
<img
src="/hero.jpg"
alt="Hero"
width="1200"
height="600"
loading="eager"
fetchpriority="high"
>
</picture>
\`\`\`
**額外最佳化:**
- 壓縮圖片至小於 200KB
- 使用 CDN 加速傳遞
- 預載主視覺圖片:`<link rel="preload" as="image" href="/hero.avif">`
#### 修正 FID(首次輸入延遲)
**問題:** 850KB JavaScript 打包阻塞主執行緒
**解決方案:**
1. **程式碼分割:**
\`\`\`javascript
// 最佳化前:所有內容在同一個打包中
import { HeavyComponent } from './HeavyComponent';
import { Analytics } from './analytics';
import { ChatWidget } from './chat';
// 最佳化後:延遲載入非關鍵程式碼
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const ChatWidget = lazy(() => import('./chat'));
// 頁面可互動後再載入分析工具
if (typeof window !== 'undefined') {
window.addEventListener('load', () => {
import('./analytics').then(({ Analytics }) => {
Analytics.init();
});
});
}
\`\`\`
2. **移除未使用的相依套件:**
\`\`\`bash
# 分析打包
npx webpack-bundle-analyzer
# 移除未使用的套件
npm uninstall moment # 改用 date-fns(較小)
npm install date-fns
\`\`\`
3. **延遲非關鍵腳本:**
\`\`\`html
<!-- 最佳化前:阻擋渲染 -->
<script src="/analytics.js"></script>
<!-- 最佳化後:延遲執行 -->
<script src="/analytics.js" defer></script>
\`\`\`
#### 修正 CLS(累計版面位移)
**問題:** 未指定尺寸的圖片導致版面位移
**解決方案:**
\`\`\`html
<!-- 最佳化前:無尺寸 -->
<img src="/product.jpg" alt="Product">
<!-- 最佳化後:指定尺寸 -->
<img
src="/product.jpg"
alt="Product"
width="400"
height="300"
style="aspect-ratio: 4/3;"
>
\`\`\`
**針對動態內容:**
\`\`\`css
/* 為後續載入的內容保留空間 */
.skeleton-loader {
min-height: 200px;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: loading 1.5s infinite;
}
@keyframes loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
\`\`\`
### 最佳化後結果
- **LCP:** 1.8s ✅(改善 57%)
- **FID:** 45ms ✅(改善 75%)
- **CLS:** 0.05 ✅(改善 80%)
- **Lighthouse 分數:** 94/100 ✅
範例 2:減少 JavaScript 打包大小
## 打包大小最佳化
### 當前狀態
- **總打包大小:** 850KB(gzip 後:280KB)
- **主要打包:** 650KB
- **第三方打包:** 200KB
- **載入時間(3G):** 8.2s
### 分析
\`\`\`bash
# 分析打包組成
npx webpack-bundle-analyzer dist/stats.json
\`\`\`
**發現:**
1. Moment.js:67KB(可用 date-fns 取代:12KB)
2. Lodash:72KB(使用整個函式庫,但只需要 5 個函式)
3. 未使用的程式碼:約 150KB 的無效程式碼
4. 無程式碼分割:所有內容在同一個打包中
### 最佳化步驟
#### 1. 取代重量級相依套件
\`\`\`bash
# 移除 moment.js(67KB)→ 使用 date-fns(12KB)
npm uninstall moment
npm install date-fns
# 最佳化前
import moment from 'moment';
const formatted = moment(date).format('YYYY-MM-DD');
# 最佳化後
import { format } from 'date-fns';
const formatted = format(date, 'yyyy-MM-dd');
\`\`\`
**節省:** 55KB
#### 2. 選擇性使用 Lodash
\`\`\`javascript
// 最佳化前:匯入整個函式庫(72KB)
import _ from 'lodash';
const unique = _.uniq(array);
// 最佳化後:只匯入需要的部分(5KB)
import uniq from 'lodash/uniq';
const unique = uniq(array);
// 或使用原生方法
const unique = [...new Set(array)];
\`\`\`
**節省:** 67KB
#### 3. 實作程式碼分割
\`\`\`javascript
// Next.js 範例
import dynamic from 'next/dynamic';
// 延遲載入重量級元件
const Chart = dynamic(() => import('./Chart'), {
loading: () => <div>載入圖表中...</div>,
ssr: false
});
const AdminPanel = dynamic(() => import('./AdminPanel'), {
loading: () => <div>載入中...</div>
});
// 基於路由的程式碼分割(Next.js 自動處理)
// pages/admin.js - 僅在造訪 /admin 時載入
// pages/dashboard.js - 僅在造訪 /dashboard 時載入
\`\`\`
#### 4. 移除無效程式碼
\`\`\`javascript
// 在 webpack.config.js 中啟用 tree shaking
module.exports = {
mode: 'production',
optimization: {
usedExports: true,
sideEffects: false
}
};
// 在 package.json 中
{
"sideEffects": false
}
\`\`\`
#### 5. 最佳化第三方腳本
\`\`\`html
<!-- 最佳化前:立即載入 -->
<script src="https://analytics.com/script.js"></script>
<!-- 最佳化後:頁面可互動後再載入 -->
<script>
window.addEventListener('load', () => {
const script = document.createElement('script');
script.src = 'https://analytics.com/script.js';
script.async = true;
document.body.appendChild(script);
});
</script>
\`\`\`
### 結果
- **總打包大小:** 380KB ✅(減少 55%)
- **主要打包:** 180KB ✅
- **第三方打包:** 80KB ✅
- **載入時間(3G):** 3.1s ✅(改善 62%)
範例 3:圖片最佳化策略
## 圖片最佳化
### 當前問題
- 15 張圖片總計 12MB
- 未使用現代格式(WebP、AVIF)
- 無響應式圖片
- 無延遲載入
### 最佳化策略
#### 1. 轉換為現代格式
\`\`\`bash
# 安裝圖片最佳化工具
npm install sharp
# 轉換腳本(optimize-images.js)
const sharp = require('sharp');
const fs = require('fs');
const path = require('path');
async function optimizeImage(inputPath, outputDir) {
const filename = path.basename(inputPath, path.extname(inputPath));
// 產生 WebP
await sharp(inputPath)
.webp({ quality: 80 })
.toFile(path.join(outputDir, \`\${filename}.webp\`));
// 產生 AVIF(最佳壓縮)
await sharp(inputPath)
.avif({ quality: 70 })
.toFile(path.join(outputDir, \`\${filename}.avif\`));
// 產生最佳化的 JPEG 備用
await sharp(inputPath)
.jpeg({ quality: 80, progressive: true })
.toFile(path.join(outputDir, \`\${filename}.jpg\`));
}
// 處理所有圖片
const images = fs.readdirSync('./images');
images.forEach(img => {
optimizeImage(\`./images/\${img}\`, './images/optimized');
});
\`\`\`
#### 2. 實作響應式圖片
\`\`\`html
<!-- 使用現代格式的響應式圖片 -->
<picture>
<!-- 支援 AVIF 的瀏覽器使用(最佳壓縮) -->
<source
srcset="
/images/hero-400.avif 400w,
/images/hero-800.avif 800w,
/images/hero-1200.avif 1200w
"
type="image/avif"
sizes="(max-width: 768px) 100vw, 50vw"
>
<!-- 支援 WebP 的瀏覽器使用 -->
<source
srcset="
/images/hero-400.webp 400w,
/images/hero-800.webp 800w,
/images/hero-1200.webp 1200w
"
type="image/webp"
sizes="(max-width: 768px) 100vw, 50vw"
>
<!-- JPEG 備用 -->
<img
src="/images/hero-800.jpg"
srcset="
/images/hero-400.jpg 400w,
/images/hero-800.jpg 800w,
/images/hero-1200.jpg 1200w
"
sizes="(max-width: 768px) 100vw, 50vw"
alt="Hero image"
width="1200"
height="600"
loading="lazy"
>
</picture>
\`\`\`
#### 3. 延遲載入
\`\`\`html
<!-- 原生延遲載入 -->
<img
src="/image.jpg"
alt="Description"
loading="lazy"
width="800"
height="600"
>
<!-- 首屏圖片使用立即載入 -->
<img
src="/hero.jpg"
alt="Hero"
loading="eager"
fetchpriority="high"
>
\`\`\`
#### 4. Next.js Image 元件
\`\`\`javascript
import Image from 'next/image';
// 自動最佳化
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority // 用於首屏圖片
quality={80}
/>
// 延遲載入
<Image
src="/product.jpg"
alt="Product"
width={400}
height={300}
loading="lazy"
/>
\`\`\`
### 結果
| 指標 | 最佳化前 | 最佳化後 | 改善幅度 |
|--------|--------|-------|-------------|
| 總圖片大小 | 12MB | 1.8MB | 減少 85% |
| LCP | 4.5s | 1.6s | 加快 64% |
| 頁面載入(3G) | 18s | 4.2s | 加快 77% |
最佳實務
✅ 建議這樣做
- 先測量 - 最佳化前務必建立基準指標
- 使用 Lighthouse - 定期執行稽核以追蹤進度
- 最佳化圖片 - 使用現代格式(WebP、AVIF)與響應式圖片
- 程式碼分割 - 將大型打包拆成較小區塊
- 延遲載入 - 延後非關鍵資源的載入
- 積極快取 - 為靜態資源設定適當的快取標頭
- 最小化主執行緒工作 - 將 JavaScript 執行時間控制在 50ms 區塊內
- 預載關鍵資源 - 使用
<link rel="preload">預載關鍵資源 - 使用 CDN - 從 CDN 提供靜態資源以加速傳遞
- 監控真實使用者 - 追蹤真實使用者的 Core Web Vitals
❌ 避免這樣做
- 不要盲目最佳化 - 先測量,再最佳化
- 不要忽略行動裝置 - 在真實行動裝置與慢速網路上測試
- 不要阻擋渲染 - 避免使用阻擋渲染的 CSS 與 JavaScript
- 不要一次載入所有內容 - 延遲載入非關鍵資源
- 不要忘記指定尺寸 - 務必指定圖片的寬度與高度
- 不要使用同步腳本 - 使用 async 或 defer 屬性
- 不要忽略第三方腳本 - 它們經常造成效能問題
- 不要跳過壓縮 - 務必壓縮與最小化資源
常見陷阱
問題:針對桌面最佳化,但在行動裝置上緩慢
症狀: 桌面 Lighthouse 分數高,行動裝置分數低
解決方案:
- 在真實行動裝置上測試
- 使用 Chrome DevTools 行動裝置節流
- 針對 3G/4G 網路最佳化
- 減少 JavaScript 執行時間
# 使用節流測試
lighthouse https://yoursite.com --throttling.cpuSlowdownMultiplier=4
問題:大型 JavaScript 打包
症狀: 可互動時間(TTI)長,FID 高
解決方案:
- 使用 webpack-bundle-analyzer 分析打包
- 移除未使用的相依套件
- 實作程式碼分割
- 延遲載入非關鍵程式碼
# 分析打包
npx webpack-bundle-analyzer dist/stats.json
問題:圖片造成版面位移
症狀: CLS 分數高,內容跳動
解決方案:
- 務必指定寬度與高度
- 使用 aspect-ratio CSS 屬性
- 使用骨架載入器保留空間
img {
aspect-ratio: 16 / 9;
width: 100%;
height: auto;
}
問題:伺服器回應時間過慢
症狀: TTFB(第一個位元組時間)高
解決方案:
- 實作伺服器端快取
- 使用 CDN 提供靜態資源
- 最佳化資料庫查詢
- 考慮靜態網站產生(SSG)
// Next.js:靜態產生
export async function getStaticProps() {
const data = await fetchData();
return {
props: { data },
revalidate: 60 // 每 60 秒重新產生
};
}
效能檢查清單
圖片
- [ ] 轉換為現代格式(WebP、AVIF)
- [ ] 實作響應式圖片
- [ ] 加入延遲載入
- [ ] 指定尺寸(寬度/高度)
- [ ] 壓縮圖片(每張小於 200KB)
- [ ] 使用 CDN 傳遞
JavaScript
- [ ] 打包大小小於 200KB(gzip 後)
- [ ] 實作程式碼分割
- [ ] 延遲載入非關鍵程式碼
- [ ] 移除未使用的相依套件
- [ ] 最小化與壓縮
- [ ] 對腳本使用 async/defer
CSS
- [ ] 內嵌關鍵 CSS
- [ ] 延遲非關鍵 CSS
- [ ] 移除未使用的 CSS
- [ ] 最小化 CSS 檔案
- [ ] 使用 CSS containment
快取
- [ ] 為靜態資源設定快取標頭
- [ ] 實作 Service Worker
- [ ] 使用 CDN 快取
- [ ] 快取 API 回應
- [ ] 對靜態資源進行版本管理
Core Web Vitals
- [ ] LCP < 2.5s
- [ ] FID < 100ms
- [ ] CLS < 0.1
- [ ] TTFB < 600ms
- [ ] TTI < 3.8s
效能工具
測量工具
- Lighthouse - 全面效能稽核
- WebPageTest - 詳細瀑布圖分析
- Chrome DevTools - 效能剖析
- PageSpeed Insights - 真實使用者指標
- Web Vitals Extension - 監控 Core Web Vitals
分析工具
- webpack-bundle-analyzer - 視覺化打包組成
- source-map-explorer - 分析打包大小
- Bundlephobia - 安裝前檢查套件大小
- ImageOptim - 圖片壓縮工具
監控工具
- Google Analytics - 追蹤 Core Web Vitals
- Sentry - 效能監控
- New Relic - 應用程式效能監控
- Datadog - 真實使用者監控
相關技能
@react-best-practices- React 效能模式@frontend-dev-guidelines- 前端開發標準@systematic-debugging- 除錯效能問題@senior-architect- 效能架構
額外資源
專業提示: 優先專注於 Core Web Vitals(LCP、FID、CLS)——它們對使用者體驗與 SEO 排名影響最大!
限制
- 僅在任務明確符合上述範圍時使用此技能。
- 請勿將輸出視為環境特定驗證、測試或專家審查的替代方案。
- 若缺少必要的輸入、權限、安全邊界或成功標準,請停止並要求釐清。






