React 前端 是做什麼的?
適用於每個 React 前端的規則。此檔案記錄了始終適用的準則;在處理該主題之前,請先閱讀對應的參考文件。
| 工作項目 | 閱讀文件 |
|---|---|
| 資料夾、層級、切片、公開 API、匯入、匯總檔案 | references/structure.md |
| FSD 深入探討:決策樹、跨匯入、實體、資產、認證/API 放置、框架接線、遷移 | references/fsd/ (索引在 structure.md 結尾) |
| 命名、檔案大小、Props、設計系統、佈局、常數 | references/code-style.md |
| 元件、Hook、Effect、記憶化、Transition、長列表、水合 | references/hooks-and-rendering.md |
| 瀑布流、Bundle 大小、程式碼分割、預載入、重新渲染成本 | references/performance.md |
| 伺服器資料、查詢、變更、Loader、搜尋參數、Zustand | references/data-and-state.md |
| 表單、驗證、表單錯誤 | references/forms.md |
| 語意、鍵盤、焦點、對比、即時區域、無障礙測試 | references/accessibility.md (React 實作) + frontend-accessibility 技能 (完整規則、稽核) |
| 單元測試、元件測試與 E2E 測試、覆蓋率、API 模擬 | references/testing.md |
| Stories、Storybook 無障礙檢查、視覺回歸 | references/storybook.md |
| XSS、渲染 HTML/Markdown/LLM 輸出、認證、CSRF、CSP、環境變數、登出 | references/security.md |
| Node 版本、套件管理器、pre-commit + gitleaks、相依性稽核 | references/tooling.md |
翻譯、語言切換、<html lang> | references/i18n.md |
| 建立新專案 | references/setup.md |
| 前端的容器映像 | references/docker.md + docker-kubernetes 技能 |
技術堆疊
- React 19 (≥ 19.2 以使用
useEffectEvent和<Activity>) · TypeScript 嚴格模式 - 渲染方式:Vite SPA 或 React Router 框架模式 (SSR + 水合)。標示 React Router framework only 的規則僅適用於該模式。無 Next.js、無 React Server Components、無 SWR。
- 路由:TanStack Router 或 React Router — 每個專案固定其一,請從程式碼中偵測,切勿混用。
- 伺服器狀態:TanStack Query · 客戶端狀態:Zustand
- 表單:React Hook Form + Zod 或 TanStack Form + Zod — 每個專案固定其一
- 驗證:在每個邊界使用 Zod (API 回應、表單、搜尋參數、環境變數、儲存、
postMessage) - 工具:Biome (lint + format)、Steiger (FSD 規則)、Vitest + Testing Library、Playwright、Storybook
- 無 React Compiler → 記憶化需手動進行,但僅在測量之後。
結構 — Feature-Sliced Design
層級 app → pages → widgets → features → entities → shared;僅允許向下匯入;同一層級的切片之間禁止匯入;每個切片僅透過其 index.ts 匯入,並使用明確的具名匯出 (禁止 export *)。shared/ui 和 shared/lib 每個元件/函式庫各有一個索引。從 app、pages、shared 開始;不要有空層級資料夾。程式碼應留在頁面中,直到滿足提取規則 — 目前在多處使用、有獨立於任何使用者的變更原因、有集中的職責;三者皆滿足才提取,在此之前允許重複。widgets 不鼓勵使用:僅用於跨多個頁面重用且無法放在頁面中的組合區塊 (現有 widgets 仍有效)。詳情請見 references/structure.md,上游規則集 references/fsd/rules.md。
- 每個檔案一個元件,每個檔案一個 Hook,每個元件約 150 行;元件以所屬切片名稱作為前綴 (
references/code-style.md)。 - 優先使用設計系統:使用
shared/ui/中的自有元件;切勿在shared/ui/外部匯入shared/ui/primitives/(UI 函式庫 CLI 產出,不可編輯)。在檢查設計系統的元件、Props 和 Token 能提供什麼之前,不要加入新的 CSS。
元件和 Hook — 始終遵守
- 切勿在另一個元件內部定義元件 — 這會導致每次渲染都重新掛載。
- 推導,不要同步:可從 props/state 計算得出的值應在渲染期間計算。不要使用
useEffect來將 props 或 state 複製到 state 中。使用key來重置。 - 使用者操作應在事件處理常式中執行,而不是在由狀態標誌觸發的 effect 中執行。
- Effect 僅用於與外部系統同步,應具有狹窄的基本型別依賴、每個 effect 只處理一個關注點,並包含清理函式。切勿關閉 exhaustive-deps 規則。
- 當下一個值依賴於前一個值時,使用
setState(prev => …);對於昂貴的初始值,使用useState(() => expensive())。 - 切勿變異 props 或 state:使用
toSorted()、toReversed()、toSpliced()、with()、展開運算子。 - 使用
{count > 0 ? <X /> : null}— 切勿在左側使用數字搭配&&。 - 不要在
useEffect中使用fetch;伺服器資料應來自 TanStack Query 或路由 loader。 memo/useMemo/useCallback僅在分析之後或需要參考穩定性時使用。- 絕不忽略錯誤:沒有空的
catch,沒有.catch(() => {})。每個路由都應有錯誤邊界;每個查詢都應有載入中、錯誤和空資料的 UI。
資料和狀態 — 始終遵守
- 請求函式 → Hook → 元件。 HTTP 僅透過
shared/api/中的客戶端進行;切勿在 Hook 或元件中匯入 HTTP 客戶端。 - 伺服器資料僅存在於 TanStack Query 中,透過查詢鍵工廠搭配
queryOptions;回應在請求函式中使用 Zod 解析。 - 單純的資源存取、CRUD 和查詢鍵工廠位於
shared/api(或獨佔使用它們的頁面/功能);entities/<x>/api僅用於包含領域規則或該實體映射的請求。 - 變更會使所有受影響的查詢失效 (或更新)。
- URL 狀態 (篩選、排序、分頁、頁籤) 存在於經過型別、Zod 驗證的搜尋參數中 — 切勿手動從
window.location解析。 - Zustand 僅用於共享的客戶端狀態;一律透過 selector 存取;持久化 store 應使用
version、migrate和partialize,且不包含敏感資料。 - 在路由 loader 中 (使用
queryClient.query({ ...options, staleTime: 'static' }),以前是ensureQueryData) 並且平行載入路由資料,而不是在巢狀元件中逐一載入。
無障礙 — 內建,而非後續補上
目標:WCAG 2.2 AA。是每個元件和頁面「完成定義」的一部分。frontend-accessibility 技能包含完整的規則和稽核程序 — 每次 UI 變更時都應載入。
- 優先使用語意化 HTML:動作使用
<button>,導航使用<a>/<Link>,每個欄位使用<label>,使用地標,一個<h1>和有序的標題。僅在沒有合適的原生元素時才使用 ARIA。 - 鍵盤:所有元素都應可透過鍵盤觸及和操作;無正數
tabIndex;無鍵盤陷阱。 - 可見焦點:每個可互動元素 (
:focus-visible,對比度 ≥ 3:1)。 - 焦點管理:路由變更時設定頁面標題並將焦點移至
<h1>或<main>;對話框應鎖定焦點,按Escape關閉,並將焦點返回至觸發元素。 - 名稱:圖示按鈕需有
aria-label;圖片需有alt(裝飾性圖片使用alt="")。 - 對比度:文字 4.5:1,UI 元件 3:1;顏色永遠不是唯一的信號。
- 尊重減少動畫設定;即時區域 (
role="status"/role="alert") 用於非同步結果和錯誤。 - 測試透過角色和可存取名稱查詢;stories 需通過 a11y 附加元件;關鍵頁面需通過 Playwright 中的 axe 檢查。
測試 — 與功能一同撰寫,而非事後
- Vitest + Testing Library 為每個功能編寫單元測試和元件測試,並在同一變更中提交。透過 UI (角色、標籤、
user-event) 測試行為,而非實作細節。 - 覆蓋率 ≥ 80% 行數且 ≥ 80% 分支,由 CI 中的 Vitest 閾值強制執行。
- Playwright E2E 涵蓋每個關鍵使用者流程 (登入、核心業務流程、付款/結帳、權限):使用基於角色的定位器,無固定等待,重用認證狀態,在關鍵頁面上執行 axe 掃描。
- 每個共享/可重用的 UI 元件都應有 Storybook story,涵蓋所有狀態 (預設、載入中、空資料、錯誤、禁用、長內容)。預設為桌面視口;僅在專案需要響應式佈局時才使用行動視口。
- 透過 Storybook + Playwright 螢幕截圖進行視覺回歸;快照測試僅謹慎且有目標地使用。
安全 — 始終遵守
- 不允許
dangerouslySetInnerHTML,除非搭配 DOMPurify;在 React 外部使用textContent,絕不使用innerHTML。模型輸出和 Markdown 絕不渲染為原始 HTML。 - 不允許將 Token 或敏感資料存入
localStorage/sessionStorage/IndexedDB。 認證應使用後端設定的HttpOnlysession cookie;對於 OIDC,偏好使用後端對前端 (BFF) 模式。 - 變更狀態的請求需發送 CSRF 標頭;僅對自己的 API 使用
credentials: 'include'。 VITE_*變數是公開的 — 絕不能在其中存放任何祕密。?redirect=目標僅限於同源相對路徑 (防止開放重定向)。- 登出需清除伺服器 session、TanStack Query 快取以及所有持久化 store。
- CSP 應作為 HTTP 標頭設定,包含
object-src 'none'、base-uri 'none'、frame-ancestors。 postMessage處理常式需檢查event.origin;絕不合併不受信任的物件 (原型污染)。- 前端永不強制執行授權 — 授權由後端負責 [ASVS 8.3.1]。
TypeScript 與 Biome
- 啟用
strict(自 TypeScript 7 起為預設 — 請保持明確);同時啟用noUncheckedIndexedAccess、verbatimModuleSyntax、moduleResolution: "bundler",lib設定為ES2023+DOM。TypeScript 7 將types預設為[]— 請明確列出"vite/client";baseUrl已移除,請使用paths("@/*": ["./src/*"])。 - 不允許
any(使用unknown並縮小型別),不允許使用非 null 斷言來忽略錯誤,不允許@ts-ignore(如果無法避免,請使用@ts-expect-error並附上原因)。不允許魔術數字或字串 — 使用shared/config/或所屬切片的config/model中的命名常數。 - 外部資料的型別應來自 Zod schema (
z.infer/z.output),而非可能偏移的手寫介面。 - Biome:使用 recommended 規則集,加上
noNestedComponentDefinitions、noReExportAll和noConsole(不在 recommended 集中);noBarrelFile應為停用,以便用於切片index.ts檔案 (references/structure.md)。 biome ci、tsc --noEmit、steiger ./src和knip應在本機和 CI 中通過。請勿未加說明註解就內聯停用規則。- 註解使用英文;TODOs 使用專案的 TODO 標記。
儲存庫衛生 — 始終遵守
- Node 版本鎖定:
.nvmrc(LTS)、package.json中的engines搭配engine-strict、packageManager指定確切的 npm/pnpm 版本;提交 lockfile。 - pre-commit 已安裝,並在 commit 和 push 時執行:對暫存變更和所有未推送的 commit 執行 gitleaks、Biome;push 時執行
tsc、相關的 Vitest 測試和相依性稽核。切勿使用--no-verify跳過。 - 相依性稽核在每次 MR 和定期排程時於 CI 中執行。
詳情請見 references/tooling.md。
Docker 與部署
容器映像、.dockerignore、Compose 和 Kubernetes 由 docker-kubernetes 技能涵蓋;前端工作流程和檢查清單位於 references/docker.md。每個映像都應有 .dockerignore。與前端相關的注意事項:
VITE_*值在建置時被注入到 bundle 中。若要一個映像用於多個環境,則需要執行時期設定:提供一個config.json(或config.js),該檔案在容器啟動時從環境變數寫入,並在應用程式啟動時擷取/驗證 — 仍為公開,仍無祕密。- Vite SPA 是靜態檔案:從 Web 伺服器提供服務,客戶端路由需 fallback 到
index.html,雜湊資產設定長快取,index.html設定no-cache,並設定references/security.md中的安全標頭。 - React Router 框架模式 (SSR) 在執行時期需要一個 Node 伺服器 (
react-router-serve或自訂伺服器) — 它不是靜態部署。
撰寫之後
若需對結果進行安全審查,建議使用 appsec-review 技能。
來源
綜合自 Vercel Engineering 的 React 最佳實踐 (github.com/vercel-labs/agent-skills, react-best-practices, MIT 許可證) — 從 Next.js 改編為搭配 TanStack Query 的 Vite/React Router;保留規則 ID 以利追溯 — 以及 OWASP 安全代理手冊 (CC BY 4.0;OWASP ASVS 5.0)。結構遵循 Feature-Sliced Design (feature-sliced.design, fsd.how);references/fsd/ 改編自官方 FSD 代理技能 (github.com/feature-sliced/skills, MIT 許可證)。無障礙目標為 WCAG 2.2。