回歸 Web 1.0 的去中心化精神:我的「聯邦式」部落格架構 (The Blog Federation)
在軟體架構的世界裡,我們常說「合久必分,分久必合」。在經歷了多年使用單一 CMS 或大型單體框架(Monolith)來管理所有內容後,我決定在 2025 年做一個大膽的實驗:將部落格「聯邦化」。
這個架構轉變的核心,不在於追求最新的技術,而在於解決最古老的痛點:耦合(Coupling)與維護成本。
為什麼選擇「聯邦式」架構?
過去我們習慣把所有文章——無論是 2015 年的舊文還是 2025 年的新作——都塞進同一個專案、同一個資料庫。這導致了幾個問題:
- 技術債累積:想升級框架版本時,必須拖著十年的舊內容一起跑。
- 技術鎖定:如果我想用最新的 Astro 寫新文章,但舊站是用 Next.js 寫的,遷移成本極高。
我的解決方案是:基於子網域的去中心化架構。
a24c.citrine.top:2024 年的內容 (Astro)n25a.citrine.top:2025 年的內容 (Next.js)...
每個子站點都是獨立的「小宇宙」,可以使用當下最適合的技術棧。但隨之而來的問題是:如何讓使用者在一個入口網站(Main Site)看到所有內容?
這就是回歸 Web 1.0 精神的時刻:使用最簡單的標準協議 —— RSS。
架構核心:主站作為「聚合器 (Aggregator)」
在這個架構中,主站(Landing Page)的角色不再是「資料庫管理者」,而是一個「訂閱者」。它不擁有內容,它只是負責聚合(Aggregate)內容。
其實作邏輯非常優雅且低成本,完全不需要複雜的 API 對接或跨站資料庫連線,僅依賴以下三個步驟:
1. 協議層:每個子站必須吐出 rss.xml
這是整個聯邦唯一的「硬性規定」。無論子站是用 Astro、Next.js 還是 Eleventy,只要它能生成一個標準的 RSS Feed,它就能加入這個聯邦。
這實現了完美的解耦:主站根本不在乎子站是用什麼寫的,它只認 XML。
2. 應用層:主站的構建 (Build Time Aggregation)
為了保持極致的效能與 SEO,我選擇 Astro 作為主要入口網站的框架。Astro 強大的 Data Fetching 能力,讓我可以在「建置時間 (Build Time)」完成所有 RSS 的抓取與混合。
這意味著,當使用者訪問主站時,他們看到的是一份已經排序好的、純靜態的 HTML,不需要在瀏覽器端等待 JavaScript 去抓取 XML,速度飛快。
核心程式碼邏輯如下(使用 rss-parser):
import Parser from "rss-parser";
// 定義聯邦子站點
const SUBDOMAINS = [
{
label: "Next.js 2025 (A)",
url: "https://n25a.citrine.top/rss.xml",
tag: "n25a",
},
{
label: "Astro 2024 (C)",
url: "https://a24c.citrine.top/rss.xml",
tag: "a24c",
},
];
const parser = new Parser();
// 並發抓取所有站點的 RSS
const results = await Promise.allSettled(
SUBDOMAINS.map(async (site) => {
try {
const feed = await parser.parseURL(site.url);
return feed.items.map((item) => ({
...item,
sourceLabel: site.label, // 標記來源
}));
} catch (error) {
return []; // 容錯設計:某個子站掛了不影響主站存活
}
})
);
// 合併並按時間倒序排列
let allPosts = [];
results.forEach((result) => {
if (result.status === "fulfilled") allPosts.push(...result.value);
});
allPosts.sort((a, b) => new Date(b.pubDate) - new Date(a.pubDate));
3. 自動化層:Deploy Hooks 閉環
因為主站是靜態生成的,如果子站發了新文章,主站怎麼知道要更新?
這時我們利用 Cloudflare Pages (或 Vercel) 的 Deploy Hooks。
- 在主站設定一個 Hook URL(例如:
api.cloudflare.com/.../trigger)。 - 在子站的部署流程(CI/CD)完成後,自動發送一個
curl請求去觸發這個 URL。
這樣就形成了一個自動化的閉環:
子站發布 -> 觸發 Hook -> 主站重新建置 (Rebuild) -> 抓取最新 RSS -> 首頁更新。
搜尋問題的解答
既然內容分散在不同子網域,搜尋怎麼辦?如果要自己做跨站索引,會大幅增加維護成本。
既然我們走的是 Web 1.0 風格,最好的解法就是 Google Programmable Search Engine (CSE)。
設定搜尋範圍為 *.citrine.top,讓 Google 的爬蟲幫我們做全文檢索。這雖然犧牲了一點樣式客製化的自由度,但換來的是零維護成本與強大的搜尋能力。
結語
這個架構的最大優勢在於**「進可攻,退可守」**。
- 低成本:全部都是靜態站點,託管費用趨近於零。
- 低維護:2024 年的網站如果不改版,就永遠不需要動它,也不用擔心 npm 套件升級把站點搞壞。
- 高自由:明年如果有新的框架問世,我直接開一個
n26.citrine.top就能馬上嘗試,完全沒有包袱。
用最簡單的技術(HTTP + HTML + RSS)解決最複雜的問題,這就是我心中理想的現代化架構。