FE Day 1 系列導覽:後端工程師的前端地圖
執行需求:CPU 可跑。今天是「前端開發實戰:React 與 Next.js 全套」系列的第一篇,我們不急著寫複雜畫面,先把整個四十五天的全貌攤開。讀完之後,你會知道這個系列為什麼選擇 React 與 Next.js 作為主線、每一天會走到哪裡、版本怎麼對齊,也會拿到一個能在本機直接跑起來的最小 React 元件,作為整趟旅程的起點。整篇閱讀時間約二十五分鐘,動手做大約十五分鐘。
引言
很多寫後端的工程師(包括剛轉職的我)對前端的印象停留在「會切版的人負責的事情」:拿到設計稿,用 HTML 把骨架刻出來,用 CSS 把顏色與間距調好,寫幾段 jQuery 把按鈕接上,這樣就結束了。這種印象在 2015 年之前大致正確,但 2016 年之後,前端的世界已經變得非常不一樣:打包工具從 Grunt、Gulp 換成 Vite、webpack 5;元件框架從 jQuery 換成 React、Vue、Svelte;型別系統從「JavaScript 寫完再說」變成 TypeScript 預設;伺服器端渲染(Server-Side Rendering,SSR)、靜態產生(Static Site Generation,SSG)與邊緣渲染三種策略在同一個框架裡可以自由切換。前端不再是「切版」這麼單純的工作,它已經變成一套完整的軟體工程體系。
這個系列就是為了「後端工程師想跨進前端」設計的。我們假設你已經會 Python 或任何強型別後端語言、會用命令列、理解 HTTP 與 REST 概念——讀過「Python 從入門到 PyTorch 深度學習」、「PyTorch 電腦視覺進階」、「NLP/LLM 應用」與 Web 系列 FastAPI 的讀者都應該已經具備這些前置能力。接下來要帶你從「會呼叫別人的 API」走到「能獨立做出完整前端介面的全端開發者」。整個系列以 React 與 Next.js 為核心,搭配 TypeScript、Tailwind CSS、Vite、Vitest、Playwright 等開源工具,最後用一個貫穿專案「預約管理系統」把所有東西串起來。
這篇會做五件事:第一,解釋後端工程師學前端要跨越的距離;第二,畫出四十五天的學習地圖;第三,列出整個系列會用到的版本基準;第四,給出你的第一個 React 元件(今天就能跑起來);第五,回答「沒有設計背景也能跟完嗎?」這個最常被問到的問題。讀完之後,你應該能用一段話回答「這個系列到底在學什麼」。
從後端到前端:跨越的距離
寫後端時,我們關心的是「資料怎麼存、邏輯怎麼跑、API 怎麼簽」。前端則不一樣:它是一個「在瀏覽器裡跑的程式」,要處理的問題包含「畫面怎麼畫、狀態怎麼存、互動怎麼接、效能怎麼量、無障礙怎麼做」。兩者寫程式的心態截然不同。
寫後端時,我們假設「同一支 API 同時被很多人呼叫」,所以重點在並發、鎖、交易、隔離等級;寫前端時,重點在「同一個畫面要根據狀態重新渲染幾次」,於是放在第一位的是不可變(immutable)資料結構、差異比對(reconciliation)、重渲染控制。後端用 try/except 把例外接住並回 500,前端要把錯誤轉成「給使用者看的訊息」並保留使用者輸入;後端做單元測試時用 pytest 與 fixtures,前端做元件測試時用 Vitest 與 Testing Library;後端用 psql 連線驗證查詢,前端用 React DevTools 觀察元件樹。
這中間的差距,靠的不是單一技巧,而是整套工程紀律:型別系統、元件設計、狀態管理、資料取得、快取策略、測試、部署、維運。本系列就是要把這些紀律一個一個介紹給你,並讓你有機會實際動手做。值得注意的是,前端生態的「解法」變化很快:今天的主流框架三年後未必還是主流,但「狀態管理」、「資料取得」、「測試」這些觀念是跨框架共通的;學會觀念再換框架,比死守某一版語法更有用。
這個系列刻意把所有範例都設計成「可獨立跑」的最小版本。每一支程式都可以直接複製貼上執行,預設使用 Vite 啟動本機開發伺服器(不需要任何外部服務);只有少數幾篇會用到部署平台(FE Day 29、FE Day 41),那幾篇會清楚標示為「需外部服務帳號」,讓沒有雲端帳號的讀者可以選擇跳過或用本機方式替代。這種設計的目標是「讓你從家裡的筆電就能開始學」,而不是「你得先準備好雲端帳號」。
四十五天的學習地圖
整個系列分成九個主題區塊,按「由內而外、由小到大」的順序排列。下表把整體安排攤開來,讓你有心理準備,知道接下來每一天會走到哪裡。
| 區塊 | 天數 | 核心主題 | 代表工具 |
|---|---|---|---|
| 導論 | FE Day 1–2 | 系列地圖、環境、工具鏈 | Node.js 22/24 LTS、pnpm 9、Vite 7 |
| 基礎 | FE Day 3–8 | TypeScript、React 元件、props、state、JSX、樣式 | TypeScript 5.8/5.9、React 19、Tailwind 4 |
| 核心 | FE Day 9–14 | useEffect、自訂 Hook、Context、表單、元件設計、資料取得 | React Hooks、Zod |
| 品質 | FE Day 15–16、25–28 | 測試、結構、效能、圖片、字體、E2E、無障礙 | Vitest 3、Playwright 1.5x、Lighthouse |
| Next.js | FE Day 17–24 | App Router、Server Components、Client Components、Server Actions、認證、SEO、API 路由 | Next.js 15 |
| 上線 | FE Day 29–30 | 部署、監控 | Vercel、自架、Docker |
| 貫穿專案 | FE Day 31–45 | 預約管理系統的設計、骨架、清單頁、流程、後台、串接 FastAPI、部署 | Next.js App Router、Tailwind、Zod |
這張表的重點不是「哪一天要做什麼」,而是「為什麼這個順序」。我們刻意把 TypeScript 放在 FE Day 3 才深入,因為 FE Day 2 才把環境裝好;同樣地,把 Next.js 放在 FE Day 17 才開始,是因為前面十六篇要先讓你熟悉 React 與 TypeScript 的基本語法,否則 Server Components 與 Client Components 的差別會讓你混淆。先建立觀念,再碰框架;先會用工具,再談最佳化;先求能跑,再求能跑好。
章節內部的順序也有邏輯。基礎章節從 TypeScript 型別(FE Day 3)→ 泛型與工具型別(FE Day 4)→ React 元件(FE Day 5)→ state(FE Day 6)→ 渲染模型(FE Day 7)→ 樣式(FE Day 8),正好對應「資料 → 元件 → 互動 → 樣式」的標準前端流程。核心章節按 useEffect(FE Day 9)→ 自訂 Hook(FE Day 10)→ Context(FE Day 11)→ 表單(FE Day 12)→ 元件設計(FE Day 13)→ 資料取得(FE Day 14)排列,讓你每學一個觀念就站在前一個的基礎上往前推。
每篇的閱讀節奏建議
這個系列每篇大概三千五百到五千個中文字,閱讀時間落在二十到三十分鐘之間。如果你是第一次接觸前端,建議每天讀一篇、搭配實際執行文中範例,大概一週可以熟悉一個章節的核心 API。如果你是已經會 React、想往 Next.js 或測試走的進階讀者,可以挑著讀,跳過已經熟悉的章節,直接看你缺的部分。
貫穿專案:預約管理系統
從 FE Day 31 開始,我們會用一個完整的「預約管理系統」把所有學到的東西串起來。系統的前端會直接對接 Web 系列打造的 FastAPI 預約後端(API 契約沿用 Web 系列 Day 35–44 的定義);如果後端沒在跑,前端會用內建的 mock 資料進入離線模式,並在畫面上清楚標示。這個專案的目的不是「交一個能上線的產品」,而是「讓你在做中學的時候有一個真實的脈絡」。後台、角色、token、表單驗證、錯誤處理、無障礙、部署——這些題目全部圍繞同一個預約系統打轉,最後會比「各自寫小範例」記得更深。
版本基準(2026 年 3 月)
前端生態的版本變動很快,這個系列為了讓你的程式碼「明天還能跑」,把版本鎖定在 2026 年 3 月的主流範圍。下表是整個系列會用到的工具與版本:
| 工具 | 版本 | 用途 |
|---|---|---|
| Node.js | 22 LTS / 24 LTS | JavaScript 執行環境 |
| pnpm | 9.x | 套件管理工具 |
| TypeScript | 5.8 / 5.9 | 型別系統 |
| React | 19.x | UI 函式庫 |
| Next.js | 15.x | 全端 React 框架 |
| Tailwind CSS | 4.x | Utility-first CSS 框架 |
| Vite | 6.x / 7.x | 開發伺服器與打包工具 |
| Vitest | 3.x | 單元測試與元件測試 |
| Playwright | 1.5x | 端到端測試 |
| ESLint | 9.x(flat config) | 程式碼風格檢查 |
幾個原則:第一,鎖定「LTS 或穩定版」,不用 Current/Canary 當主力,避免日常被版本問題中斷;第二,Node.js 22 LTS(別名 Jod)與 24 LTS(別名 Krypton)都會用,22 在 2024 年 10 月進入 Active LTS、24 在 2025 年 10 月成為 Active LTS,兩個版本對本系列用到的 API 都足夠;第三,TypeScript 5.8 與 5.9 都會出現,5.9 是 2026 年 3 月當下的最新版;第四,React 19 重點放在 Server Components 與 Server Actions,後續在 Next.js 章節會大量使用;第五,Tailwind CSS 4 的「CSS-first 設定」(不用設定檔,改用 @theme)會從 FE Day 8 開始貫穿。
完整實作:用 Vite 建立你的第一個 React 元件
今天先不寫太多程式碼,目標是「讓 React 在你電腦上跑起來,並寫出第一個會回『Hello』的元件」。先建立專案:
# 用 Vite 7 的 React + TypeScript 範本建立專案
pnpm create vite@latest hello-fe -- --template react-ts
cd hello-fe
# 安裝依賴
pnpm install
# 啟動開發伺服器
pnpm dev
# 輸出:VITE v7.x.x ready in xxx ms
# 輸出:Local: http://localhost:5173/
瀏覽器打開 http://localhost:5173/ 就能看到 Vite 的歡迎畫面。接著把 src/App.tsx 換成我們的第一個元件:
// src/App.tsx
// 第一個 React 元件:用 props 接收名字,渲染一段歡迎訊息
// 後端工程師可以把這支函式理解成「在瀏覽器裡執行的 view function」
type HelloProps = {
name: string;
};
function Hello({ name }: HelloProps) {
// JSX:像 HTML,但不是字串;瀏覽器拿到的是經過編譯的 JS 物件
return <h1 className="text-2xl font-bold">Hello, {name}!</h1>;
}
export default function App() {
// 上層元件決定要把什麼資料傳給下層元件
// 這就是 React 的「單向資料流」:資料從上往下傳
return (
<main className="mx-auto max-w-xl p-8">
<Hello name="後端工程師" />
<p className="mt-4 text-slate-600">
這是你的第一個 React 元件。
明天我們會把 Hello 換成更通用的版型,並學會用 props 傳更多資料。
</p>
</main>
);
}
存檔後瀏覽器會立刻熱重載,看到「Hello, 後端工程師!」字樣。這個範例有三個重點:第一,Hello 是一個「以 props 為輸入、回傳 JSX 為輸出」的純函式(pure function),跟後端寫的 view function 概念相同;第二,className 是 JSX 版的 HTML class 屬性,因為 class 在 JavaScript 是保留字;第三,type HelloProps 用 TypeScript 描述 props 的形狀,這樣呼叫端傳錯型別會立刻被編譯器抓到。
接著看一下 Vite 幫你產生的 src/main.tsx,這是 React 真正「掛上畫面」的地方:
// src/main.tsx
// React 應用的入口:把 App 元件掛到 index.html 的 #root 上
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import "./index.css";
const rootEl = document.getElementById("root");
if (!rootEl) throw new Error("找不到 #root 元素");
createRoot(rootEl).render(
// StrictMode:開發模式下會主動檢查不安全的生命週期、副作用等
<StrictMode>
<App />
</StrictMode>,
);
這支檔案對應到後端的 if __name__ == "__main__":決定「要把哪個元件掛到哪個 DOM 節點」。React 19 之後,入口一律用 createRoot(舊的 ReactDOM.render 在 18 版被標記為棄用)。StrictMode 在開發環境下會把每個元件渲染兩次,幫你抓出「不純」的副作用,正式上線時不會影響效能。
最後看一下 index.html,注意 React 不是「取代 HTML」,而是「在 HTML 提供的根節點上動態產生畫面」:
<!doctype html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hello FE</title>
</head>
<body class="bg-slate-50">
<!-- React 會把元件渲染到這個 div 裡 -->
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
這個結構對應到後端的 app.mount("/", template):HTML 提供容器,React 程式碼負責把容器填滿。script type="module" src="/src/main.tsx" 直接指向 TS 檔案——這是 Vite 的神奇之處,瀏覽器拿到的其實是 Vite 幫你編譯過的版本,但開發時不用先 build 就能改。
為了讓你感受 React 19 的簡潔,下面示範一個「按按鈕打招呼」的小範例。我們會在 FE Day 6 才完整講解 useState,這裡先看一個輪廓:
// src/App.tsx(互動版)
// React 19 + useState 的最小示範:點按鈕切換打招呼與再見
import { useState } from "react";
export default function App() {
// useState 回傳「目前狀態」與「更新狀態的函式」
const [greet, setGreet] = useState(true);
return (
<main className="mx-auto max-w-xl p-8">
<p className="text-xl">
{greet ? "Hello, 後端工程師!" : "再見,明天見。"}
</p>
<button
type="button"
onClick={() => setGreet((v) => !v)}
className="mt-4 rounded bg-slate-900 px-4 py-2 text-sm text-white"
>
切換訊息
</button>
</main>
);
}
這支程式展示 React 最核心的兩個觀念:「元件是函式」、「狀態由 React 管理」。useState(true) 告訴 React「幫我記一個布林值,初始是 true」;按下按鈕時呼叫 setGreet,React 會自動重新渲染元件、把新的 greet 帶回畫面。今天先看過就好,FE Day 6 會把 useState 與事件處理完整展開。
順帶看一下「把後端資料變成清單」會長什麼樣——這對應你熟悉的 Jinja 迴圈:
// src/App.tsx(清單版)
// 示範:在 React 裡把後端的陣列資料渲染成 UI
// 對應到後端就是 Jinja / template 的 for item in items
type Item = { id: number; label: string };
const items: Item[] = [
{ id: 1, label: "建立 Vite 專案" },
{ id: 2, label: "學會 JSX 與 props" },
{ id: 3, label: "進入 React 19 大門" },
];
export default function App() {
return (
<main className="mx-auto max-w-xl p-8">
<h1 className="text-2xl font-bold">今天要做的事</h1>
<ul className="mt-4 list-disc pl-6">
{items.map((item) => (
<li key={item.id}>{item.label}</li>
))}
</ul>
</main>
);
}
這段程式碼先宣告一個 Item 型別,再用 map 把每個條目轉成 li。key={item.id} 是 React 告訴每個節點「你是誰」的方式——FE Day 7 會專門講解,今天先記得「只要在 React 裡 map 出一串同類元素,就要給 key」就好。
最後看一下 vite.config.ts:
// vite.config.ts
// Vite 的設定檔:決定 dev server、build plugin、別名
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
host: true,
},
});
這個檔案對應後端的 app.config:把「整個專案的全域設定」集中在同一個地方。host: true 讓 Vite 監聽所有網路介面(不只是 localhost),這樣在手機或另一台電腦可以用 http://你的區網IP:5173/ 預覽畫面;之後做響應式除錯時會很有用。
常見錯誤與踩雷
第一次把 React 跑起來,最常踩的雷有三個。第一個是「裝錯 Node 版本」。如果用系統內建的 Node(例如 Ubuntu 20.04 預設的 Node 18、或 macOS 舊版的 Node 16),pnpm create vite@latest 會直接失敗或裝出不相容的版本。修法是用 nvm(macOS/Linux)或 fnm(跨平台)切到 22/24 LTS,再重新執行指令。可以用 node -v 確認目前是哪個版本。
第二個是「把 JSX 寫成字串」。很多人第一次看到 JSX 會直覺以為這是 HTML 字串,但其實它是 React 的「元素物件」,瀏覽器不會直接看到這段文字,而是看到 Vite/Babel 編譯出來的 React.createElement(...) 呼叫。如果你把 JSX 用雙引號包起來(例如 return "),瀏覽器只會把字串當文字顯示,不會變成標題。Hello
"
第三個是「props 沒有標型別」。第一版寫 React 的人常會省略 props 型別,等元件長大後再回頭補,結果中間改 props 欄位時找不到呼叫端、也不敢刪舊欄位。建議從一開始就用 type HelloProps = { name: string } 描述形狀,未來要加欄位或拆元件時有完整的契約可以對照。FE Day 3 與 FE Day 4 會把型別系統講完整。
效能與實務提醒
今天的範例只渲染一個標題,談效能有點殺雞用牛刀,但有兩個觀念先記起來比較好。第一,React 的渲染是「把元件函式執行一次、把回傳的 JSX 對應到真實 DOM」的過程;只要 props 或 state 沒變,React 不會重複執行元件函式(這個比對機制叫 reconciliation,FE Day 7 會細談)。第二,Vite 的 dev server 用 esbuild 做預編譯,冷啟動通常遠低於三百毫秒;改檔案後的熱重載(HMR)只更新有變動的模組,不用整頁重整。這兩個特性讓「改程式 → 看結果」的迭代速度比舊的 webpack + CRA 時代快非常多。
實務上,第一次跑 React 的人最容易遇到的「效能」問題其實是「裝太多東西」。很多人會在 pnpm create vite@latest 之後立刻裝 Redux、React Router、styled-components、Axios 全部加上去,結果專案膨脹到第一個畫面要載入數 MB 的 JavaScript。這個系列的建議是「用到再裝」:FE Day 5 之後才會裝 React Router,FE Day 11 才會碰 Context,FE Day 14 才會接資料層。今天裝好 Vite + React + TypeScript 就夠了,剩下的等用到再說。
另一個常見的踩雷是「把 package.json 的 engines 欄位忽略」。當你把專案推上 GitHub、另一個同事 clone 下來之後,他可能裝到跟你不同的 Node 版本,這時候 pnpm install 會出現奇怪的 peer dependency 警告。建議在 package.json 加上 "engines": { "node": ">=22 <25" },並透過 .npmrc 的 engine-strict=true 強制套用。CI 上則可以用 actions/setup-node 綁定版本,從源頭避免「我電腦能跑你電腦不能跑」的經典問題。下面是 Vite 範本生成、加上 engines 之後的 package.json 片段:
{
"name": "hello-fe",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview"
},
"engines": {
"node": ">=22 <25",
"pnpm": ">=9"
},
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@vitejs/plugin-react": "^4.3.0",
"typescript": "^5.9.0",
"vite": "^7.0.0"
}
}
小結
今天我們把整個系列的全貌攤開來了:你會看到後端工程師學前端要跨越的距離、知道四十五天的學習地圖與排序邏輯、鎖定 2026 年 3 月的版本基準、也真的用 Vite + React + TypeScript 跑出了第一個會回「Hello」的元件。接下來 FE Day 2 要把環境正式蓋起來:Node.js LTS、pnpm、TypeScript 編譯器、ESLint 9 的 flat config、VS Code 設定,整套工具鏈一次到位。讀完今天這篇,你應該能用一句話回答「這個系列在學什麼」——React 19 + TypeScript 5.8/5.9 + Next.js 15 + Tailwind 4,從「後端工程師的視角」一路走到能獨立交付一個完整的前後端分離系統。
為了給你一個「這就是前端工程師工作環境」的最後一瞥,這裡補上一個最小可跑的 ESLint 9 設定。ESLint 9 之後改用「扁平設定檔」(flat config),把所有設定合併成一個陣列匯出:
// eslint.config.js
// ESLint 9 扁平設定檔:把多份設定合併成一個陣列
import js from "@eslint/js";
import tseslint from "typescript-eslint";
import reactPlugin from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
export default [
// 先套用社群推薦的基礎規則
js.configs.recommended,
// 加上 TypeScript 與 React Hooks 規則
...tseslint.configs.recommended,
{
files: ["**/*.{ts,tsx}"],
plugins: {
react: reactPlugin,
"react-hooks": reactHooks,
},
languageOptions: {
// React 19 全域變數(例如 JSX 命名空間)
globals: { ...reactPlugin.configs.flat.recommended.languageOptions.globals },
},
rules: {
// 確保每個 useEffect 的依賴都有列在陣列裡
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
},
},
];
結語
明天,我們會把開發環境正式「蓋起來」:裝好 Node.js 22/24 LTS、用 Corepack 啟用 pnpm 9、設定 TypeScript 5.8/5.9 的 tsconfig.json、把 ESLint 9 的 flat config 寫成可以照抄的範本、裝好 VS Code 與 React 相關的擴充套件。FE Day 2 結束時,你的電腦就會是一個「前端工程師的標準工作環境」,後續四十三篇的所有範例都能直接照著做。記得今天那個 hello-fe 專案先留著,明天會在同一個專案上把 ESLint、TypeScript 嚴格模式與資料夾結構補完。
延伸資源
- React 官方〈Quick Start〉(19.x,2026 年 3 月):
https://react.dev/learn - Vite 官方〈Getting Started〉(7.x):
https://vite.dev/guide/ - MDN〈Introduction to the DOM〉:
https://developer.mozilla.org/zh-TW/docs/Web/API/Document_Object_Model/Introduction - TypeScript Handbook〈The Basics〉(5.9):
https://www.typescriptlang.org/docs/handbook/2/basic-types.html - Node.js Release 工作表(22 LTS / 24 LTS):
https://nodejs.org/en/about/previous-releases
留言
張貼留言