惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
S
Securelist
GbyAI
GbyAI
The Register - Security
The Register - Security
B
Blog
Recorded Future
Recorded Future
D
DataBreaches.Net
C
Cybersecurity and Infrastructure Security Agency CISA
A
About on SuperTechFans
C
CERT Recently Published Vulnerability Notes
T
The Blog of Author Tim Ferriss
Vercel News
Vercel News
Google DeepMind News
Google DeepMind News
S
Schneier on Security
S
SegmentFault 最新的问题
Martin Fowler
Martin Fowler
T
Tenable Blog
T
The Exploit Database - CXSecurity.com
阮一峰的网络日志
阮一峰的网络日志
宝玉的分享
宝玉的分享
AWS News Blog
AWS News Blog
L
Lohrmann on Cybersecurity
Spread Privacy
Spread Privacy
N
News | PayPal Newsroom
Engineering at Meta
Engineering at Meta
T
Tor Project blog
The Hacker News
The Hacker News
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
MongoDB | Blog
MongoDB | Blog
Cyberwarzone
Cyberwarzone
Security Archives - TechRepublic
Security Archives - TechRepublic
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Threatpost
WordPress大学
WordPress大学
Google Online Security Blog
Google Online Security Blog
G
GRAHAM CLULEY
Google DeepMind News
Google DeepMind News
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Attack and Defense Labs
Attack and Defense Labs
N
Netflix TechBlog - Medium
SecWiki News
SecWiki News
Hacker News: Ask HN
Hacker News: Ask HN
M
MIT News - Artificial intelligence
Scott Helme
Scott Helme
Microsoft Security Blog
Microsoft Security Blog
H
Help Net Security
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org

Aemon's Blog

用 Pandoc 把 Markdown 简历转成 HTML 和 PDF 榨干这台NAS第006话-关于备份 榨干这台 NAS 第 005 话-外网访问之 Tailscale 榨干这台 NAS 第 004 话-刮削 榨干这台 NAS 第 003 话-硬链接 榨干这台 NAS 第 002 话-下载工具 榨干这台 NAS 第 001 话-文件浏览器(File Browser) 榨干这台 NAS 第 000 话-目录结构 煎蛋保险小课堂 What is this thing 15 What is this thing 14 如何「黑入」你的特斯拉 What is this thing 13 emoji 背后的故事 What is this thing 12 A puzzle a day nvm use 命令不生效问题以及解决方法 What is this thing 11 微波炉简易使用指南 What is this thing 10 青旅
给 Hexo 博客换上 Giscus 评论系统
Aemon · 2026-06-28 · via Aemon's Blog

之前博客用的是 Valine,后端数据放在 LeanCloud 上。这个组合用了好多年,基本上属于「配好之后就忘了它存在」的东西。

但是最近 LeanCloud 发了停止对外服务的公告,2027 年 1 月 12 日之后,数据读写、API、控制台这些都会停。也就是说,如果什么都不做,评论系统早晚会变成摆设。

所以今天来捣鼓一下:把旧的 Valine 评论换成 Giscus,新评论走 GitHub Discussions,旧评论则静态归档到页面里。

一开始也看了 Waline、Twikoo 之类的方案。它们都挺好,体验上也更接近 Valine,匿名评论、后台管理、邮件通知这些都能做。

但我这次想优先解决一个问题:别再依赖一个单独的在线数据库服务了

Giscus 的思路很简单:每篇文章对应一个 GitHub Discussion,评论数据就存在 GitHub 里。我的博客本来就部署在 GitHub Pages 上,源码也在 GitHub,评论也放过去,心理负担比较小。

当然它也有缺点:读者必须登录 GitHub 才能评论。这个门槛不算低,但对我这个博客来说可以接受。

准备 GitHub 仓库

Giscus 配置之前,需要先确认三件事:

  1. 仓库是公开的。
  2. 仓库开启了 Discussions。
  3. 安装了 giscus GitHub App。

Discussions 在仓库的 Settings 里打开。giscus App 则去 GitHub Marketplace 或 giscus 官网按提示安装,仓库权限选择当前博客仓库即可。

准备好之后,打开 giscus 的配置页,填入仓库:

1
AemonCao/AemonCao.github.io

页面和 discussion 的映射关系我选的是:

1
Discussion 的标题包含页面的 pathname

原因是 Hexo 的永久链接本来就长这样:

1
2
3
/2020/12/25/whatisthisthing-5/
/2022/08/08/榨干这台NAS第000话-目录结构/
/about/

之前 Valine 导出的评论里,url 字段也是这个格式。用 pathname 作为绑定关系,比完整 URL 更稳。以后即使用了自定义域名,也不会因为域名变了导致评论分裂。

另外我勾选了严格匹配。博客里有很多类似 whatisthisthing-9whatisthisthing-10 这样的标题,严格匹配可以减少 GitHub 搜索匹配错 discussion 的概率。

最后得到的关键配置大概是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script src="https://giscus.app/client.js"
data-repo="AemonCao/AemonCao.github.io"
data-repo-id="MDEwOlJlcG9zaXRvcnkyNDQ1NDY0NjE="
data-category="Announcements"
data-category-id="DIC_kwDODpN7nc4DAA13"
data-mapping="pathname"
data-strict="1"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="bottom"
data-theme="preferred_color_scheme"
data-lang="zh-CN"
data-loading="lazy"
crossorigin="anonymous"
async>
</script>

接入 NexT 主题

我这个博客用的是 Hexo + NexT。当前主题本身内置了 Valine、Gitalk、Disqus 等评论系统,但是没有内置 Giscus。

所以做法是按 NexT 原来的评论注入方式补一个 Giscus。

先在主题配置里关掉 Valine:

1
2
valine:
enable: false

然后新增 Giscus 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
giscus:
enable: true
repo: AemonCao/AemonCao.github.io
repo_id: MDEwOlJlcG9zaXRvcnkyNDQ1NDY0NjE=
category: Announcements
category_id: DIC_kwDODpN7nc4DAA13
mapping: pathname
strict: 1
reactions_enabled: 1
emit_metadata: 0
input_position: bottom
theme: preferred_color_scheme
lang: zh-CN
loading: lazy

主题里再加两个东西:

  1. 一个 filter,用来告诉 NexT:页面上要放一个 #giscus-comments 容器,页面底部还要加载 Giscus 脚本。
  2. 一个 swig 模板,用来真正生成 Giscus 的 <script>

这样每个开启评论的页面底部都会出现 Giscus 评论区。

旧评论怎么办

旧评论不建议直接导入 Giscus。

不是完全不能做,而是导入之后会有几个问题:

  1. 所有旧评论都会变成同一个 GitHub 账号发布。
  2. 原始评论时间不能真正变成 GitHub 评论时间。
  3. 匿名昵称、邮箱、IP、UA 这些 Valine 元数据不适合搬进 GitHub。
  4. 嵌套回复关系也很难做到完全一致。

所以最后我选了一个比较朴素的办法:旧评论静态归档,新评论交给 Giscus

LeanCloud 导出的评论是 JSON streaming 格式,每一行是一条评论。先按 url 分组,然后只保留这些字段:

1
2
3
4
5
6
7
8
{
"id": "5ff983415d6b37098950665c",
"nick": "nathanZheng",
"link": "",
"createdAt": "2021-01-09T10:19:45.434Z",
"replyTo": "",
"content": "我还以为昨天更新了, 原来是修改日期"
}

这些字段不会放进页面:

1
2
3
4
5
ip
mail
ua
ACL
QQAvatar

评论内容也不再原样输出 HTML,而是转成纯文本,再交给模板转义。这样可以避免把旧评论里的用户 HTML 直接塞回页面。

最后把净化后的数据放到:

1
source/_data/old_comments.json

再写一个 helper,通过当前页面的 page.path 找对应的旧评论。如果有旧评论,就在 Giscus 上方渲染一个「历史评论」区域;没有旧评论,就什么也不显示。

最终效果就是:

1
2
3
文章正文
历史评论
Giscus 新评论

验证

改完之后跑一遍:

1
2
pnpm clean
pnpm build

我检查了几个页面:

  1. 有旧评论的文章会显示「历史评论」。
  2. /about/ 这种独立页面也能显示旧评论。
  3. 新文章没有旧评论区,只显示 Giscus。
  4. 生成后的 HTML 里没有旧评论导出里的邮箱和 IP。

这样就算 LeanCloud 到期停服,旧评论也不会丢;新的评论则继续放在 GitHub Discussions 里。

参考