開發工具 · 個人作品集

個人作品集網站

用 Next.js 16 + React 19 從零打造的作品集網站,JSON 資料驅動架構,所有內容與展示層完全分離。

使用的技術

Next.js 16React 19TypeScriptTailwind CSS v4JSON Data-Driven

🤔 為什麼要自己寫作品集網站?

市面上作品集模板很多,但大多千篇一律 — 換個顏色、塞點內容就跟別人長得一樣。 我想做一個真正屬於自己的網站:從架構到每一個 CSS 動畫都自己決定。

更重要的是,作品集本身就是一個作品。它不只是展示專案的櫥窗,更是我對前端技術理解程度的直接證明。

🏗️ 架構設計:JSON 資料驅動

整個網站最核心的設計決策:資料與展示完全分離

所有內容(關於我、專案、經歷、教育、技能、證照)都存放在 content/ 資料夾的 JSON 檔案裡。 頁面元件只負責讀取 JSON 然後渲染 — 改內容不需要碰任何代碼

content/
├── about.json            # 個人資料、社群連結
├── projects.json         # 所有專案(含分類、技術標籤)
├── experience.json       # 工作經歷
├── education.json        # 學歷
├── skills.json           # 技能分類
└── certifications.json   # 證照

這個架構帶來的好處非常明顯:

  • 新增專案:編輯 JSON → 完事。不需要建新頁面或改路由。
  • 改履歷:修改對應 JSON 欄位,網站即時更新。
  • 多語言友好:未來只要加一組翻譯 JSON 就能支援英文版。
  • 版本控制:JSON 是純文字,git diff 一目了然。

📂 專案分類系統

專案數量變多後,扁平列表已經不夠用。我設計了一個分類系統,每個專案帶有 category 標籤, 前端按分類渲染成獨立區塊,每個分類有各自的圖示、配色和漸層風格:

🤖AI / 機器學習
🌐基礎設施 / 網絡
🎓教學 / 設計
📝實戰經驗
💻開發工具

這樣訪客可以快速找到感興趣的領域,不會被一堆專案淹沒。

🎨 視覺設計心得

🌈
漸層卡片系統
每張專案卡片用不同漸層色,按分類分配色系。這不是隨機的 — AI 專案偏藍紫、基礎設施偏綠、教學偏粉紅,讓人一看顏色就知道是哪類。
微互動動畫
背景的浮動粒子、hover 時的陰影加深與文字位移、按鈕的漸層移動 — 這些小細節讓網站不會覺得「死」。用 CSS animation + Tailwind group-hover 實現,不需要 JS 動畫庫。
🔍
Noise 紋理覆蓋
全頁覆蓋了一層極淡(opacity 1.5%)的 SVG noise 紋理。這是很多高質感設計網站的做法 — 讓純色背景有一點「顆粒感」,不會太乾淨而顯得廉價。
📐
Geist 字型系統
使用 Vercel 的 Geist Sans + Geist Mono,搭配系統字型備選。這組字型乾淨現代,而且在 Next.js 裡可以透過 next/font 自動優化,零佈局偏移。

💣 踩過的坑

坑 #1專案詳情頁忘了建
projects.json 裡設了 url: "/projects/slug",但忘了建對應的 app/projects/slug/page.tsx。點「查看詳情」直接 404。這個錯犯了兩次才學乖。
坑 #2Tailwind v4 的變化
Tailwind v4 引入了新的 CSS-first 配置方式,跟 v3 的 tailwind.config.js 完全不同。一開始用 v3 的寫法怎麼都不生效,花了些時間才搞懂。
坑 #3Next.js App Router 的學習曲線
從 Pages Router 轉到 App Router 需要重新理解很多概念:Server Components vs Client Components、文件約定路由、layout 嵌套機制。值得,但初期確實踩了不少坑。

⚡ 技術棧為什麼這樣選

Next.js 16 + React 19

App Router 的 RSC(React Server Components)讓整個首頁可以在伺服器端渲染,零客戶端 JS。 讀 JSON 檔案這種 IO 操作直接在 Server Component 裡用 fs.readFileSync,簡單粗暴又高效。

Tailwind CSS v4

Utility-first 的開發方式讓我可以在 TSX 裡直接寫樣式,不需要額外的 CSS 檔案。 v4 的 CSS-first 配置讓自定義 theme 變得更直覺。

TypeScript(嚴格模式)

JSON 資料有明確的 interface 定義(Project、About、Experience...), 改 JSON 結構時 TypeScript 會立刻提醒哪些元件需要同步更新。重構時的安全網。

🗂️ 完整目錄結構

app/
├── layout.tsx                    # 全域佈局(Header + Footer + 字型)
├── page.tsx                      # 首頁(組裝所有 Section 元件)
├── globals.css                   # 全域樣式、動畫、noise 紋理
└── projects/
    ├── vm-lobster/page.tsx       # 各專案詳情頁
    ├── exam-generator/page.tsx
    ├── tailscale-exit-node/page.tsx
    └── ...

components/
├── layout/                       # Header, Footer
├── sections/                     # Hero, Projects, Experience, Education, Skills
└── ui/                           # Button, Section(通用容器)

content/                          # ← 所有資料在這裡
├── about.json
├── projects.json
├── experience.json
├── education.json
├── skills.json
└── certifications.json

lib/
└── data.ts                       # JSON 讀取函數 + TypeScript 型別定義

🚀 部署流程:從本機到公網

網站開發完成後,要讓外面能訪問,需要三層配置:

1Next.js 靜態匯出 + 啟動
npm run build 編譯後,以 npm start(Node.js 伺服器模式)在局域網主機上啟動,默認監聽 localhost:3000
2端口映射(Port Forwarding)
在路由器上設定端口映射,將公網的特定端口轉發到內網主機的 :3000。這樣外部流量才能穿過 NAT 到達 Next.js 伺服器。
3反向代理(Nginx Proxy Manager)
使用 Nginx Proxy Manager 作為反向代理,將自定義域名(如 self.hachimi.qzz.io)指向內網的 Next.js 服務。同時啟用 SSL(Let's Encrypt 自動證書),讓網站走 HTTPS。
4DNS 解析(Cloudflare)
在 Cloudflare 設定域名 A 記錄,指向家用寬頻的公網 IP。搭配 DDNS 解決動態 IP 問題,確保域名始終指向正確的伺服器。
🔗
請求流程
用戶瀏覽器 → Cloudflare DNS → 家用公網 IP → 路由器端口映射 → Nginx Proxy Manager(SSL 終止 + 反向代理)→ Next.js :3000

🚀 未來規劃

🌍
多語言支援
繁中 + 英文切換,JSON 架構已經準備好了
📊
文章/部落格區
用 MDX 寫技術文章,整合到現有架構
🌙
深色模式
CSS 變數已預留,等有空補上切換邏輯
更多動畫
滾動觸發的淡入動畫,讓瀏覽體驗更流暢