☰
giscus:基于 GitHub Discussions 的评论系统接入与高级配置指南
2026/10/6 7:53:55 网站建设 项目流程
  • 后端

【免费下载链接】giscus

A commenting system powered by GitHub Discussions. :octocat: :speech_balloon: :gem:

项目地址:https://gitcode.com/gh_mirrors/gi/giscus
点击查看免费下载

giscus 是一款完全开源、无需数据库的评论组件,它把 GitHub Discussions 直接变成你网站的评论区,访客可以用 GitHub 账号发表评论与表情反应,评论数据天然沉淀在你的仓库里。本文以仓库官方 README(匈牙利语版 README.hu.md,内容与英文版 README.md 一致)为骨架,结合仓库源码与配置,系统讲解 giscus 的工作原理、快速接入、仓库级高级配置、宿主页面通信与自托管部署,帮助你完整掌握这套评论方案。

giscus 是什么:核心特性一览

giscus 是一个"由 GitHub Discussions 驱动"的评论系统:访客通过 GitHub 在你网站上留下评论和反应,所有数据都存储在 GitHub Discussions 中。它的设计深受 [utterances] 启发,但与 utterances 基于 GitHub Issues 不同,giscus 完全构建在 Discussions 及其 GraphQL API 之上。

官方 README 明确列出的核心特性包括:

  • 开源:整个项目以开源形式发布,可以自由查看、修改与部署。
  • 无追踪、无广告、永久免费:不依赖第三方广告与统计服务。
  • 无需数据库:所有评论数据都存放在 GitHub Discussions 中,由 GitHub 负责存储与备份。
  • 支持自定义主题:内置多套主题,并允许通过自定义 CSS 深度定制(详见 ADVANCED-USAGE.md 的data-theme一节)。
  • 支持多语言:项目内置数十种语言的界面翻译,翻译资源集中在 locales 目录,每种语言包含 common.json 与 config.json 两个文件。
  • 高度可配置:支持从仓库级配置到 script 标签属性的多层级定制。
  • 自动同步:自动从 GitHub 拉取新的评论与编辑内容,无需手动刷新。
  • 可自托管:可以部署在自己的服务器上,详见 SELF-HOSTING.md。

注意(来自官方 README):giscus 仍处于活跃开发阶段,GitHub 也在持续演进 Discussions 及其 API,因此 giscus 的某些功能可能随时间发生变化或失效。接入时建议关注上游更新。

工作原理:如何用 GitHub Discussions 承载评论

根据 README 的"How it works"一节,giscus 的工作流程可以拆成三个关键环节:

  1. 查找讨论:当 giscus 在页面加载时,会调用 GitHub Discussions 搜索 API,根据你选择的映射方式(页面 URL、pathname、<title>等)查找与当前页面关联的 Discussion。
  2. 自动创建:如果找不到匹配的 Discussion,giscus bot 会在访客第一次发表评论或留下反应时,自动在对应仓库中创建一条新的 Discussion。
  3. 身份与授权:访客要发表评论,必须通过 GitHub OAuth 流程授权 [giscus app] 以访客的名义发帖;访客也可以直接到 GitHub 上的 Discussion 里评论,而你可以在 GitHub 端对评论进行审核管理。

源码层面,讨论的查找逻辑集中在 services/github/getDiscussion.ts。它构造 GraphQL 查询时,会根据strict参数选择搜索策略:

const resolvedTerm = strict ? await digestMessage(term) : term; const searchIn = strict ? 'in:body' : 'in:title'; const query = `repo:${repo} ${categoryQuery} ${searchIn} ${JSON.stringify(resolvedTerm)}`;

默认情况下以讨论标题作为搜索词在in:title中检索;当开启严格模式时,则改为在in:body中检索标题的哈希值(下文"data-strict"一节会详细说明)。另外该文件还强制将仓库名转为小写,以规避 GitHub 在查询中使用 category 时的一个已知问题。返回的讨论数据随后通过 lib/adapter.ts 中的适配函数(如adaptDiscussion、adaptComment)转换为组件渲染所需的内部数据结构。

快速接入与基础配置

在 giscus 官网配置页(自托管时使用你自己的部署页面)选择仓库、映射方式与主题后,页面会生成一段<script>标签,把它粘贴到网页中即可完成接入。script 标签上携带的data-属性构成 giscus 的配置面,在 lib/types/giscus.ts 的ISetConfigMessage接口中可以看到完整的可配置项:repo、repoId、category、categoryId、term、description、backLink、number、strict、reactionsEnabled、emitMetadata、inputPosition、lang、theme。

一个典型的接入脚本形如(来自 ADVANCED-USAGE.md 的示例):

<script src="https://giscus.app/client.js" >string === window.origin

只有origins与originsRegex中的任一规则匹配window.origin时,giscus 才会加载;如果两个列表都为空(或未定义),则默认允许加载。

{ "origins": ["https://giscus.app"] }

originsRegex:用正则匹配来源域名

originsRegex与origins类似,但接受的是正则表达式字符串,测试方式为:

new RegExp(pattern).test(window.origin)

两者可以组合使用,例如本仓库的 giscus.json 同时配置了精确域名与预览环境域名:

{ "origins": [ "https://giscus.app", "https://giscus.vercel.app" ], "originsRegex": [ "https://giscus-git-([A-z0-9]|-)*giscus\\.vercel\\.app", "http://selfhost:[0-9]+" ], "defaultCommentOrder": "oldest" }

底层实现位于 lib/config.ts 的assertOrigin函数:它先遍历origins做全等匹配,再遍历originsRegex做正则测试,任一命中即放行,两者皆空则直接返回true。这一机制在自托管场景下尤其重要——你可以用它把 giscus 限制在你自己信任的站点域名内,防止他人盗用你的仓库讨论。

defaultCommentOrder:默认评论排序

设置默认评论排序方式,取值为"oldest"(从旧到新)或"newest"(从新到旧),默认值为"oldest"。对应类型定义见 lib/types/giscus.ts 中的CommentOrder。

{ "defaultCommentOrder": "newest" }

script 标签的高级>export async function digestMessage(message: string, algorithm: AlgorithmIdentifier = 'SHA-1') { const msgUint8 = new TextEncoder().encode(message); const hashBuffer = await webcrypto.subtle.digest(algorithm, msgUint8); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join(''); return hashHex; }

在 services/github/getDiscussion.ts 中,严格模式下的搜索词即由digestMessage(term)生成。启用该选项时,需要确保目标 Discussion 的正文中包含标题的 SHA-1 哈希:

  • 开启该选项之后由 giscus 新建的 Discussion 会自动附带哈希,格式为 HTML 注释,因此在 GitHub 页面上不可见:
<!-- sha1: cad60a29d1b50cbeb42ec2ff630fc508afb1d2e3 -->
  • 对于在此之前已存在的 Discussion,可以手动编辑讨论正文,把标题的 SHA-1 哈希(可用任意 SHA-1 计算器生成)写进正文任意位置即可完成迁移。格式不必完全一致,只要哈希出现在正文中,giscus 就能找到它。

data-theme:加载自定义主题 CSS

data-theme的值可以是内置主题名,也可以是一个CSS 文件的 URL。传入 URL 时,giscus 会在<head>的末尾追加一个<link rel="stylesheet">元素来加载该样式:

<script src="https://giscus.app/client.js" ><link id="giscus-theme" rel="stylesheet" crossorigin="anonymous" href="https://giscus.app/themes/custom_example.css">

仓库内置主题的完整清单可见 lib/variables.ts 的availableThemes(如light、dark、preferred_color_scheme、transparent_dark、noborder_*、gruvbox、catppuccin_*、cobalt、purple_dark、fro等),对应的样式文件存放在 styles/themes 目录,其中 custom_example.css 可以作为编写自定义主题的起点。

安全提醒(来自官方文档):加载外部 CSS 文件可能不安全。请确保你信任该 CSS 的作者与提供方;如果所使用的 CSS 给网站上的 giscus 用户带来安全漏洞,项目不为此负责,请务必让你的用户知晓这一点。

<meta>标签:定制回链giscus:backlink

当 giscus 新建一条 Discussion 时,默认会在讨论正文中回链当前页面(使用window.location.href)。如果你想自定义这个回链地址,可以在页面<head>中加入带name="giscus:backlink"的<meta>标签,giscus 会改用其content属性作为回链:

<head> <!-- ... --> <meta name="giscus:backlink" content="https://bit.ly/RickRolled"> <!-- ... --> </head>

此时新创建的 Discussion 正文中的链接将是https://bit.ly/RickRolled而不是页面真实 URL。这在你想为页面使用短链接时非常有用——例如网站 URL 结构或域名变更时,短链接不会因此失效。

与宿主页面通信:message 事件

giscus 运行在<iframe>中,通过postMessage与宿主页面双向通信,对应的消息类型定义在 lib/types/giscus.ts。

giscus → 宿主页面(iframe 向父窗口发消息)

giscus 通过window.parent.postMessage()向父窗口发出message事件,宿主页面可以监听这些事件并根据 giscus 的状态更新页面:

function handleMessage(event: MessageEvent) { if (event.origin !== 'https://giscus.app') return; if (!(typeof event.data === 'object' && event.data.giscus)) return; const giscusData = event.data.giscus; // 例如 console.log(giscusData),注意用 'discussion' in giscusData 等判断消息类型 } window.addEventListener('message', handleMessage); // 稍后移除监听 window.removeEventListener('message', handleMessage);
  • IErrorMessage:默认情况下,giscus 遇到错误时会向父窗口发送{ error: string }格式的错误消息。客户端脚本正是利用它自动清理父页面localStorage中失效或过期的会话数据。对大多数用户用处不大,但需要时也可以自行接收:
interface IErrorMessage { error: string; } if ('error' in giscusData) { const errorMessage: IErrorMessage = giscusData; console.error(errorMessage.error); }
  • IMetadataMessage:如果在 script 标签上设置data-emit-metadata="1",giscus 会周期性发送讨论元数据(仅在 Discussion 存在时发送):
interface IMetadataMessage { discussion: IDiscussionData; viewer: IUser; } if ('discussion' in giscusData) { const metadataMessage: IMetadataMessage = giscusData; console.log(metadataMessage.discussion); console.log(metadataMessage.viewer); }

IDiscussionData包含讨论的id、url、locked状态、仓库nameWithOwner、反应总数、评论/回复计数等字段(见 lib/types/giscus.ts)。此外该文件中还定义了IResizeHeightMessage(iframe 高度自适应)与ISignOutMessage(登出)等内部消息类型。

宿主页面 → giscus(父窗口向 iframe 发消息)

giscus<iframe>的contentWindow也监听message事件,宿主页面可以借此动态更新 giscus 配置,而无需重新加载 script 或 iframe 元素:

function sendMessage<T>(message: T) { const iframe = document.querySelector<HTMLIFrameElement>('iframe.giscus-frame'); if (!iframe) return; iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app'); }
  • ISetConfigMessage:setConfig中的属性全部可选,因此你可以只更新部分配置、其余保持原样。例如动态切换主题并关闭反应功能:
interface ISetConfigMessage { setConfig: { theme?: Theme; repo?: string; repoId?: string; category?: string; categoryId?: string; term?: string; description?: string; backLink?: string; number?: number; strict?: boolean; reactionsEnabled?: boolean; emitMetadata?: boolean; inputPosition?: InputPosition; lang?: AvailableLanguage; }; } sendMessage({ setConfig: { theme: 'https://giscus.app/themes/custom_example.css', reactionsEnabled: false, } });

InputPosition('top' | 'bottom')、CommentOrder('oldest' | 'newest')等类型均定义于 lib/types/giscus.ts。

从 utterances / gitalk 迁移

如果你之前使用过基于 GitHub Issues 的评论系统(例如 [utterances]、[gitalk]),可以无缝迁移到 giscus:先在 GitHub 端把已有的 Issues转换为 Discussions,转换后只需确保讨论标题与页面之间的映射关系正确(标题要与页面 URL、pathname 或 title 等映射方式对应),giscus 便会自动使用这些已有讨论,而不会重复创建。转换操作在 GitHub 的 Discussion 管理界面完成。

自托管部署

官方 README 指出 giscus 可以自行部署(详见 SELF-HOSTING.md)。自托管的核心步骤包括:

  1. 创建 GitHub App:在 GitHub 的 App 创建页面注册新应用。
    • 授权回调 URL 必须设置为https://[你的域名]/api/oauth/authorized(对应本仓库 pages/api/oauth/authorized.ts 路由)。
    • 不要勾选"Expire user authorization tokens"(giscus 目前不支持令牌过期),如确有需求,可修改代码中的TOKEN_VALIDITY_PERIOD来定期吊销用户令牌。
    • Webhook 不需要,取消勾选"Active"。
    • 仓库权限只需为Discussions开启 "Read & write",其余保持默认。
  2. 生成凭据:生成私钥(private key)、生成并保存 client secret、复制 App ID 与 Client ID。
  3. 安装 App:在侧边栏进入 "Install App" 并安装到你的账号。建议选择 "Only select repositories" 并指定仓库;若选择 "All repositories",App 将能访问包括私有仓库在内的所有讨论,任何知道仓库名的人都能读取和发帖,务必谨慎。
  4. (可选)配置 Supabase 缓存令牌:GitHub App 的安装访问令牌 TTL 只有 60 分钟,可以在 Supabase 中建表缓存令牌以减少向 GitHub 的令牌请求次数、避免触发限流。默认表名为installation_access_tokens,schema 包含installation_id(int8,主键)、token(varchar)、expires_at(timestamptz)、created_at(timestamptz,默认NOW())、updated_at(timestamptz,默认NOW()),各列均不可为空;同时需关闭表的 RLS 或使用service_role密钥。
  5. 部署应用:giscus 官网托管在 Vercel 上,但任何能运行 Next.js 应用及 serverless 函数的平台都可以部署。流程为克隆仓库 → 设置环境变量 →yarn install→yarn build→yarn start。所需环境变量的完整清单见 lib/variables.ts,包括GITHUB_APP_ID、GITHUB_CLIENT_ID、GITHUB_CLIENT_SECRET、GITHUB_INSTALLATION_ID、GITHUB_PRIVATE_KEY、ENCRYPTION_PASSWORD(用于加密用户令牌的随机字符串)、NEXT_PUBLIC_GISCUS_APP_HOST以及可选的 Supabase/Valkey 缓存相关变量。
  6. 使用自托管实例:在自托管站点的配置页生成 script 配置(如data-repo-id、data-category-id),并确保网页引用的是你的部署所托管的 client.js。

另外,README 还提到若要使用 React、Vue 或 Svelte 集成,可以关注 giscus 的组件库,相关用法可进一步参考仓库文档。

多语言、使用案例与贡献

  • 多语言:giscus 界面支持数十种语言,翻译文件位于 locales(每种语言一个目录,含common.json与config.json),README 本身也提供了多种语言版本(如 README.zh-CN.md、README.de.md、README.fr.md 等),匈牙利语版即为本文依据的 README.hu.md。
  • 使用案例:官方 README 中专门有一节列举使用 giscus 的网站,包括 laymonage.com、os.phil-opp.com、Stats and R、Tech Debt Burndown Podcast 等,涵盖个人博客与技术文档站点。
  • 贡献:欢迎参与贡献,具体指引见 CONTRIBUTING.md;如果正在使用 giscus,官方也建议在 GitHub 上为项目加星标。

结语

giscus 的整套设计遵循"复用 GitHub 生态"的思路:评论存储、身份认证、内容审核、数据备份全部交由 GitHub 完成,你只需维护一段脚本与一份可选的仓库配置。结合本仓库源码,你可以进一步阅读 lib/types/giscus.ts 理解消息协议、通过 lib/config.ts 掌握 origin 校验逻辑、在 services/github 中追踪完整的 GitHub GraphQL 调用链,从而在接入、定制乃至自托管时做到心中有数。

  • 后端

【免费下载链接】giscus

A commenting system powered by GitHub Discussions. :octocat: :speech_balloon: :gem:

项目地址:https://gitcode.com/gh_mirrors/gi/giscus
点击查看免费下载

相关推荐

上一篇:如何上手 Maccy:1 行命令搞定的 macOS 剪贴板管理指南
下一篇:unlock-music:浏览器解锁15种加密音乐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询