mcpField
W
WebPerf Snippets

WebPerf Snippets

本地服务
webperf-snippets.net开发工具1.5k今天更新

关于 WebPerf Snippets

WebPerf Snippets 是通过 Playwright 在无头 Chromium 中运行精选性能片段的命令行工具。它面向需要诊断 Core Web Vitals 及其他页面性能问题的开发者,也可自动执行审计并在 CI 中设置性能预算。

主要功能

  1. 01在无头 Chromium 中运行精选片段
  2. 02Core Web Vitals 与加载工作流
  3. 03交互与结构审计
  4. 04JSON 和 Markdown 报告
  5. 05多次运行与性能预算
  6. 06CPU 与网络限速

适用场景

  1. 01在 CI 中诊断 LCP 回归
  2. 02按性能预算拦截拉取请求
  3. 03审计交互延迟与布局偏移
  4. 04将合成测量与 CrUX 实测数据对照

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"nucliweb-webperf-snippets": {
"command": "npx",
"args": [
"-y",
"webperf-snippets"
],
"env": {
"CRUX_API_KEY": "<CRUX_API_KEY>"
}
}
}
}
启动命令npx -y webperf-snippets
需要配置的环境变量
CRUX_API_KEY密钥Chrome UX Report API key for the field data of get_crux; the other tools work without it

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmwebperf-snippets1.6.0

工具

8

收录的工具列表 · 更新于 1 天前

参数类型必填说明
categoryenum否仅列出此类别的片段CoreWebVitals | Loading | Interaction | Media | Resources

详细介绍

webperf-snippets CLI

通过 Playwright 在无头模式下运行精选的 WebPerf Snippets。诊断 Lighthouse 未能呈现的 Core Web Vitals,并根据实际性能预算拦截 CI。

webperf-snippets-CLI

状态: v0.4。提供 Core Web Vitals、加载、交互和结构审计工作流,并可按名称运行集合中的每个代码片段。请参阅路线图。

为什么使用

Lighthouse 会给出评分。DevTools 代码片段则能给出诊断,例如 TTFB / 资源加载延迟 / 元素渲染延迟的细分部分、LoAF 脚本归因,以及阻塞渲染的资源。此 CLI 会在无头浏览器中运行相同的精选代码片段,让你能够:

  • 在 CI 中诊断 LCP 回退,无需复制粘贴到 DevTools。
  • 根据实际性能预算拦截拉取请求。
  • 自动运行你已经在手动执行的代码片段。

安装

Playwright 是对等依赖项。请安装 Playwright 和此 CLI,并安装 chromium 浏览器:

npm install --save-dev webperf-snippets playwright
npx playwright install chromium

用法

npx webperf-snippets <url> [options]
示例

运行默认的 Core Web Vitals 工作流(LCP + CLS;若 LCP > 2.5s,则额外运行 LCP-Subparts):

npx webperf-snippets https://example.com

加载审计(11 个步骤:TTFB、FCP、阻塞渲染的资源、脚本、资源计时、第三方影响、字体、缓存;请参阅 CLI 页面中的列表):

npx webperf-snippets https://example.com --workflow loading

用于区分第一方和第三方资源的步骤,会将页面的根域名及其子域名(对于 example.com,如 cdn.example.com)视为第一方。如果网站从其他域名(例如 CDN)提供自己的资源,请使用 --own-domains 指定域名,可用逗号分隔,也可重复指定:

npx webperf-snippets https://example.com --workflow loading --own-domains cdn.example.net,static.example.org

每个域名都按其根域名计算,因此 cdn.example.net 会将 example.net 下的所有主机都视为第一方。CLI 会在每个代码片段的 OWN_DOMAINS 常量中写入域名列表,与在控制台中编辑代码片段顶部内容时使用的常量相同。域名为空或包含空格时,CLI 会以代码 2 退出。

用于 CI 的结构检查(22 项检查:阻塞渲染的资源、压缩、字体、图像、提示、DOM 大小等;请参阅 CLI 页面中的列表):

npx webperf-snippets https://example.com --workflow audit

用于 PR 评论的 Markdown 输出:

npx webperf-snippets https://example.com --markdown

JSON 输出(用于传递给 jq 或 CI):

npx webperf-snippets https://example.com --json

JSON 输出会在 conditions 中记录页面的测量方式,以便后续运行判断测量方式是否相同:视口、工作流(或使用 --snippet 时的代码片段路径)、等待时间以及 CLI 版本。

"conditions": { "viewport": "mobile", "workflow": "core-web-vitals", "waitMs": 3000, "cliVersion": "1.6.0" }

单个代码片段:

npx webperf-snippets https://example.com --snippet LCP-Subparts

使用交互脚本进行合成 INP 测量:

npx webperf-snippets https://example.com --snippet INP --interact-script interactions.json
npx webperf-snippets https://example.com --snippet Interaction/Interactions --interact-script interactions.json

交互代码片段(Interactions、Input-Latency-Breakdown、LongTask、Forced-Synchronous-Layout 等)会在第一步之前安装,并在最后一步之后读取,因此其结果会包含这些步骤造成的影响。

CLI 会等待浏览器报告最后一次交互的计时信息,然后才读取代码片段。如果脚本在点击后立即结束,页面会在点击所触发的后续操作(例如请求或动画)发生之前就被读取;如果需要测量这些操作,请以 wait 步骤结束脚本。

交互审计(长任务、长动画帧、滚动、布局偏移、强制布局、交互延迟)。CLI 会滚动页面,或运行你的 --interact-script;如果脚本中没有点击操作,则会跳过需要点击的步骤:

npx webperf-snippets https://example.com --workflow interaction

使用 Playwright 存储状态(Cookie 和 localStorage)访问需要登录的页面:

# Step 1: sign in once and save the session
npx playwright codegen --save-storage=auth.json https://example.com/login

# Step 2: measure an authenticated page
npx webperf-snippets https://example.com/dashboard --storage-state auth.json

该文件包含有效的会话 Cookie。请勿将其纳入版本控制(将其添加到 .gitignore),并在 CI 中运行时使用临时账号。如果路径不存在,CLI 会以代码 2 退出。

对于需要从每个请求中读取令牌的访问代理(例如 Cloudflare Access 的服务令牌),请使用 --header 将令牌作为请求标头传入,每个标头指定一次:

npx webperf-snippets https://review.example.com \
  --header "CF-Access-Client-Id: $CF_ACCESS_CLIENT_ID" \
  --header "CF-Access-Client-Secret: $CF_ACCESS_CLIENT_SECRET"

这些标头会随每个请求发送到 URL 所属的源,绝不会发送到其他源,因此第三方不会收到令牌,其跨源请求也无需进行 CORS 预检。浏览器会暂停发往该源的每个请求以添加这些标头,这会使计时增加几毫秒;如果代理接受会话 Cookie,使用 --storage-state 测量就不会产生这项开销。没有名称或冒号的标头会以代码 2 退出。像上面那样从环境变量读取这些值,避免它们出现在 shell 历史记录中。

将测量值与 CrUX 现场数据进行比较(即真实用户在第 75 百分位的体验):

CRUX_API_KEY=your-key npx webperf-snippets https://example.com
Field data (CrUX p75, mobile)
  🟡 LCP    2.80s      needs-improvement    (synthetic: 2.10s)
  🟢 CLS    0.0800     good                 (synthetic: 0.0500)
  🟡 INP    220ms      needs-improvement    (synthetic: n/a)

获取 Chrome UX Report API 的密钥,并通过 --crux-key 或 CRUX_API_KEY 环境变量传入;建议使用环境变量,因为标志会出现在 shell 历史记录和 CI 日志中。该部分会显示在人类可读和 Markdown 输出中,并显示在 --json 输出的 crux 下。

  • 数据群体由 --viewport 决定:desktop 使用桌面数据,mobile 和 tablet 使用手机数据。标题会注明使用的是哪一种。
  • 如果页面本身没有数据,CLI 会改为查询源,并将该部分标记为 origin-level,以免与页面级数据混淆。如果源也没有数据,输出会显示 Field data: not available。
  • CrUX 出错(配额、网络问题或 10 秒内没有响应)时,只会跳过该部分,不会改变退出代码,也绝不会打印密钥。
  • 除非运行交互脚本,否则 INP 的合成值会显示为 n/a。

运行结束后,使用 --report-to 将结果发送到某个端点:

npx webperf-snippets https://example.com --workflow audit \
  --report-to https://reports.example.com/api/report \
  --api-key $REPORT_API_KEY

如果不使用 --report-to,CLI 不会进行任何外部调用。使用该参数时,所有代码片段运行完毕后,结果会以 JSON 格式通过 POST 发送:

{
  "url": "https://example.com",
  "workflow": "audit",
  "timestamp": "2026-05-06T10:00:00.000Z",
  "navMs": 1240,
  "results": [],
  "meta": { "viewport": "mobile", "waitMs": 3000, "cli_version": "1.6.0" }
}

运行 --snippet 时,workflow 为 null,并且 snippet 字段会包含名称。使用 --cpu 或 --network 时,meta 会在 throttling 中包含运行条件;使用 --runs 时,runs 会包含运行摘要。results 与 --json 输出中的列表相同,因此可能包含 URL 和测量页面的详情;请仅将其发送到你信任的端点。

  • URL 必须使用 https。只有 localhost 可以使用 http,因此密钥绝不会以明文发送。
  • --api-key 会作为 Authorization: Bearer <key> 发送。建议使用 PERF_REVIEWS_API_KEY 环境变量,因为标志会出现在 shell 历史记录和 CI 日志中。密钥绝不会被打印。
  • 退出代码不会取决于报告。POST 失败(错误状态、端点无法访问或 5 秒内没有响应)时会打印警告,退出代码仍由预算和代码片段决定。如果端点响应 { "ok": false, "regressions": [...] },回归项会作为警告打印,同样不会改变退出代码。

使用 --cpu 和 --network,在较慢设备和网络的条件下进行测量。如果不使用这些参数,CLI 会以当前机器的速度运行;笔记本电脑或 CI 运行器的速度通常比大多数手机快:

npx webperf-snippets https://example.com --cpu 4 --network slow-4g

--cpu <factor> 会按指定倍数降低主线程速度。--network 使用 DevTools 中的预设,数值相同:

预设下载上传延迟
fast-4g8.1 Mbps1.35 Mbps165 ms
slow-4g1.44 Mbps675 kbps562.5 ms
3g400 kbps400 kbps2000 ms

Chrome 会将延迟施加到每个响应的正文,而不是标头上。从 responseStart 读取的值(例如 TTFB 及其子项)不包含该延迟;每个资源的下载、FCP、LCP 和加载事件则包含。报告会在标题下方注明运行条件,JSON 输出则会在 throttling 中包含这些条件,例如 { "cpu": 4, "network": "slow-4g" }。CPU 因子小于 1 或使用未知预设时,会以代码 2 退出。 一次页面加载就是一个样本,实验室数据会因加载次数不同而变化。--runs <n> 会依次测量页面 1 到 9 次,并像 WebPageTest 一样报告中位数运行结果:每项结果都来自该次运行,因此彼此一致(LCP 的子部分之和等于其 LCP):

npx webperf-snippets https://example.com --runs 5 --budget-lcp 2500

中位数运行结果是 LCP 处于中位数的那次运行。不含 LCP 的工作流会使用其测量的 FCP、TTFB 和导航时间中的第一项,而 --median-by <metric> 可以选择其他指标(LCP、FCP、TTFB、CLS、INP 或 navMs)。运行次数为偶数时,会取中间两次运行中较低的那次,因此报告始终对应实际发生过的一次运行。报告会添加各项指标在所有运行中的中位数、最小值和最大值,JSON 输出则会在 runs 中包含这些数据:

"runs": {
  "count": 5,
  "failed": 0,
  "medianRun": 3,
  "medianBy": "LCP",
  "summary": {
    "LCP": { "median": 2140, "min": 1980, "max": 2610, "values": [2610, 2010, 2140, 1980, 2290], "unit": "ms" }
  }
}

medianRun 从 1 开始计数,values 保留各次运行的顺序。预算会比较各项指标的中位数,而不是某一次运行。失败的运行(例如未完成的导航)会计入 failed,并从中位数计算中排除;若所有运行都失败,命令会以代码 1 退出。每次运行开始时都会将其报告写入 stderr,因此 stdout 只包含报告。无效的次数或指标会导致命令以代码 2 退出。

使用 --matrix <file>,即可在一条命令中测量多个页面、多个设备和多个变体。文件中列出这些项目,CLI 会在每台设备和每个变体上测量每个 URL,每种组合依次加载 runs 次:

{
  "urls": {
    "home": "https://example.com/",
    "article": "https://example.com/news/some-article"
  },
  "devices": {
    "mobile": { "viewport": "mobile", "cpu": 4, "network": "slow-4g" },
    "high-end": { "viewport": "mobile", "cpu": 1, "network": { "downloadKbps": 50000, "uploadKbps": 10000, "latencyMs": 20 } },
    "desktop": { "viewport": "desktop" }
  },
  "variants": {
    "no-consent": {},
    "consent": { "storageState": "states/consent.json" }
  },
  "runs": 3
}
npx webperf-snippets --matrix matrix.json --budget-lcp 2500
  • urls:名称和 URL。也可以使用 URL 数组,并以每个 URL 的路径和查询参数(/、/news/)为其命名;如果 URL 包含多个主机,还会附上主机名。
  • devices:viewport 预设、cpu 倍数和 network。网络可以是预设值(fast-4g、slow-4g、3g),也可以指定 DevTools 未提供预设的网络(如 5G),并以千比特每秒和毫秒为单位设置参数。视口预设数组(["mobile", "desktop"])可简写为不启用限速的设备。如果没有 devices,矩阵会像 Lighthouse 一样,使用 CPU 4x 和 Slow 4G 测量一台中端手机。
  • variants:每个变体的条件,包括 storageState(相对于该文件的路径)、headers 和 ownDomains。如果没有 variants,组合就是各设备上的页面:报告中不会有 Variant 列,组合的 id 为页面和设备(/news/ · mobile)。
  • runs(1 到 9)和 medianBy,其值会被 --runs 和 --median-by 替换。

命令行选项会应用于每种组合:--workflow、--snippet、--wait、--interact-script、--header、--own-domains、--storage-state、--cpu、--network 和各项预算。文件中的 cpu、network 和 storageState 会覆盖命令行对应的设置;文件中的 headers 和 ownDomains 会与命令行选项合并,同名标头以变体中的设置为准。矩阵文件用于纳入版本控制,因此请通过 --header 和环境变量传递访问代理令牌等机密信息;如果文件中的标头名称看起来像机密信息,会发出警告。CLI 不认识的键会导致错误,避免因拼写错误而在缺少相应条件的情况下进行测量。 该报告是一个表格,每个组合占一行,列出各项指标的评分中位数,随后列出决定退出代码的错误;--verbose 会额外显示每个组合中位数运行的报告。--markdown 会生成相同的表格,并将每个组合的报告折叠到 <details> 块中,以便在拉取请求评论中保持可读性。使用 --json 时,输出为 { "matrix", "runs", "combinations" },每个组合都是其中位数运行的报告,包含其 id、name、device、variant(当文件定义了变体时)、runs 和 conditions,以及其设备的视口。预算会与每个组合的中位数进行比较。当某个组合超出预算、出现错误或所有运行都失败时,命令以代码 1 退出;文件无效时,则在任何页面加载之前以代码 2 退出,并指出 JSON 中的问题位置。--viewport 不适用,因为每台设备都会设置自己的视口。

使用 CrUX 时,CLI 会针对每个 URL 和设备类型各请求一次,因此同一设备的各个变体会共享其现场数据。使用 --report-to 时,它会为每个组合发送一份报告,报告正文是单个页面的内容,其中包含 meta.device、meta.variant 和 meta.runs;命令行和文件中的标头是加载条件,报告不会包含它们的值。

使用 --baseline <file>(该文件是此次运行的 --json 输出)将一次运行与较早的运行进行比较。比较结果会指出哪些指标超出实验室噪声范围而变差或变好、哪些错误是新增或已修复,以及两次运行的测量方式有哪些不同:

# On main, once: the baseline
npx webperf-snippets https://example.com --runs 5 --json > baseline.json

# On the pull request: compare and report
npx webperf-snippets https://pr-123.example.com --runs 5 --baseline baseline.json --markdown

# Fail when the page gets worse
npx webperf-snippets https://pr-123.example.com --runs 5 --baseline baseline.json --fail-on-regression

如果两次运行都测量了 LCP、FCP、TTFB、CLS 和 INP,则会比较这些指标;每一侧都使用 --runs 指定的中位数。如果只有一侧测量了某项指标,则显示为 not measured。当某项指标恶化幅度超过其阈值(基线数值的一定比例与最小值两者中的较大者),且在基线包含两次或更多次运行时,其结果高于基线中最慢的一次运行,该指标就算退化:中位数仍处于基线范围内,说明基线本身已有这种波动。指标改善时也使用相同规则,只是方向相反;否则视为未变化。

指标基线比例最小值
LCP、FCP、TTFB10%100 ms
INP10%50 ms
CLS无0.05

--threshold 会更改阈值的一部分,同时保留另一部分:--threshold LCP=15% 设置比例,--threshold LCP=200ms 设置最小值,--threshold CLS=0.1 设置 CLS 唯一的阈值部分。可以重复使用它来设置更多指标。

参与比较的错误是那些决定退出代码的错误:工作流步骤中严重级别为 error 的问题,以及执行失败的代码片段。如果两个错误的代码相同,且指向同一资源,那么无论错误消息如何表述,都视为相同;页面自身的资源按其路径和查询进行比较,因此来自其他主机的拉取请求预览应用可以与生产环境匹配。若一侧的代码片段没有代码(例如基线来自较早版本),则按错误消息比较,并忽略其中的数值,因此“Render-blocking CSS (69.21 KB)…”和“Render-blocking CSS (71.80 KB)…”属于同一个错误。只有本次运行中出现的错误是新增错误,只有基线中出现的错误则视为已修复。警告和信息不参与比较,因为它们变化过于频繁。

报告会在常规报告之后添加比较结果,--markdown 还会为拉取请求评论生成一个表格。JSON 输出会在 baseline 中包含比较结果:

"baseline": {
  "file": "baseline.json",
  "url": "https://example.com/",
  "runs": { "count": 5, "medianBy": "LCP" },
  "metrics": {
    "LCP": { "baseline": 2100, "current": 2480, "delta": 380, "deltaPercent": 18.1, "threshold": 210, "verdict": "regressed" }
  },
  "errors": { "new": [{ "id": "render-blocking", "message": "1 render-blocking resource(s) delay rendering until 900ms" }], "fixed": [] },
  "warnings": []
}

当两次运行采用了不同的测量方式,例如使用了不同的工作流或代码片段、视口、等待时间、限流设置、运行次数或 CLI 版本,或者使用了不同的路径或查询参数时,CLI 仍会进行比较,并在 stderr、报告和 warnings 中发出警告:阅读拉取请求评论的人看不到 CI 的 stderr。另一个主机不会发出警告,因为它是针对生产环境的拉取请求的预览应用。只有一次运行的基线会警告你仅有阈值适用。

比较仅提供参考,除非使用 --fail-on-regression,否则退出代码与不进行比较时相同;使用该选项时,如果某项指标退步或出现新的错误,则以 1 退出,并在 stderr 中列出相关项。基线不存在或不是 CLI 的输出、矩阵的基线对应单个页面或单个页面的基线对应矩阵,或者 CLI 不识别 --threshold 时,CLI 会在页面加载前以代码 2 退出。

矩阵会将之前矩阵的 --json 输出作为基线,并按 id 将每种组合与相同 id 的组合进行比较:

npx webperf-snippets --matrix matrix.json --runs 3 --baseline last-week.json

表格会在每项指标后添加一列变化值:当变化有意义时显示变化量(▲ +380ms、▼ −90ms),未变化时显示 =,基线中没有的组合则显示 new。表格下方会列出警告(所有组合都有相同警告时只列出一次)、每种组合新增和修复的错误,以及仅存在于一侧的组合。--markdown 输出相同内容,每种组合的 <details> 块中包含其自身的比较结果。在 JSON 输出中,每种组合都会包含自己的 baseline;根级 baseline 会列出文件以及新增的 added 和缺失的 missing 组合。如果任何组合退步或出现新错误,--fail-on-regression 会以 1 退出。

CI 门控:

npx webperf-snippets https://example.com --budget-lcp 2500 --budget-cls 0.1

每项预算都会与测量值进行比较;使用 --runs 时,则与中位数比较。数值超过预算时即判定失败。--budget-lcp 和 --budget-cls 需要使用 core-web-vitals 工作流;--budget-fcp 需要使用 loading 工作流;--budget-ttfb 需要使用 loading 或 audit 工作流;--budget-inp 需要使用带点击或按键操作的 interaction 工作流;使用该指标的代码片段时,--snippet 也适用。运行未测量的指标所对应的预算会在页面加载前以代码 2 退出;未实际测量的指标(例如没有交互时的 INP)所对应的预算则以代码 1 退出:预算绝不会在未经检查的情况下通过。报告会列出每项预算的数值和判定结果:passed、exceeded(并注明超出多少)或 not measured(并说明原因)。这些内容会显示在面向用户的报告和 Markdown 报告的 Budgets 部分,以及 JSON 输出和 --report-to 正文的 budgets 中。矩阵会在表格下方列出失败的预算及其对应组合。每项失败的预算也会写入 stderr,包括使用 --json 时。

选项
选项描述
--workflow <name>要运行的工作流。默认值:core-web-vitals。选项:core-web-vitals、loading、audit、interaction。
--snippet <name>按名称、别名或 Category/Name 路径运行单个代码片段。
--json输出 JSON,而不是格式化文本。
--markdown输出可由 GitHub 渲染的 Markdown(用于 PR 评论)。
--viewport <preset>视口预设:mobile(默认值)、tablet、desktop。
--wait <ms>页面加载后、评估代码片段前的等待时间。默认值:3000。
--cpu <factor>按此系数降低主线程速度,例如 4。默认不进行限速。
--network <preset>使用 DevTools 预设限制网络速度:fast-4g、slow-4g、3g。默认不进行限速。
--interact-script <path>JSON 文件,包含页面加载后要执行的交互(scroll、click、hover、type、wait)。先安装 Interaction 代码片段,然后再读取。
--storage-state <path>用于需要身份验证的页面的 Playwright 存储状态(Cookie 和 localStorage)。
--header "Name: value"仅用于 URL 所属源的请求标头,例如访问代理的令牌。可重复使用以添加更多标头。
--own-domains <list>视为第一方的站点域名,例如站点自己的 CDN。可用逗号分隔,也可重复指定。
--runs <n>依次测量页面 n 次(1 到 9 次),并报告各次运行结果的中位数。
--median-by <metric>用于选择中位数运行结果的指标:LCP、FCP、TTFB、CLS、INP 或 navMs。默认选择已测得的 LCP、FCP、TTFB 和 navMs 中的首个指标。
--matrix <file>测量 JSON 文件中每个 URL 在其列出的每种设备和变体上的结果,并报告中位数表格。
--baseline <file>将页面或矩阵中的每种组合与先前运行的 --json 输出进行比较:哪些指标在超出误差范围的情况下变差或变好,以及哪些错误是新增或已修复的。
--threshold <metric>=<v>--baseline 的指标阈值,例如 LCP=15%、LCP=200ms 或 CLS=0.1。可重复指定以添加更多指标。
--fail-on-regression如果指标相对于 --baseline 出现回退,或出现新错误,则以 1 退出。
--crux-key <key>在测量值旁添加 CrUX 实测数据(p75)。优先使用 CRUX_API_KEY。
--report-to <url>运行后将结果 POST 到此 https URL。未指定时不会进行外部调用。
--api-key <key>使用 --report-to 时作为 Bearer 令牌发送。优先使用 PERF_REVIEWS_API_KEY。
--budget-lcp <ms>如果 LCP 超过此值或未测得,则以 1 退出。
--budget-fcp <ms>如果 FCP 超过此值或未测得,则以 1 退出。
--budget-ttfb <ms>如果 TTFB 超过此值或未测得,则以 1 退出。
--budget-cls <score>如果 CLS 超过此值或未测得,则以 1 退出。
--budget-inp <ms>如果 INP 超过此值或未测得,则以 1 退出。
--verbose显示所有项目,包括通过检查的项目。
--headed显示浏览器窗口(用于调试)。
-h, --help显示帮助信息。
代码片段别名
别名代码片段
LCPCoreWebVitals/LCP
CLSCoreWebVitals/CLS
INPCoreWebVitals/INP
LCP-SubpartsCoreWebVitals/LCP-Subparts
fontsLoading/Fonts-Preloaded-Loaded-and-used-above-the-fold
render-blockingLoading/Find-render-blocking-resources
resource-hintsLoading/Resource-Hints-Validation
preload-scriptsLoading/Validate-Preload-Async-Defer-Scripts
priority-hintsLoading/Priority-Hints-Audit
critical-cssLoading/Critical-CSS-Detection
ttfbLoading/TTFB-Sub-Parts
script-partiesLoading/First-And-Third-Party-Script-Info
script-loadingLoading/Script-Loading
lazy-atfLoading/Find-Above-The-Fold-Lazy-Loaded-Images
lazy-conflictLoading/Find-Images-With-Lazy-and-Fetchpriority
eager-below-foldLoading/Find-non-Lazy-Loaded-Images-outside-of-the-viewport
后续步骤

一次运行的结果可在同一页面加载过程中添加步骤:LCP 超过 2.5 s 时添加 LCP-Subparts,超过 4 s 时添加 LCP-Trail;图片或视频 LCP 会添加相应的熵、图片或视频审计;CLS 超过 0.1 时添加 Layout-Shift-Loading-and-Interaction,超过 0.25 时还会添加延迟加载图片、字体、关键 CSS 和缺少尺寸信息的图片;TTFB 超过 600 ms 时添加 TTFB-Sub-Parts;FCP 超过 1.8 s 时添加渲染阻塞检查。完整表格请参阅 CLI 页面。每个代码片段只运行一次,后续步骤会给出提示:其中的 error 问题不会更改退出代码。

退出代码
代码含义
0所有检查均已通过。
1超出预算、代码片段出错、工作流中的某个步骤报告了 error 问题,或使用 --fail-on-regression 时,相对于基线出现回归。
2用法错误(缺少 URL、工作流未知、基线或阈值无效)。

MCP 服务

webperf-snippets mcp 会通过 stdio 启动一个 Model Context Protocol 服务,让 AI Agent 可以按名称调用代码片段,而无需读取其源码。将它添加到能够启动本地服务的客户端中,例如 Claude Code:

claude mcp add webperf -- npx -y webperf-snippets mcp

它需要 Playwright 的 Chromium(npx playwright install chromium);如果没有安装,工具会返回这条命令。MCP 服务文档介绍了其他客户端(Cursor、VS Code、Claude Desktop、Gemini CLI)的配置。该服务已列入 MCP Registry,名称为 io.github.nucliweb/webperf-snippets。

工具功能
list_snippets列出代码片段及其类别、标题、简短别名,以及是否会跟踪交互。可选参数为 category。
run_snippet在无头 Chromium 中打开一个 URL,运行一个代码片段并返回其返回的对象。参数为 url、snippet(名称、别名或 Category/Name),以及可选的 viewport 和 waitMs。记录交互的代码片段会在通过 open_page 打开的页面上运行。
run_workflow运行 CLI 的工作流(core-web-vitals、audit、loading、interaction)及其决策树中的后续步骤。参数为 url、workflow,以及可选的 viewport 和 waitMs。
get_crux返回某个 URL 或其来源的 CrUX LCP、CLS 和 INP p75 值。参数为 url,以及可选的 formFactor(phone、desktop、tablet)。服务的环境中需要设置 CRUX_API_KEY。
open_page在后续调用中保持打开的页面中打开一个 URL,并安装跟踪代码片段(track,例如 INP)。返回一个 sessionId。
interact在打开的页面上执行步骤:click、type、hover、scroll 或 wait。
read_results返回打开页面的跟踪代码片段所记录的内容。
close_page关闭打开的页面。

该服务还提供资源,供客户端附加到上下文中:

资源内容
webperf://schema每个代码片段结果都遵循的约定:基本结构、状态、结果读取方式,以及问题代码的规则。
webperf://schema/{snippet}一个代码片段返回的字段及示例,还有其问题代码。
webperf://workflows/{category}某个类别的工作流和决策树。

此外还提供提示词,即用于串联工具的模板(在 Claude Code 中为 /mcp__webperf__audit_lcp):audit_lcp、debug_inp 和 audit_page,每个提示词都带有一个 url 参数。

CrUX 密钥应放在客户端配置中,绝不能作为工具参数:

claude mcp add webperf -e CRUX_API_KEY=<key> -- npx -y webperf-snippets mcp

最多可同时打开三个页面;页面在闲置 10 分钟后关闭;客户端断开连接时,所有页面和 Chromium 都会关闭。

该服务可以响应协议两个版本的客户端:2026-07-28 修订版,以及较早的、使用 initialize 启动的版本。ADR 0002 解释了为何将其设为子命令并使用 stdio。

CI 示例

GitHub Actions:如果 LCP 超过 2.5s,则让 PR 失败:

- run: |
    npm install --no-save webperf-snippets playwright
    npx playwright install --with-deps chromium
    npx webperf-snippets https://staging.example.com --budget-lcp 2500 --budget-cls 0.1
GitHub Action

该代码仓库提供了一个组合式 Action,可安装 CLI 和 Chromium、运行工作流并以 Markdown 格式输出结果。因此,任何代码仓库都无需额外设置,即可根据性能预算设置门禁:

jobs:
  webperf:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: nucliweb/webperf-snippets/.github/actions/webperf-snippets@main
        id: webperf
        with:
          url: https://staging.example.com
          budget-lcp: 2500
          fail-on-budget: "false"

      - uses: actions/github-script@v7
        env:
          BODY: ${{ steps.webperf.outputs.markdown }}
        with:
          script: |
            await github.rest.issues.createComment({
              ...context.repo,
              issue_number: context.issue.number,
              body: process.env.BODY,
            });

      - if: steps.webperf.outputs.exit-code != '0'
        run: exit 1
输入默认值描述
url必填要测量的 URL。
workflowcore-web-vitals要运行的工作流:core-web-vitals、loading、audit 或 interaction。
budget-lcpautoLCP 预算,单位为毫秒。auto 在 core-web-vitals 工作流中为 2500,在其他工作流中不设预算。留空可禁用检查。
budget-fcpFCP 预算,单位为毫秒,适用于 loading。
budget-ttfbTTFB 预算,单位为毫秒,适用于 loading 或 audit。
budget-clsautoCLS 预算。auto 在 core-web-vitals 工作流中为 0.1,在其他工作流中不设预算。留空可禁用检查。
budget-inpINP 预算,单位为毫秒,适用于通过点击或按键执行的 interaction。
fail-on-budgettrue超出预算或代码片段出错时,让该步骤失败。设为 "false" 可读取 exit-code 并自行决定。
cli-versionlatest要运行的 webperf-snippets npm 软件包版本。
输出描述
markdownMarkdown 格式的结果。也会写入作业摘要。
exit-codeCLI 的退出代码:0 表示通过,1 表示超出预算或代码片段出错,2 表示用法错误。

Markdown 中包含从测量页面获取的文本,因此请像上面那样通过环境变量(env: 和 process.env)将其传递给其他步骤,切勿在脚本中插入 ${{ steps.webperf.outputs.markdown }}。将 fail-on-budget: "false" 设为关闭后,Action 步骤始终会成功,因此后续步骤可以先发布评论,再让作业失败。如果没有 permissions: pull-requests: write,评论步骤就无法在拉取请求中发布评论。

共享运行器上的 LCP、CLS 和 INP 测量结果会有 15% 到 30% 的波动;设置门禁时,建议优先使用确定性的 audit 工作流,或设置宽松的预算。

发布

CLI 软件包通过基于标签的工作流发布到 npm。发布是明确且有意为之的操作;只有推送 cli-v* 标签时才会发布。

发布步骤
  1. 更新 cli/package.json 中的版本。
  2. 提交版本变更。
  3. 创建标签并推送:
    git tag cli-v0.2.0
    git push origin cli-v0.2.0
    
  4. publish-cli CI 作业会运行完整测试套件,并发布到 npm。
为何选择基于标签,而非基于路径

另一种方案是在每次向 main 推送涉及 cli/ 的更改时自动发布,并通过版本检查跳过重复发布。但我们选择基于标签发布,因为这样可以让每次发布都经过慎重决定;main 上的 CI 通过并不意味着软件包已准备好发布,而标签则能明确传达这一意图。

访问控制

标签保护规则会限制可以推送 cli-v* 标签的人员。在代码仓库中,前往 Settings → Rules → New ruleset 配置规则,将目标设为 cli-v* 标签模式,并将推送权限限制为管理员或维护者。这样可以确保只有经授权的协作者才能触发发布。

必需的密钥

必须在仓库设置中配置 NPM_TOKEN 密钥,并授予其发布 webperf-snippets npm 包的权限。

已知限制

  • 无头模式下的 CLS 较为保守:除非通过脚本执行滚动,否则不会检测到仅在滚动时发生的布局偏移。
  • 仅限首次导航:每次调用 webperf-snippets 只运行一个 URL。对于 SPA,必须直接传入路由切换后的 URL。
  • 合成 INP ≠ 实际用户 INP:--interact-script 测量的是单个脚本事件的处理程序延迟。实际 INP 反映的是所有用户会话中最差的交互;字段数据请使用 RUM。

路线图

  • v0.2:加载工作流(TTFB、FCP、渲染阻塞、脚本、字体)、共享页面会话、用于 INP 的合成交互、用于 PR 评论的 Markdown 报告器。 ✓ 已发布
  • v0.3:GitHub Action 封装、身份验证流程(登录并测量登录后的页面)、CrUX 字段数据补充、--report-to。 ✓ 已发布
  • v0.4:按名称运行任意代码片段、22 步审计、11 步加载工作流、交互工作流,以及 Core Web Vitals 的决策树后续步骤。 ✓ 已发布

工作原理

  1. 通过 Playwright 启动无头 chromium。
  2. 导航到 URL,等待 load 事件,然后等待 --wait 毫秒(默认 3000 毫秒),以便较晚出现的条目到达页面。
  3. 在页面上下文中评估每个代码片段的 IIFE,并捕获其返回对象。代码片段通过带缓冲的 PerformanceObserver 读取 Chrome 仅向观察器公开的条目(LCP、布局偏移、长任务、事件时序),因此也能读取其运行前记录的条目。
  4. 使用交互脚本时,先安装跟踪代码片段,再运行交互,等待页面稳定,然后读取跟踪数据并运行其他代码片段。
  5. 根据工作流的决策树将后续代码片段加入队列。
  6. 呈现结果(人类可读或 JSON 格式),并以适当的代码退出。

许可证

MIT,详见 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。