/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
前端构建性能基线建立:Lighthouse与WebVitals指标自动化监控

在前端工程的日常迭代中,我们经常会遇到这样的尴尬局面:
- 团队在上个月花费两周时间做了一场专项性能攻坚,把首屏加载时间优化到了 0.9 秒,Lighthouse 跑分达到了 95 分;
- 然而仅仅过了两个迭代,随着新业务组件、未经压缩的配图以及第三方统计埋点 SDK 的陆续引入,首屏时间又悄无声息地滑落回 3.5 秒。
性能优化最怕的是“一锤子买卖”。没有自动化监控与指标防劣化机制的性能优化,就像是在沙滩上建城堡。
为了将优秀的加载性能固化为团队的研发红线,我们需要建立一套基于 Google Core Web Vitals 的量化性能基线(Performance Baseline)与 CI/CD 自动化卡点监控系统。
Core Web Vitals 核心三大指标与阈值定义
Google 官方定义的核心用户体验三大指标:
┌─────────────────────────────────────────────────────────────┐
│ Core Web Vitals 黄金标准 │
├──────────────────────────────┬──────────────────────────────┤
│ 1. LCP (最大内容绘制) │ 优秀: ≤ 2.5s | 较差: > 4.0s│
│ – 用户感知首屏主内容呈现速度│ │
├──────────────────────────────┼──────────────────────────────┤
│ 2. INP (交互到下次绘制延迟) │ 优秀: ≤ 200ms | 较差: > 500ms│
│ – 用户点击/按键后的交互响应性│ │
├──────────────────────────────┼──────────────────────────────┤
│ 3. CLS (累积布局偏移) │ 优秀: ≤ 0.1 | 较差: > 0.25 │
│ – 页面加载过程中元素的意外跳动│ │
└──────────────────────────────┴──────────────────────────────┘
步骤一:客户端实时性能埋点与上报(web-vitals)
利用 Google 官方的 web-vitals 极轻量库(仅约 1KB),在真实用户浏览器端捕获实时的性能数据并异步回传:
// src/lib/vitalsMonitor.ts
import { onCLS, onINP, onLCP, onFCP, onTTFB, Metric } from 'web-vitals';
function sendToAnalytics(metric: Metric) {
const body = JSON.stringify({
name: metric.name,
value: metric.value,
rating: metric.rating, // 'good' | 'needs-improvement' | 'poor'
delta: metric.delta,
id: metric.id,
path: window.location.pathname,
timestamp: Date.now()
});
// 使用 sendBeacon 保证在页面卸载时也能可靠发出上报请求,绝不阻塞主线程
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/telemetry/vitals', body);
} else {
fetch('/api/telemetry/vitals', { body, method: 'POST', keepalive: true });
}
}
export function initWebVitalsTracker() {
onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);
onFCP(sendToAnalytics);
onTTFB(sendToAnalytics);
}
步骤二:CI/CD 自动化性能门禁(Lighthouse CI)
为了防止劣化代码被合并到主干分支,在 GitHub Actions 中集成 Lighthouse CI (LHCI) 作为 PR 必过卡点。
1. 项目根目录下配置 .lighthouserc.json:
{
"ci": {
"collect": {
"numberOfRuns": 3,
"startServerCommand": "pnpm run preview",
"url": ["http://localhost:4173/"]
},
"assert": {
"assertions": {
"categories:performance": ["error", { "minScore": 0.90 }],
"first-contentful-paint": ["error", { "maxNumericValue": 1500 }],
"largest-contentful-paint": ["error", { "maxNumericValue": 2500 }],
"cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }]
}
},
"upload": {
"target": "temporary-public-storage"
}
}
}
2. 在 GitHub Actions 流水线中激活 LHCI:
# .github/workflows/lighthouse-ci.yml
name: Performance Guard
on:
pull_request:
branches: [main]
jobs:
lhci:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v4
– uses: pnpm/action-setup@v3
with:
version: 9
– uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
– name: Build & Run Lighthouse CI
run: |
pnpm install –frozen-lockfile
pnpm run build
npm install -g @lhci/cli
lhci autorun
如果某个 PR 引入了未压缩的巨大图片或重型依赖,导致 Lighthouse 性能跑分低于 90 分,GitHub Actions 流水线会直接标红挂起,禁止合并,并在 PR 评论中附带详细的性能诊断明细。



