懒惰开发者的富链接

当我在Twitter或Slack上分享博客链接时,它显示为纯文本。没有预览图片。只有一个像granda.org/en/2026/01/02/claude-code-on-the-go/这样的URL。

我需要Open Graph图片。标准方法:为每篇文章手动创建一个1200x630的图片。这很繁琐。我让Claude自动化它。

flowchart LR
    Push[git push] --> GHA[GitHub Actions]
    GHA --> Hugo[Hugo Server]
    GHA --> PW[Playwright]
    PW -->|screenshot| Hugo
    PW --> IMG[OG Image]
    IMG --> Commit[git commit]
    Commit --> Deploy[Deploy]
flowchart TB
    Push[git push] --> GHA[GitHub Actions]
    GHA --> Hugo[Hugo Server]
    GHA --> PW[Playwright]
    PW -->|screenshot| Hugo
    PW --> IMG[OG Image]
    IMG --> Commit[git commit]
    Commit --> Deploy[Deploy]

设置

我向Claude说明了问题:文章需要社交预览图片,但我不想手动创建它们。截取文章内容的屏幕截图,将其保存为OG图片,自动更新前置元数据。

Claude构建了什么

组件用途
generate-og-image.js用于截图文章的Playwright脚本
generate-og-images.yml文章更改时触发的GitHub Action
baseof.html更改条件性og:image元标签

Playwright脚本启动无头Chrome,导航到文章,强制浅色模式,隐藏页眉和页脚,并以1200x630截图:

const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
  viewport: { width: 1200, height: 630 },
  deviceScaleFactor: 2, // Retina for crisp text
});

// Force light mode, hide nav
await page.evaluate(() => {
  document.documentElement.setAttribute("data-theme", "light");
  document.querySelector("header").style.display = "none";
  document.querySelector("footer").style.display = "none";
});

await page.screenshot({ path: outputPath, type: "png" });

GitHub Action在任何.en.md文件更改时触发,启动Hugo,运行脚本,并将生成的图片提交回仓库:

on:
  push:
    branches: [main]
    paths:
      - "content/posts/**/*.md"

steps:
  - name: Start Hugo server
    run: hugo server --bind 0.0.0.0 --port 1313 &

  - name: Generate OG images
    run: node scripts/generate-og-image.js "$file"

  - name: Commit changes
    run: |
      git add static/images/posts/ content/posts/
      git commit -m "Generate Open Graph images for blog posts"
      git push

当前置元数据有image字段时,模板有条件地包含图片:

{{- if .Params.image -}}
<meta property="og:image" content="{{ $canonical }}{{ .Params.image }}">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="{{ $canonical }}{{ .Params.image }}">
{{- else -}}
<meta name="twitter:card" content="summary">
{{- end -}}

404: 找不到Slug

第一次运行。Playwright截取了一个空白页面。URL返回404。

脚本从文件名构建了URL:automatic-blog-translations.en.md/en/2025/12/23/automatic-blog-translations/

但Hugo不使用文件名作为slug。它使用标题。实际的URL是/en/2025/12/23/automatic-blog-translations-with-claude-and-github-actions/

我本可以在JavaScript中重新实现Hugo的slugify算法。相反:询问Hugo。

const output = execSync("hugo list all", { encoding: "utf8" });
// CSV output includes the exact permalink Hugo generates

一行代码。没有边缘情况。Hugo已经知道自己的URL。

接下来是什么

当前实现仅为英文文章生成图片。翻译版本引用相同的图片路径,这是可行的,但这意味着即使在分享西班牙语或日语版本时,OG图片也始终显示英文文本。

真正的i18n支持将在下一个PR中到来。目前,每篇文章都获得一个社交图片,这总比没有好。

总结

这花了14分钟来构建和调试。现在每篇文章都自动获得社交预览图片。每篇文章无需手动工作。自动化在几篇文章后就能收回成本。

发布可用版本,发现差距,迭代。


相关文章: