架站筆記

Hexo 留言系統選 giscus:為什麼用 GitHub Discussions,以及完整設定教學

2026-08-09 #Hexo#GitHub#教學#giscus#留言系統

靜態網站有個先天的缺口:沒有後端,就沒有地方存留言。這篇記錄我怎麼幫這個 Hexo 部落格加上留言功能——為什麼在幾個方案中選了 giscus(把留言存進 GitHub Discussions)、它的取捨在哪,以及從零到上線的完整設定步驟,包含主題沒內建支援時要怎麼自己接。

一、靜態網站的留言困境

Hexo 產生的是純 HTML,部署到 Cloudflare Pages 之後就是一堆靜態檔案。留言卻是動態的——需要接收、儲存、讀取,這三件事都需要一個「活著的」後端。

所以所有靜態網站的留言方案,本質上都在回答同一個問題:這個後端由誰來當? 主流答案有三種:

方案 後端是誰 代價
Disqus 第三方商業服務 免費版有廣告、追蹤使用者、載入慢、資料在別人手上
Twikoo / Waline 你自己部署(Vercel + MongoDB 之類) 要維護、要顧資料庫、免費層有額度限制
giscus GitHub Discussions 訪客必須有 GitHub 帳號

二、為什麼我選 giscus

giscus 的核心概念很妙:把 GitHub Discussions 當成留言資料庫。每篇文章對應一則 discussion,訪客在你網站上留的言,其實是發到你指定 repo 的 Discussions 裡。

選它的四個理由:

1. 零後端、零維護、零成本。 這是決定性的。Twikoo 或 Waline 雖然功能更全,但代價是我得多養一個 Vercel 專案和一個 MongoDB Atlas 資料庫——兩個都有免費額度,也都有可能在某天突然出問題、額度用盡、或服務條款變更。giscus 的「後端」是 GitHub,它掛掉的機率比我的部落格本身還低。

2. 資料在自己手上,而且格式開放。 留言就是 GitHub Discussions,你隨時能用網頁看、用 API 匯出、用 gh CLI 操作。相較之下 Disqus 的資料躺在別人的系統裡,匯出還要看它心情。

3. 不追蹤、無廣告。 Disqus 免費版會在你的頁面上塞廣告和追蹤腳本——對一個講技術的部落格來說,這是形象問題也是效能問題。

4. 讀者群契合。 這是最現實的判斷:我寫的是 RAG、Claude Code、Hexo 這類主題,會看到這裡並想留言的人,幾乎必然有 GitHub 帳號。giscus 最大的缺點(要求 GitHub 登入)在我的場景裡幾乎不構成阻力。

什麼時候不該選 giscus

反過來說,如果你的部落格寫的是美食、旅遊、生活記錄,讀者裡有 GitHub 帳號的可能不到一成——那 giscus 的登入門檻會直接讓留言區永遠是空的。那種情況請選 Twikoo 或 Waline,它們支援匿名留言。 工具沒有絕對的好壞,只有適不適合你的讀者。

三、設定教學

步驟 1:準備一個公開 repo 放留言

重點:這個 repo 必須是 public。 giscus 靠訪客的 GitHub 身分去讀寫 Discussions,private repo 一般訪客根本看不到。

如果你的部落格原始碼是私有的(我的就是),開一個獨立的公開 repo 專門放留言是更好的做法——原始碼保持私密,留言公開可讀,兩邊互不影響:

1
2
gh repo create <你的帳號>/blog-comments --public \
--description "Comment threads for my blog (giscus)"

步驟 2:開啟 Discussions 功能

Repo 頁面 → Settings → 往下找到 Features → 勾選 Discussions

或用 CLI 一行搞定:

1
gh api -X PATCH repos/<你的帳號>/blog-comments -f has_discussions=true

步驟 3:安裝 giscus App

github.com/apps/giscusInstall,授權範圍只選剛才那個 repo(不要給整個帳號權限,最小權限原則)。

這步不能用 CLI 代勞,必須在瀏覽器完成——它是 GitHub App 的授權流程。

步驟 4:取得設定參數

giscus.app 填入 repo 名稱,網頁會自動幫你產生設定並顯示一段 <script>。你需要裡面四個值:data-repodata-repo-iddata-categorydata-category-id

如果你跟我一樣偏好在終端機解決,用 GraphQL API 直接查:

1
2
3
4
5
6
7
gh api graphql -f query='
query {
repository(owner: "<你的帳號>", name: "blog-comments") {
id
discussionCategories(first: 10) { nodes { id name } }
}
}'

回傳的 repository.idR_kgDO... 開頭)就是 repo_id,選一個分類(我用 Announcements,因為它預設只有維護者能開新討論串,比較不會被灌垃圾)的 idDIC_kwDO... 開頭)就是 category_id

步驟 5:接進 Hexo 主題

接下來分兩種情況。

情況 A:主題已內建 giscus 支援(NexT、Butterfly、Fluid 等多數熱門主題都有)——直接在主題設定檔填入參數就好:

1
2
3
4
5
6
giscus:
enable: true
repo: yourname/blog-comments
repo_id: R_kgDO...
category: Announcements
category_id: DIC_kwDO...

情況 B:主題沒有支援(我的 FlatPaper 只內建 Twikoo 和 Artalk)——自己加一段 partial。在主題的 layout/_partial/ 底下找到留言相關的檔案,加入 giscus 的分支:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="giscus"></div>
<script src="https://giscus.app/client.js"
data-repo="<%= gs.repo %>"
data-repo-id="<%= gs.repo_id %>"
data-category="<%= gs.category %>"
data-category-id="<%= gs.category_id %>"
data-mapping="pathname"
data-strict="1"
data-reactions-enabled="1"
data-input-position="top"
data-theme="preferred_color_scheme"
data-lang="zh-TW"
data-loading="lazy"
crossorigin="anonymous"
async>
</script>

幾個參數值得說明:

  • data-mapping="pathname":用文章路徑對應 discussion。比 url 好——之後換網域,留言不會因為網址變了而全部對不上。
  • data-strict="1":嚴格比對,避免路徑相近的文章共用同一則討論串。
  • data-lang="zh-TW":留言區介面用繁體中文。
  • data-loading="lazy":捲到留言區才載入,不拖慢首屏。

步驟 6(進階):讓留言區跟著網站切換深淺色

giscus 是嵌在 iframe 裡的,你網站的深色模式切換影響不到它。結果就是:網站切成深色,留言區還是刺眼的白色。

解法是用 postMessage 通知 iframe 換主題。我的做法是監聽網站根元素的 class 變化(我的主題用 .dark-mode 表示深色),變動時把新主題送進去:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(function () {
function giscusTheme() {
return document.documentElement.classList.contains('dark-mode') ? 'dark' : 'light';
}
function syncGiscus() {
var frame = document.querySelector('iframe.giscus-frame');
if (!frame) return;
frame.contentWindow.postMessage(
{ giscus: { setConfig: { theme: giscusTheme() } } },
'https://giscus.app'
);
}
// 網站切換深淺色時同步
new MutationObserver(syncGiscus).observe(document.documentElement, {
attributes: true, attributeFilter: ['class']
});
// giscus 載入完成後也同步一次(否則初始狀態可能不對)
window.addEventListener('message', function (ev) {
if (ev.origin === 'https://giscus.app') syncGiscus();
});
})();

第二個監聽器容易被忽略但很重要:iframe 是非同步載入的,如果只在切換時同步,第一次載入的主題會是錯的

四、幾個實務細節

留言區只在文章頁出現。 首頁、分類頁、標籤頁不需要留言。多數主題的留言 partial 都有 is_post() 之類的判斷,自己接的話記得加上,否則首頁會被塞一堆 iframe。

單篇關閉留言:在該篇文章的 front-matter 加 comments: false 即可。

第一則留言才會建立討論串。 部署完成後你看到的是空的留言框——這是正常的。giscus 採 lazy 建立,等第一個人留言時才會在 Discussions 開對應的討論串。想自己測試的話,去自己的文章底下留一則就看得到了。

通知會進 GitHub。 有人留言時,你會收到 GitHub 的通知(跟 issue 一樣)。想關掉就到那個 repo 的 Watch 設定調整。

小結

giscus Twikoo / Waline Disqus
後端維護
成本 免費 免費額度內 免費(有廣告)
匿名留言
資料掌控 ✅(GitHub) ✅(自己的 DB)
隱私 無追蹤 無追蹤 有追蹤

我的判斷準則很簡單:技術部落格選 giscus,生活型部落格選 Twikoo。 讀者是誰,決定了哪個門檻可以接受。

如果你正好也在用 Hexo 架站,這個部落格的建站流程也記錄過——從零到自動部署到 Cloudflare Pages。歡迎在下面留言(正好可以順便測試 giscus 有沒有裝好 🙂)。

Creative Commons 姓名標示 非商業性

本文採用 CC BY-NC 4.0 授權

歡迎轉載與引用,請標明出處(Hexo 留言系統選 giscus:為什麼用 GitHub Discussions,以及完整設定教學 — mur mur);禁止用於商業用途。

商業使用或合作提案,歡迎來信洽談:murmur20260202@gmail.com

留言
分享

留言