

網站開發
一個基於 Turborepo monorepo 架構的雙網域作品集,採用 Next.js 打造,並整合了檔案式 CMS、Obsidian 風格知識圖譜與共享元件庫。
年份
2025
角色
設計師與開發者
技術
Next.js, React, TypeScript, TailwindCSS
這個專案是一個現代化、高效能的平台,設計上能透過單一、統一的程式碼庫,同時運行 harrychang.me 和 lab.harrychang.me 兩個不同的網域。專案採用 Turborepo monorepo 架構,有效管理多個 Next.js 應用程式。選擇此架構是為了簡化開發流程,讓我能在主要作品集與實驗性網站之間共享程式碼,同時也為我姐姐的個人網站 emilychang.me 的開發提供支援。
主要作品集的核心,是一套客製化的 Markdown 內容管理系統。這套架構會在網站 build 階段,直接解析共用的 content/ 目錄中的 Markdown 檔案來生成靜態頁面。這讓主網站不需依賴傳統資料庫,達成了高效能且易於維護的成果。
前端採用 React 與 TypeScript 開發,確保了程式碼庫的穩健性與型別安全。使用者介面則用 TailwindCSS,透過它 utility-first 的特性,實現了快速開發。網站的三欄式版面設計,靈感來自 Joseph Zhang 的作品集。
這個專案的心臟是它極具彈性的架構。透過 Next.js 的 middleware,系統能根據不同的 subdomain 動態重寫請求,將使用者導向主要作品集或實驗性網站,而這一切都由同一個 Next.js 應用程式驅動。主要作品集的內容以 Markdown 檔案形式儲存,使其扮演了一個 Headless CMS 的角色。一個客製化程式會透過以下幾個關鍵函式庫來處理這些檔案:
gray-matter:用於解析每個檔案頭部的 YAML frontmatter,來提取 metadata。remark 與 remark-html:將 Markdown 內容轉換為 HTML,以便在網頁上渲染。這樣的架構將內容與呈現方式完全分離,讓更新網站內容就像操作 Git 一樣簡單。
在開發過程中,我特別著重於網站的效能、擴展性與功能的實現。
Monorepo 的高效率:透過 Turborepo,我們能將共用的 UI 元件、Hooks 與工具函式集中於 packages/ui 和 packages/lib,讓多個應用程式共享。這大幅減少了重複的程式碼,並簡化了依賴管理。
靜態與動態渲染:主要作品集採用靜態網站生成(SSG)以追求效能。所有頁面都在建置階段預先渲染完成,結合 Next.js 自動化的 code-splitting,確保了最快的載入速度。實驗性網站則採用動態渲染,以支援由資料庫驅動的功能。
動態媒體處理:我開發了一個名為 transformMedia 的客製化 Remark 插件,用來智慧地處理不同類型的媒體。它會遍歷 Markdown 結構,自動嵌入帶有自訂預覽圖的 YouTube 和 Google Drive 影片,同時將標準的圖片標籤轉換為優化過的 figure 元素,具備延遲載入與微光載入動畫。
圖片最佳化:透過 Scripting,自動將圖片轉換為現代的 WebP 格式並調整尺寸,同時產生低解析度的圖片預覽圖,用來實現模糊載入的視覺效果。
API 整合:頁尾整合了即時的「音樂播放中」元件,透過 Spotify API 取得我目前的聽歌狀態,並以客製化的動畫進度卡片呈現。
國際化(i18n):網站透過客製化的客戶端 React Context,完整支援英文與繁體中文。內容是依據檔案後綴(_zh-tw.md)進行本地化,當特定內容的中文版本不存在時,網站會自動顯示英文版本。
受 Obsidian 的圖譜檢視啟發,網站內建了一個互動式知識圖譜,將所有內容——專案、部落格文章、攝影作品與論文——之間的關聯以視覺化方式呈現。以 D3.js 力導向模擬為基礎並透過 HTML5 Canvas 渲染,節點之間透過共同標籤、分類以及離線 Embedding 管線所生成的語意相似度進行連結。
完整的圖譜可在 /graph 專屬頁面存取,支援分類篩選、行動裝置最佳化的節點卡片,以及跟隨游標的預覽提示框。精簡版的嵌入式圖譜則驅動了每個內容頁面中的「接下來」卡片,顯示局部鄰近子圖以呈現相關內容,鼓勵使用者進一步探索。
這個作品集旨在展示多元的作品與想法。
本站的原始程式碼已開源於 GitHub,並採用 CC BY-NC 4.0 授權。網站內所有文字與圖片內容則保留版權。