翻译:
为 Next.js 应用程序打开图形卡 。 何等的连结 变成 当有人粘贴时 它进入WhatsApp,Telegram,Slack,iMessage或Facebook——常常是唯一的部分 在决定是否打开网页之前.
1个佐藤里出品人, 卖家加雅加达桑斯和2个卡片
"布料"每个 opengraph-image.tsx 打电话 品牌身份被约束一次
app,因此本软件包上的两个应用程序从相同的布局中抽取,仍读作
两种产品.
快开始
// app/_lib/og.tsx — bind the identity once
import { createOgCards, domainFromEnv } from '@djangocfg/widget-ogimage';
import { settings } from '@core/settings';
export const { size, contentType, brandCard, contentCard } = createOgCards({
name: settings.app.name,
description: settings.app.description,
tagline: 'Run on one machine. Coordinate many.',
domain: domainFromEnv({ fallback: settings.app.siteUrl }),
siteUrl: settings.app.siteUrl,
accentColor: '#61B8FF',
mark: <svg …/>, // inline SVG only — see below
});
// app/opengraph-image.tsx — the brand card: home, and the fallback everywhere
import { brandCard, contentType, size } from '@lib/og';
export const runtime = 'nodejs';
export const alt = 'CMDOP — run commands across your machines';
export { size, contentType };
export default async function OpengraphImage() {
return brandCard('Skills & MCP servers', 'Browse, search, and install.');
}
// app/skills/[slug]/opengraph-image.tsx — one entity
import { contentCard, contentType, size } from '@lib/og';
import { getSkill } from '@lib/api';
export const runtime = 'nodejs';
export { size, contentType };
export default async function Image({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const skill = await getSkill(slug).catch(() => null); // never throw — see rules
return contentCard({
title: skill?.seoTitle || skill?.name, // empty → brand card
eyebrow: 'Skill',
description: skill?.seoDescription,
footer: 'Marketplace · Skills',
image: skill?.cover, // absolute URL, root-relative path, or data URI
});
}
通过将片段附加到任何页面路径来检查本地性 :
/opengraph-image, (中文(简体) ), /skills/<slug>/opengraph-image两者都归还1200×630 PNG.
三条
runtime = 'nodejs' 在每一个路线. 字体解码器使用 Buffer,哪个
边缘运行时间不提供.
别扔了. 在爬行者等待时,卡片会制作 一条500多条的路
聊天线上赤灰色的矩形——严格说来比通用品牌差
纸牌。 每一次都一样 .catch(() => null),以及 contentCard 倒计时
brandCard 当标题为空.
没有 openGraph.images 在一张卡片上方. 下一个文件公约只适用
在没有明确的情况下 images 和明确条目 赢。 。 。 .
一个 images 在布局中阵列不补充其下方的牌, 它
沉默地禁用它们——根版式可以压制应用程序中的每张卡片
一次 一次吗. withoutOgImages(metadata) 从生成的元数据中剥离它们.
API 密码
| 导出 | 作用 |
|---|---|
createOgCards(config) | 捆绑身份 – { size, contentType, brandCard, contentCard }建议的切入点. |
fitDescription(title, text) | 将预算描述为标题长度的函数;在单词边界上修剪. |
ogFooter(...parts) | 将事实与 ·丢掉缺席的. |
ogImageUrl(path, siteUrl) | 绝对 URL 或 undefined ——佐藤取出图像本身. |
domainFromEnv • 妇女 siteUrlFromEnv • 妇女 metadataBaseFromEnv • 妇女 resolvePublicUrl | 网站来源 NEXT_PUBLIC_SITE_URL 有个应用公司的倒闭. |
withoutOgImages(metadata) | 条纹 openGraph.images 编号 : twitter.images 所以一个部分的卡适用. |
renderOgImage(options, fonts) • 妇女 OG_SIZE • 妇女 OG_CONTENT_TYPE • 妇女 DEFAULT_OG_THEME | 直接画出一张牌. |
loadOgFonts() | 供应商的打字机,每个流程一次解码. |
loadImageDataUri(path, mime) | 本地文件作为数据 URI(一个带有应用程序的出船相片). |
OgCardsConfig
| 外地 | 页:1 |
|---|---|
name | 品牌牌标题; 内容牌上的文字标记 |
description? • 妇女 tagline? | 品牌牌描述和页脚 |
domain? | 右下打印 |
siteUrl? | 解决根关系 image 路径 |
accentColor? • 妇女 theme? | 调色板; theme.footer 默认重音 |
mark? | 内置 SVG 。 Satori 无法装入带有 CSS 的 React 图标组件, 以及一个 <img> 到远程标志使每张卡都依赖于一个在爬行者等待时可能失败的获取. |
loadFonts? | 交换打字面 |
版式
相框为1200×630而佐藤里不剪接:一个标题足够长来包装
推入脚而去取取取出. titleSizeFor 步骤标题
通过 84 ~ 66 ~ 52px 的34和58个字符,以及 fitDescription 预算
对应这些步骤的描述(150 ~ 92 ~ 0个字符),所以两个字符
移动在一起。 换个,换个.
一张相片上,两道相片将左半边暗出,使拷贝能活下来 无论图像发生什么, 复制栏缩小 停留在 地上被打乱了 这些数字是通过渲染得到的;如果你改变它们, 做一个,看看它.
字体
src/fonts/index.ts 实值 生成 ——三个 .woff 旁边的文件
真理的来源。 佐藤无法使用 next/font (woff2, 返回类)
名称)且不能读取 .woff 在生产建筑的路线旁(无)
追踪到输出中, 因此字节被插入到模块中
图. ~64KB 来源,在构建时支付,从未被发送到浏览器.
pnpm fonts # node scripts/generate-fonts.mjs
加上雅加达桑斯,SIL开放字体许可证1.1.
元数据
页次 Metadata (标题模板、警语、hreflang、静态品牌图像)
@djangocfg/nextjs/og-image是因为 makeMetadataFactory它没有“放弃”
卡片"故意的大小写:上面的文件常规通过设计凌驾元数据,
因此,支持两者将是两个机制竞相设置同一标记.