本文最后更新于:2024年8月11日 上午
背景
Twitter 卡片可以让人在 Twitter 上分享链接时展示更丰富的内容,它不仅可以显示网页的标题、描述、图片等信息,还能让分享的链接更加有趣,也更容易引起别人的注意。像是这样
近日,吾辈开发了一个名为 GitHub Critic 的小工具,用于分析 GitHub 用户并提供建设性的有趣的批评建议。这个项目的灵感来自于推友宝玉的一条推文。在将这个工具分享到 Twitter 后,吾辈意识到仅仅分享一个链接可能不够吸引人,因此吾辈开始探索如何利用 Twitter 卡片来更好地展示这个项目。
介绍
首先吾辈尝试问 Claude 怎么做,它说明了基本的格式和在 Nextjs 中实现的方法。主要是涉及到网页中特定的 meta 标签,例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <head> <meta name="twitter:card" content="summary" /> <meta name="twitter:site" content="@rxliuli" /> <meta name="twitter:creator" content="@dotey" /> <meta name="twitter:title" content="GitHub Critic" /> <meta name="twitter:image" content="'https://github-critic.rxliuli.com/logo.png'" /> <meta name="twitter:description" content="GitHub Critic 是一个用来分析你的 GitHub 并提出批评建议的小工具" /> </head>
|
只要在网页中添加了这些 meta 标签,然后在 Twitter 上分享链接时就会显示卡片信息,如下图所示
两个有用的链接
其事除了 summary 之外,还有其他几种类型,例如 Summary Card with Large Image、App Card、Player Card 等,但由于吾辈只需要分享简单的文本信息,因此只使用了 summary 类型。
实现
在 Nextjs 中,我们可以利用 generateMetadata
函数来动态生成 meta 信息。这个函数在服务端执行,允许我们根据路由参数或其他数据源来生成元数据。以下是一个具体的实现示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| export async function generateMetadata({ params, }: { params: { username: string } }) { const initialAnalysis = (await kv.get(params.username)) as | UserAnalysis | undefined return { title: `GitHub Critic for ${params.username}`, description: initialAnalysis?.analysis.commentary.slice(0, 160) ?? `Check out the GitHub Critic for ${params.username}`, twitter: { card: 'summary', site: '@rxliuli', createor: `@${params.username}`, images: initialAnalysis?.user.image ?? 'https://github-critic.rxliuli.com/logo.png', } as Metadata['twitter'], } }
|
测试 Twitter 卡片是一个挑战,因为它需要公网可访问的 URL。虽然我最初尝试了 GitHub PR + Vercel Preview 的方式,但这个流程相对较慢。为了所见即所得,吾辈转而使用 Cloudflare Tunnel 将本地服务器暴露到公网,有点类似于内网穿透,但免费而简单。
问题
在实际测试时,吾辈还遇到了一个奇怪的 Nextjs 的问题,服务端组件引用的客户端组件中使用了 location 对象导致整个页面都无法渲染,而且这个问题仅在生产模式出现(fuck)。
这是服务端路由组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| export default function Page() { return ( <div> <Head> <title>GitHub Critic</title> <meta name="description" content="GitHub Critic 是一个用来分析你的 GitHub 并提出批评建议的小工具" /> </Head> <main> <h1>GitHub Critic</h1> <p>Check out the GitHub Critic for your GitHub</p> {/* 此处引用了客户端组件 */} <ClientAnalyze /> </main> </div> ) }
|
然后在客户端中使用了 location 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 'use client'
function twitterShareUrl(username: string) { const u = new URL('https://twitter.com/intent/tweet') u.searchParams.set('url', `${location.origin}/${username}`) u.searchParams.set('text', `GitHub Critic for ${username}`) u.searchParams.set('via', 'rxliuli') return u.toString() }
export default function ClientAnalyze(props: { username: string }) { return ( <div> <Link href={twitterShareUrl(username)} target={'_blank'}> <Twitter className={'h-4 w-4'} /> </Link> </div> ) }
|
不得已修改了客户端组件,使用环境变量替代了 location 对象。参考 Testing Twitter Cards,但这个回答提到在生产环境添加环境变量 API_URL
没有用,还是需要添加一个 BASE_URL
环境变量。
修改 nextjs 配置文件
1 2 3 4 5 6 7 8
| const nextConfig = { env: { baseUrl: process.env.BASE_URL || process.env.VERCEL_URL, }, }
export default nextConfig
|
修改客户端组件
1 2 3 4 5 6 7 8 9
| function twitterShareUrl(username: string) { const u = new URL('https://twitter.com/intent/tweet') u.searchParams.set('url', `${process.env.baseUrl}/${username}`) u.searchParams.set('text', `GitHub Critic for ${username}`) u.searchParams.set('via', 'rxliuli') return u.toString() }
|
这个问题突出了 Nextjs 中服务端组件与客户端组件的割裂,甚至在客户端组件中使用 location 对象时都需要特别注意。每天学会一个 Nextjs 小知识,今天你学废了吗?
总结
实现 Twitter 分享链接显示卡片比吾辈想象中简单的多,之需要在网页中添加 meta 标签即可。希望这篇文章能帮助你尝试将你的网站添加分享到 Twitter 的支持。