giscus 评论组件集成说明
本站是纯静态 Docusaurus 站点,评论能力不能依赖本地服务器或运行时数据库。当前实现使用 giscus,把页面评论存放到独立 GitHub Discussions 仓库 NeverGpDzy/docs-comments,站点只负责在指定页面加载评论组件。
评论组件的设计目标是和音频播放器一样自动挂载:文章作者不需要在每篇 Markdown 或 MDX 文件里手动引入组件。只要页面属于博客详情页、Travel 文档详情页,或被布局层明确允许的自定义页面,布局层会自动渲染评论区。
当前行为
评论只出现在下面这些页面:
| 页面类型 | 中文路径 | 英文路径 | 是否显示评论 |
|---|---|---|---|
| 博客详情页 | /blog/... | /en/blog/... | 是 |
| Travel 文档详情页 | /docs/Travel/... | /en/docs/Travel/... | 是 |
| About 页面 | /about | /en/about | 是 |
| 博客列表页 | /blog | /en/blog | 否 |
| 其他文档页 | 非 /docs/Travel/... 的文档 | 非 /en/docs/Travel/... 的文档 | 否 |
| 其他自定义页面 | 非 /about 的自定义页面 | 非 /en/about 的自定义页面 | 否 |
中英文对应页面共用同一条 Discussion。实现方式是把英文页面路径开头的 /en 去掉后再作为 giscus 的 term:
/blog/2026/05/02/hamasushi-big-conveyor-belt-sushi-meal
/en/blog/2026/05/02/hamasushi-big-conveyor-belt-sushi-meal
-> /blog/2026/05/02/hamasushi-big-conveyor-belt-sushi-meal
/docs/Travel/hong-kong-travel
/en/docs/Travel/hong-kong-travel
-> /docs/Travel/hong-kong-travel
/about
/en/about
-> /about
这样读者在中文页或英文页看到的是同一个评论区,避免同一篇内容被拆成两套讨论。
GitHub 侧配置
评论数据放在仓库:
NeverGpDzy/docs-comments
这个仓库需要满足以下条件:
- 仓库必须是 public。
Settings -> General -> Features中启用 Discussions。- Discussions 中存在
Announcements分类。 - giscus GitHub App 已安装并授权给
NeverGpDzy/docs-comments。 - 不创建
giscus.json,因此不限制来源域名。
当前前端写死的 giscus 配置如下:
| 配置项 | 值 |
|---|---|
repo | NeverGpDzy/docs-comments |
repoId | R_kgDOSTPzRQ |
category | Announcements |
categoryId | DIC_kwDOSTPzRc4C8Qej |
mapping | specific |
strict | 1 |
reactionsEnabled | 1 |
emitMetadata | 0 |
inputPosition | bottom |
loading | lazy |
repoId 和 categoryId 不是密钥,可以写入前端代码。它们来自 giscus 配置页生成的 script 片段。
代码结构
核心文件:
| 文件 | 作用 |
|---|---|
src/components/GiscusComments/index.js | 评论组件主体,封装 giscus 配置、语言、主题和 term 生成 |
src/components/GiscusComments/styles.module.css | 评论区标题、间距和分隔线样式 |
src/theme/BlogPostPage/index.js | 博客详情页 swizzle 布局,自动挂载评论 |
src/theme/DocItem/Layout/index.js | 文档详情页 swizzle 布局,仅在 Travel 分支挂载评论 |
src/theme/MDXPage/index.js | content-pages 布局,仅在 About 页面挂载评论 |
package.json | 声明 @giscus/react 依赖 |
组件关系:
BlogPostPage
-> BlogAudioPlayer
-> BlogPostItem
-> GiscusComments
-> BlogPostPaginator
DocItem/Layout
-> if isTravelDocMetadata(metadata)
-> DocItemContent
-> GiscusComments
-> DocItemPaginator
-> else
-> normal doc layout without comments
MDXPage
-> MDXContent
-> if getGiscusTerm(metadata.permalink) === '/about'
-> GiscusComments
-> else
-> normal MDX page without comments
评论组件实现
GiscusComments 接收一个可选的 permalink:
<GiscusComments permalink={metadata.permalink} />
博客页和文档页都传入 Docusaurus metadata 中的 permalink,而不是直接依赖浏览器地址。这样 SSR、静态构建和客户端导航时使用的路径来源更稳定。
组件内部会处理四件事。
1. 生成稳定的 giscus term
getGiscusTerm() 会规范化路径:
- 去掉
#hash。 - 去掉
?query。 - 去掉尾部
/。 - 如果路径以
/en开头,去掉/en。 - 空路径回退为
/。
示例:
getGiscusTerm('/en/docs/Travel/hong-kong-travel/')
// => '/docs/Travel/hong-kong-travel'
getGiscusTerm('/blog/post-a?preview=1#comments')
// => '/blog/post-a'
因为 giscus 使用 mapping="specific",term 就是页面和 Discussion 的绑定键。这个值一 旦改动,旧评论不会丢失,但页面会关联到新的 Discussion,看起来就像评论区被重置。因此不要随意修改 term 规则。
2. 同步语言
组件通过 useDocusaurusContext() 读取当前 locale:
| 当前 locale | giscus lang | 评论标题 |
|---|---|---|
zh-Hans | zh-CN | 评论 |
en | en | Comments |
3. 同步主题
组件通过 useColorMode() 读取 Docusaurus 当前颜色模式:
| Docusaurus 主题 | giscus 主题 |
|---|---|
| light | light |
| dark | dark |
切换站点明暗主题时,React 会重新渲染 giscus 组件并同步主题。
4. 只在布局层挂载
评论组件没有写进文章内容文件,而是写进主题布局:
// src/theme/BlogPostPage/index.js
<BlogPostItem>{children}</BlogPostItem>
<GiscusComments permalink={metadata.permalink} />
// src/theme/DocItem/Layout/index.js
<DocItemContent>{children}</DocItemContent>
<GiscusComments permalink={metadata.permalink} />
// src/theme/MDXPage/index.js
{isAboutPage && <GiscusComments permalink={metadata.permalink} />}
博客布局文件只用于博客详情页,因此博客列表页不会出现评论。文档布局中只有 isTravel 分支渲染评论,因此 Travel 之外的文档页不会出现评论。content-pages 布局中只有 getGiscusTerm(metadata.permalink) === '/about' 时渲染评论,因此 About 之外的自定义 Markdown / MDX 页面不会出现评论。
新增内容时的规则
新增博客
只要在 blog/ 新增中文博客,评论会自动出现。
如果有英文版,应放在:
i18n/en/docusaurus-plugin-content-blog/{same-file-name}
文件名和 slug 保持一致时,中英文会共用同一条 Discussion。
新增 Travel 文档
中文文件放在:
docs/Travel/{slug}.mdx
英文文件放在:
i18n/en/docusaurus-plugin-content-docs/current/Travel/{slug}.mdx
文件名和 slug 保持一致时,中英文会共用同一条 Discussion。
新增其他文档
其他文档默认不会显示评论。如果以后要给新的文档分类开启评论,应优先扩展判断函数或在 DocItem/Layout 中新增清晰的分类判断,不要在每篇文档里手动插入组件。
新增自定义页面
自定义 Markdown / MDX 页面默认不会显示评论。当前只有 About 页面通过 src/theme/MDXPage/index.js 的路径判断开启评论 。如果以后要给新的自定义页面开启评论,应在 MDXPage 中新增清晰的路径判断,不要在页面内容文件里手动插入组件。
维护注意事项
不要随意改 term 规则
term 是页面和 Discussion 的主键。下面这些改动都会导致新旧评论分裂:
- 从去掉
/en改成保留/en。 - 从 pathname 改成 title。
- 从去尾斜杠改成保留尾斜杠。
- 改文章 slug 或 permalink。
如果必须改 slug,旧 Discussion 仍在 docs-comments 仓库里,但新页面会创建新的 Discussion。需要人工在 GitHub Discussions 中迁移、合并或保留旧讨论链接。
不要把评论组件写进 MDX
当前设计是布局自动挂载。About 页面也是通过 MDXPage 布局挂载评论,而不是在 About 内容文件中引入组件。手动写进 MDX 会带来重复评论区、双语不一致和维护困难。
不限制来源域名的影响
当前没有 giscus.json,所以其他网站理论上也可以嵌入同一个 giscus 配置。实际评论仍需要 GitHub 登录,并且内容可以在 NeverGpDzy/docs-comments 的 Discussions 中删除、锁定或管理。
如果未来要限制来源,可以在评论仓库新增 giscus.json,但这会改变当前约定,需要同步更新本文档。
repoId 和 categoryId 变更
如果重建评论仓库、迁移仓库或更换 Discussion 分类,需要重新到 giscus 配置页生成 repoId 和 categoryId,然后更新 src/components/GiscusComments/index.js。
测试清单
每次修改评论组件或挂载逻辑后,至少运行:
npm run build
npm run build:en
重点检查页面:
| 页面 | 预期 |
|---|---|
/blog/2026/05/02/hamasushi-big-conveyor-belt-sushi-meal | 显示评论 |
/en/blog/2026/05/02/hamasushi-big-conveyor-belt-sushi-meal | 显示同一评论 |
/docs/Travel/hong-kong-travel | 显示评论 |
/en/docs/Travel/hong-kong-travel | 显示同一评论 |
/about | 显示评论 |
/en/about | 显示同一评论 |
/blog | 不显示评论 |
/en/blog | 不显示评论 |
| 任意非 Travel 文档页 | 不显示评论 |
| 任意非 About 自定义页面 | 不显示评论 |
部署后再做一次真实评论测试:
- 在中文博客页发布一条测试评论。
- 切到对应英文博客页,确认能看到同一条评论。
- 在中文 Travel 页发布一条测试评论。
- 切到对应英文 Travel 页,确认能看到同一条评论。
- 在
/about发布一条测试评论。 - 切到
/en/about,确认能看到同一条评论。 - 到
NeverGpDzy/docs-comments的Announcements分类确认 Discussion 被创建。