關於本站

本站是 Bojin Li 的個人網站。

歷史

年份

技術棧

2019

GitHub Pages + Jekyll + Disqus,Huxpro 佈景主題

2020

Vercel + Jekyll + Disqus,Huxpro 佈景主題

2021

Vercel + React 17 + Tailwind CSS + Vite + TypeScript

2022

Vercel + Next.js 12 + Notion API + Giscus + p5 + three.js

2024

Vercel + Next.js 14/15 + Tailwind CSS + shadcn/ui

2026(目前版本,Haku)

Cloudflare Workers + TanStack Start + Vite + Tailwind CSS + Durable Objects

關於 Haku

Haku 參考自 Yohaku,延續了 Yohaku 對閱讀的重視,包括留白、紙張與細節動效帶來的感受,也有著同樣完善的富文本文章呈現。至於 Haku 這個名字,一方面保留了 Yohaku 的一部分;另一方面,Haku 在日語裡,恰好也是我名字中「帛」字的讀音。

Yohaku 以 Next.js 為基礎,而本站最終部署在 Cloudflare Workers 上,也需要盡可能針對中國大陸特殊的網路環境進行最佳化。因此,本站採用了 TanStack Start、TanStack Router 和 Vite,並引入 Durable Objects,這樣就能在 Worker 上盡可能深入底層地最佳化 SSR 效能,也避開 Next.js 的龐大體積,以及它在非 Vercel 平台上的不確定性。

後端方面,Yohaku 配套的許多功能本站用不上,而 Haku 又有不少自己的客製化與最佳化,所以參考 Yohaku 重寫了一套 CMS,在協定上盡可能與 Yohaku 配套的 mx-space 保持一致。

整體架構

在 monorepo 裡,分成 Web、Core、Admin 三個應用程式。

應用程式

職責

技術

部署

Web

公開網站,包括首頁、文章與獨立頁面

React、TanStack Start / Router、Vite、Tailwind CSS

Cloudflare Workers

Core

內容、媒體、身分、留言等後端服務

NestJS、Fastify、Drizzle、PostgreSQL、Redis

自建伺服器,由 Dokploy 管理

Admin

內容管理後台

React、Vite、CodeMirror、Haklex / Lexical

自建伺服器,由 Dokploy 管理

Mermaid diagram

三個應用程式透過共用的 TypeScript 與 Zod 契約對接,也會在請求與回應的邊界上驗證資料。

伺服器端渲染

Haku 使用伺服器端渲染。第一次開啟頁面時,Worker 會先依照路由與語言取得所需資料,產生帶有內容的 HTML,再以串流方式傳給瀏覽器,讓讀者不用等腳本載入完畢,就能先看到內容。

接著,瀏覽器會進行 hydration,接管伺服器已經產生好的頁面,讓導覽、選單、留言等互動開始運作。之後的站內跳轉由 TanStack Router 處理,只按需讀取下一個頁面需要的資料,不必每次重新載入整份文件。

Mermaid diagram

為了讓伺服器端渲染與瀏覽器接管順利銜接,每個伺服器請求都有獨立的 Router、QueryClient 和 Jotai store,瀏覽器裡也各有一份,因此不同讀者的資料不會混在一起。進場動畫則隨著路由處理:首次開啟、一般跳轉與上一頁/下一頁的還原各有各的行為;預先擷取資料或在背景更新時,頁面也不會無故重播動畫。

快取

網站設定、導覽資訊與首頁的各種彙總,對所有讀者都相同,因此適合共用。它們會以公開快照的形式保存在 Cloudflare 的 Durable Objects 裡,同一份資料的並行讀取會合併為一次。快照過期後,會先將保留的舊內容回傳給讀者,同時在背景更新(stale-while-revalidate),減少等待。發布新內容後,舊快照會被標記為過期;快取更新也有版本檢查,較早發起的請求即使較晚完成,也不能把舊資料寫回去覆蓋新資料。

文章正文不進入這層共用快取,每次都從已發布的內容讀取;HTML 與伺服器函式的回應也維持私有。

首頁展示的活動與統計資料也是相同的思路,由後端定期彙總。讀者開啟首頁時,不必臨時請求外部服務;外部服務偶爾慢一點,也不會拖慢正文閱讀。

載入速度最佳化

Haku 在載入速度上做了這些處理。

  • 盡可能縮小網站啟動資料,只傳送導覽與目前頁面所需的資訊,不夾帶無關頁面的內容。
  • 銜接路由的 loader 與查詢快取,減少同一次導覽中的重複讀取。
  • 富文本、地圖與 3D 等較重的相依套件,依使用情境拆分,需要時才載入。
  • 提前準備正文使用的字型、語言與渲染模組,避免重新整理及 hydration 時出現不一致。
  • 為背景與 3D 動效安排排程,頁面隱藏或讀者啟用減少動態效果時,暫停或改為靜態,盡量不占用閱讀所需的資源。

此外,Haku 在 Chrome 開發人員工具的受限網路模式下反覆測試 SSR 與首屏,也引入 Sentry,協助定位線上錯誤與效能問題。

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...