把 OG 装进 CI:防回归门禁
改版合入三周后,市场部在 LinkedIn 分享新品页:卡片没图,标题回退成布局里的 <title>。查 git blame,og:image 是在一次「清理重复 head 标签」的重构里被顺手删掉的——PR 过了 Lighthouse、过了视觉回归,就是没人查原始 HTML 里的 meta。
这不是「再截一张分享预览图」能防住的问题。OG 是典型的改了没人发现坏了字段:人眼看页面正常,爬虫看的才是卡片契约。
事故复盘模板(下次可直接贴 issue)
写进 postmortem 时,尽量把下面五格填满,而不是只写「OG 坏了」:
| 格 | 要写清的内容 | 示例 |
|---|---|---|
| 症状 | 哪个平台、什么卡片形态 | LinkedIn 无图;Slack 标题来自错误页面 |
| 首次发现 | 谁、何时、什么渠道 | 运营在发帖日发现;用户反馈截图 |
| 引入 commit | 删标签 / 改模板 / 换渲染路径 | 重构 head、CMS 默认字段、SPA 壳替换 SSR |
| 为何门禁没拦 | 缺检查 / 只看浏览器 / 只看预览站 | CI 无 OG 步骤;扩展只验了 localhost |
| 修复与防再发 | 补标签 + 哪条自动化 | 恢复 meta;CI 对 out/ 跑 og-kit check |
把「为何门禁没拦」单独成格,是为了逼出流程债:多半不是规则不存在,而是没有稳定、可失败的自动化。
为什么扩展替不掉 CI
浏览器扩展适合开发期与私有环境:localhost、登录态、staging、一键 rescrape。它跑在你的会话里,能看见真实 DOM。
GitHub Actions / 其他 CI 没有你的扩展。跑在无头 runner 上的检查必须是:
- 可安装的 CLI 或脚本
- 确定性退出码(绿 / 红 / 工具挂了)
- 机器可读输出(JSON / SARIF / JUnit),好让 PR 注释与 Code Scanning 接得上
把 OG 想成 ESLint:编辑器插件提升手感,仓库门禁才防止「别人合入时弄坏」。Lighthouse 同理——本地分数很爽,PR 不 fail 就会漂移。
门禁最小集(先过这三条,再谈完美)
不必第一天启用全部 32 条规则。对「防回归」最值钱的是:
1. 必填字段还在
| 规则 id | 严重级别 | 含义 |
|---|---|---|
og-title-missing |
error | 没有 og:title |
og-type-missing |
error | 没有 og:type |
og-url-missing |
error | 没有 og:url |
og-image-missing |
error | 没有 og:image |
实务上还会把 og-description-missing(warn)和 twitter-card-missing(warn)纳入视线;默认 --fail-on error 时 warn 不拦 PR,但报告里能看见。
2. 图真的可被爬虫拿到
| 规则 id | 严重级别 | 常见事故 |
|---|---|---|
og-image-relative-url |
error | 相对路径,爬虫常直接丢掉 |
og-image-not-https |
error | 非 HTTPS |
og-image-forbidden |
error | 鉴权图床 / 403 |
og-image-content-type-mismatch |
error | Content-Type 与真实格式不一致 |
本地扫静态 HTML 时,部分网络图规则需要可达的公网资源;对纯构建产物目录,至少应先拦住「标签缺失 + 相对路径」这类确定 bug。
3. 体积与尺寸别把 IM 打爆(可先 warn)
| 规则 id | 严重级别 | 说明 |
|---|---|---|
og-image-bytes-exceeds-platform-budget |
warn | 超出平台字节预算 |
og-image-dimensions-too-small |
warn | 小于推荐 1200×630 |
字节数字因平台而异,且不少来自社区实测而非单一官方承诺——规则文档会标来源档位。CI 里先 warn 可见、error 必填 通常更稳。
稳定规则 id 是公共 API:文档 URL、--disable / --only、baseline 条目都挂在 id 上。改名等于破坏门禁——这点和 ESLint rule id 一样。
接入示例:概念 GitHub Actions
已发布包入口是 npx --yes @og-kit/cli(可执行文件名 og-kit)。同一套规则与报告 schema 与网站扫描共用。
# .github/workflows/og-check.yml — 概念示例,按你的构建产物路径改
name: Open Graph gate
on:
pull_request:
push:
branches: [main]
jobs:
og:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
# 你自己的站点构建:Next / Astro / 任意静态导出
- name: Build site
run: npm ci && npm run build
- name: Check Open Graph on build output
run: |
npx --yes @og-kit/cli check ./out \
--fail-on error \
--base-url https://example.com \
--json > og-report.json
# 目录按框架改:out/ dist/ build/ .next/ 等
# 退出码:0 通过 · 1 有达到 fail-on 的问题 · 2 工具/配置失败
- name: Upload report (optional)
if: always()
uses: actions/upload-artifact@v4
with:
name: og-report
path: og-report.json
要点:
- 先构建再扫产物(或扫你关心的公网 URL)。只扫源码里的 TSX 模板,抓不到框架最终吐出的 HTML。
--base-url让相对路径解析与「页面身份」类规则有意义;没有它时,依赖公网身份的规则会被跳过并列出,而不是假装通过。- 人类可读输出不是稳定接口;自动化请用
--json、--sarif或--junit。 - 退出码契约:
0通过,1findings,2工具失败——CI 才能把「OG 坏了」和「安装挂了」分开。
本地等价:
npx --yes @og-kit/cli check https://example.com
npx --yes @og-kit/cli check ./dist --base-url https://example.com --fail-on error
npx --yes @og-kit/cli --version
# 四行:og-kit / engine / ruleset / report-schema(版本契约见仓库 docs)
GitHub Action 封装现状(诚实边界)
仓库里有 @og-kit/action 目录,定位是 CLI 的薄封装。以当前仓库现状为准:它仍是占位 / 未上架的 marketplace Action,不要写成「点一下就能用的官方 Action」。生产可用路径就是上面的 npx @og-kit/cli check …。等 Action 真正发布、有 action.yml 与版本标签后,再把 YAML 换成 uses: 即可——门禁语义(规则 id、退出码、JSON)不变。
baseline 与噪音治理
第一天对存量站点全开 error,往往几十条历史债把 PR 刷红。可采纳路径:
收窄目标
--only og-title-missing,og-type-missing,og-url-missing,og-image-missing,og-image-relative-url
或只扫关键模板:check ./out/pricing.html ./out/index.html。baseline 豁免已知债
npx --yes @og-kit/cli check ./out \ --base-url https://example.com \ --baseline .ogkit-baseline.json \ --update-baseline把当前 findings 写入 baseline 并提交。之后相同 target + ruleId(可选 pin message)不再导致 exit 1;新回归仍会红。
按规则关掉,而不是关掉整条 job
--disable title-truncation-risk,og-title-matches-title
或ogkit.config.*里写rules/failOn/baseline,与 CLI 标志合并。勿用「永远 continue-on-error」当 baseline
那会让回归静默。baseline 的价值是:旧债可见、新债失败。
治理节奏建议:每月从 baseline 抠掉几条(修标签),而不是无限追加豁免。规则 id 稳定,才方便在 issue 里写「关掉 og-image-bytes-exceeds-platform-budget 直到压图 pipeline 就绪」。
和视觉 QA、预览站怎么分工
| 手段 | 擅长 | 不擅长 |
|---|---|---|
| 设计稿 / 人眼 | 品牌、安全区、对比度 | 合入后标签被删 |
| 第三方 / 站内预览 | 布局与截断近似 | 权威缓存;CI 无头环境 |
| 浏览器扩展 | localhost、登录态、rescrape 引导 | Actions runner |
| CLI 门禁 | 稳定规则 id、exit code、PR 失败 | 替你做视觉审美 |
第三方预览是近似;权威仍是各平台官方 debugger(系列前文已写)。CI 解决的是「标签与可达性是否还在」,不是「LinkedIn 缓存里是不是上周的图」——后者要 rescrape,见系列缓存篇。
检查清单(可复制进团队 wiki)
- 构建产物或关键公网 URL 在 PR 上跑
og-kit check -
--fail-on error(或配置等价)使缺og:image等 error 失败 - 使用
--json/ SARIF / JUnit 之一做工件或 Code Scanning - 存量债走 baseline 或
--only,而不是关掉 job - 规则文档链到稳定 id(例如
og-image-missing) - 未把未上架的 GitHub Action 写成依赖路径;以
npx @og-kit/cli为准 - 改版 / 换 head 组件的 PR 必须触达上述 job
用 CLI 自检一次
公网页可先贴首页扫描看报告形态;同一套规则进 CI 时用 CLI:
npx --yes @og-kit/cli check https://你的域名/关键页 --fail-on error
完整规则表:规则参考。平台差异与 rescrape 不在本文展开——门禁只保证「契约字段还在且图可达」,不保证「所有平台缓存已更新」。
下一篇读什么
- Open Graph 到底在解决什么 —— 全流程与工具地图(CI 只是第 5 步)
- 为什么你的 Open Graph 卡片一片空白 —— 五分钟分诊
- 必填 meta 清单、图片工程、缓存 / rescrape —— 系列相邻篇
- localhost / staging 死角 —— 扩展路径(CI 够不到时)
三条可带走的结论: 视觉 QA 代替不了 meta 回归门禁;门禁最小集是「必填 + 图可达 +(可选)体积」且 id 必须稳定;今天就用 npx @og-kit/cli check 进 Actions,Action 封装以上架为准、不夸大。