FSTS 前端編碼規範
OMS 專案前端(React 18 + TypeScript 5 + Vite)的編碼規範(v1.1,2026-03-02)。適用範圍:證券業 Order Management System 前端。回到 FSTS 專案總覽、搭配後端:FSTS 後端編碼規範。
一句話
OMS 前端以 Vite + React 18 + TypeScript 5 為骨幹,UI 採 Radix UI + Tailwind CSS headless 路線,狀態切為 TanStack Query(server)+ Zustand(client)+ useState(local) 三層,禁用中國大陸來源套件(Ant Design / UMI / dayjs / Taro 等)並要求 MIT / Apache 2.0 / BSD 授權。12
1. 技術選型原則
1.1 核心原則
- 不使用中國大陸來源套件(如 Ant Design、UMI、dva、Taro、dayjs 等)
- 優先選擇歐美主流開源生態系,確保長期維護性與合規性
- 所有套件須有 MIT / Apache 2.0 / BSD 授權1
1.2 官方技術棧
| 類別 | 選用套件 | 說明 |
|---|---|---|
| 建置工具 | Vite | 快速 HMR、原生 ESM |
| UI 元件庫 | Radix UI + Tailwind CSS | Headless + 自訂樣式 |
| 狀態管理 | Zustand (client) + TanStack Query (server) | 輕量 + 資料快取 |
| 路由 | React Router v6 | 巢狀路由、lazy loading |
| 表單 | React Hook Form + Zod | 高效能 + 型別安全驗證 |
| 表格 | TanStack Table | Headless、支援虛擬滾動 |
| 圖表 | Recharts 或 Lightweight Charts | 金融圖表 |
| HTTP 客戶端 | Axios | 攔截器、取消請求 |
| 日期處理 | date-fns | 純函數、Tree-shakable |
| 國際化 | react-i18next | 多語系 |
| 測試 | Vitest + Testing Library | 與 Vite 整合 |
| 代碼檢查 | ESLint + Prettier | 統一風格 |
1.3 禁用套件清單
| 禁用 | 替代方案 | 原因 |
|---|---|---|
| Ant Design (antd) | Radix UI + Tailwind | 中國來源 |
| UMI | React Router + Vite | 中國來源 |
| dva | Zustand | 中國來源 |
| dayjs | date-fns | 中國來源 |
| Taro | N/A | 中國來源 |
| element-plus | N/A | 中國來源(Vue 生態) |
| naive-ui | N/A | 中國來源(Vue 生態) |
| cnpm / tnpm | npm / pnpm | 中國來源 Registry |
2. 專案結構
frontend/src/
├── app/ # 應用層:路由、Provider、全域設定
│ ├── App.tsx, routes.tsx
│ └── providers/ (AppProvider, QueryProvider)
├── features/ # 功能模組(按業務領域分)
│ └── {orders, products, dashboard}/
│ └── (api/, components/, hooks/, types/, pages/)
├── shared/ # 跨功能共用
│ ├── components/ (ui/, layout/, data-display/)
│ ├── hooks/, utils/, types/, constants/
├── services/ # 外部服務整合
│ ├── api/ (Axios instance、攔截器)
│ └── websocket/ (即時行情)
├── stores/ # Zustand 全域狀態
└── styles/ (globals.css)
根目錄另有 index.html、package.json、vite.config.ts、tailwind.config.ts、eslint.config.js、prettier.config.js、tsconfig.json。3
2.1 模組邊界規則
features/內的模組之間禁止直接引用,必須透過shared/共用shared/不得引用任何features/模組services/為純技術層,不包含業務邏輯- 每個 feature 可獨立 lazy load
- 禁止使用 barrel file(
index.tsre-export),直接引用具體檔案以利 tree-shaking4
3. 命名規範
3.1 檔案命名
| 類型 | 規則 | 範例 |
|---|---|---|
| React 元件 | PascalCase .tsx | OrderTable.tsx |
| Hook | camelCase,use 開頭 | useOrdersQuery.ts |
| 工具函式 | camelCase | formatters.ts |
| 型別定義 | camelCase | orderTypes.ts |
| 常數 | camelCase 檔名,UPPER_SNAKE 值 | appConstants.ts |
| Query Key Factory | camelCase | orderQueryKeys.ts |
| 測試 | 與原始檔同名 + .test | OrderTable.test.tsx |
說明:除 React 元件檔案使用 PascalCase 外,其他所有 .ts 檔案統一使用 camelCase(與 TanStack、Zustand 等主流套件一致)。5
3.2 程式碼命名
- 元件 — PascalCase:
export function OrderDetailPanel(...) - Hook — camelCase,
use開頭:export function useOrderQuery(...) - 型別 / 介面 — PascalCase,不加
I前綴:export interface OrderResponse { } - 常數 — UPPER_SNAKE_CASE:
export const MAX_PAGE_SIZE = 100 - 事件處理 —
handle前綴:const handleSubmit = () => { } - Boolean 變數 —
is/has/should前綴:isLoading,hasPermission,shouldRefresh6
反例(禁止):function orderDetailPanel()(元件非 PascalCase)、interface IOrderResponse(用 I 前綴)、const loading(Boolean 缺語意前綴)。6
4. 元件設計規範
4.1 撰寫原則
- 使用函式元件 + 具名匯出
- Props 型別獨立定義於元件上方
- 禁止使用
React.FC(型別推斷不精確)7
4.2 Export 規則
| 情境 | 使用方式 | 原因 |
|---|---|---|
| 元件、Hook、工具函式 | export function 具名匯出 | 可搜尋性佳、支援 tree-shaking |
| Page 元件 | export default function | React.lazy() 要求 default export |
forwardRef 元件 | export const X = forwardRef(...) | React API 限制,允許此例外 |
4.3 元件分類
| 分類 | 位置 | 特性 |
|---|---|---|
| Page Component | features/*/pages/ | 對應路由、組合子元件、處理資料取得 |
| Feature Component | features/*/components/ | 業務邏輯相關、可存取 feature 的 store/api |
| Shared Component | shared/components/ | 純展示、無業務邏輯、只接收 props |
| Layout Component | shared/components/layout/ | 頁面框架(Sidebar, Header) |
4.4 元件大小限制
- 單一元件檔案不超過 250 行
- 超過則拆分子元件或抽離 Hook
- 一個檔案只匯出一個元件(小型輔助元件例外)8
5. 狀態管理規範
5.1 狀態分層
| 層級 | 套件 | 說明 |
|---|---|---|
| Server State(API 資料、快取、同步) | TanStack Query | 自動快取、refetch、stale time |
| Client Global State(用戶偏好、UI 主題、認證) | Zustand | 跨頁面持久狀態 |
| Component Local State(表單輸入、展開收合、對話框) | useState / useReducer | 不需跨元件共用 |
5.2 TanStack Query 使用規範
Query Key Factory 獨立檔案(與 Query Hook 分離),擺在 features/orders/api/orderQueryKeys.ts。9
6. API 整合規範
6.1 Axios Instance
baseURL從import.meta.env.VITE_API_BASE_URL(預設/api/v1),timeout: 15_000- Request 攔截器:自動帶 Token(
Authorization: Bearer ${token}) - Response 攔截器:401 自動清除 auth + 導
/login;error.response.data作為 ProblemDetails 拋出10
6.2 API 函式規範
每個 Domain 一個 API 模組,函式命名對應 HTTP Method(getOrders, getOrderById, createOrder, updateOrderStatus)。檔案位置:services/api/orderApi.ts。11
6.3 API 錯誤型別(RFC 7807 ProblemDetails)
後端回傳的錯誤格式遵循 RFC 7807;前端使用共用型別 ProblemDetails:12
interface ProblemDetails {
type: string;
title: string;
status: number;
detail: string;
traceId?: string;
errors?: Record<string, string[]>;
}禁止使用 inline 型別斷言(如 (error as { detail?: string })?.detail)。12
7. 金融業專用規範
7.1 數值格式化
所有金額一律使用專用格式化函式,禁止手動拼接:13
formatCurrency(value, currency = 'TWD')—Intl.NumberFormat('zh-TW', { style: 'currency', currency })formatStockPrice(value)— 2 位小數formatChangePercent(value)— 含+/-符號
7.2 即時資料(WebSocket)
金融業需要即時行情推送。核心設計要點:14
- 使用
useRef穩定symbolsreference(避免重複連線) - 斷線自動重連(exponential backoff)
onerror錯誤處理JSON.parsetry-catchuseEffect用空依賴,連線只建立一次,symbols 透過 ref 讀取
7.3 安全性要求
- Token 優先使用 httpOnly Secure Cookie(後端設定,前端碰不到 Token)
- 若因架構限制使用
localStorage,須搭配嚴格 CSP 政策防止 XSS - 所有 API 請求必須走 HTTPS
- 敏感頁面(交易、帳務)需設 Session Timeout(建議 15 分鐘)
- 禁止在前端
console.log輸出敏感資料(帳號、金額、身分證字號) - Production build 應透過 Vite 設定
esbuild.drop: ['console', 'debugger']移除所有 console - 使用 CSP Header 防止 XSS15
8. 樣式規範
8.1 Tailwind CSS 原則
- 使用 Tailwind 工具類別(
className="rounded-md bg-blue-600 px-4 py-2 ...") - 複雜樣式用
clsx+tailwind-merge(合併成cn()工具函式) - 語意化顏色透過 Tailwind config 定義:
text-market-up(紅)、text-market-down(綠)— 台灣證券業慣例:漲紅跌綠16
本專案唯一樣式方案為 Tailwind CSS,不使用 CSS Modules、styled-components 或其他 CSS-in-JS。16
8.2 響應式設計
- Mobile-first 設計(
sm:→md:→lg:→xl:) - 金融交易畫面最小支援 1280px 寬螢幕
- Dashboard 支援多螢幕分割顯示17
9. Import 排序規範
所有檔案的 import 依以下順序排列,各群組之間空一行:18
- React 核心(
import { useState } from 'react') - 第三方套件(
@tanstack/react-query、zod等) @/路徑別名(shared → services → stores)- 相對路徑引用(feature 內部)
- 型別 import(使用
import type)
可搭配 ESLint import/order 或 @trivago/prettier-plugin-sort-imports 自動排序。
10. ESLint 檢核規則
本專案使用 ESLint Flat Config 格式(eslint.config.js),搭配 typescript-eslint 的 strictTypeChecked 預設規則集。19
10.1 TypeScript 嚴格規則
| 規則 | 設定 | 說明 |
|---|---|---|
@typescript-eslint/no-unused-vars | error | 未使用變數為錯誤,_ 開頭參數除外 |
@typescript-eslint/no-explicit-any | error | 禁止使用 any 型別 |
@typescript-eslint/explicit-function-return-type | off | 由 TypeScript 推斷 |
@typescript-eslint/consistent-type-imports | error | 型別 import 必須用 import type |
@typescript-eslint/no-misused-promises | warn | Promise 誤用警告 |
10.2 命名規範
| 對象 | 格式 | 範例 |
|---|---|---|
| interface | PascalCase | OrderResponse, AuthState |
| typeAlias | PascalCase | OrderStatus, UserRole |
| enum | PascalCase | Theme, Locale |
| Boolean 變數 | is / has / should / can / will 開頭 | isLoading, hasPermission |
10.3 React 規則
react-hooks/rules-of-hooks: error — Hook 必須在頂層呼叫react-hooks/exhaustive-deps: warn —useEffect依賴陣列完整性檢查react-refresh/only-export-components: warn — 檔案只匯出元件(支援 HMR),允許const匯出19
10.4 一般規則
no-console: warn — 禁止console.log,允許console.warn/console.errorprefer-const: errorno-var: error19
10.5 刻意關閉的規則
@typescript-eslint/no-confusing-void-expression— 與 React event handler 慣例衝突@typescript-eslint/restrict-template-expressions— 過度嚴格,影響開發效率19
10.6 繼承規則集
js.configs.recommended(來自@eslint/js)tseslint.configs.strictTypeChecked(來自typescript-eslint)20
單行忽略(僅在必要時使用,需附註原因):// eslint-disable-next-line @typescript-eslint/no-explicit-any -- 第三方套件型別不完整。21
11. 環境變數規範
Vite 要求前端可存取的環境變數必須以 VITE_ 開頭:22
| 變數 | 說明 | 預設值 |
|---|---|---|
VITE_API_BASE_URL | 後端 API 基礎路徑 | /api/v1 |
VITE_WS_URL | WebSocket 即時行情位址 | — |
.env檔案禁止納入版控(加入.gitignore)- 不得在
VITE_變數中存放敏感資訊(API Secret、DB 密碼) - 提供
.env.example作為範本
12. 測試規範
12.1 Co-location(與原始碼並排)
前端業界主流是將測試檔案放在原始碼旁邊,而非像後端獨立成專案:23
src/shared/utils/formatters.ts
src/shared/utils/formatters.test.ts ← 同目錄
規則:foo.ts 的測試就是同目錄下的 foo.test.ts(元件則為 foo.test.tsx)。
不獨立資料夾的原因:Vite 打包不會包含 .test.ts、就近維護、刪除方便、IDE 側邊欄切換快。另一種做法是同層建立 __tests__/ 子資料夾收納測試(視覺較乾淨),兩種都是主流,團隊統一即可。23
12.2 測試優先順序(投資報酬率由高到低)
| 順序 | 類型 | 說明 | 範例 |
|---|---|---|---|
| 1 | 工具函式 / 純邏輯 | 最容易測、最穩定 | formatters.test.ts, cn.test.ts |
| 2 | Store / Hook | 商業邏輯集中處,改壞影響大 | authStore.test.ts, useOrderFilters.test.ts |
| 3 | 元件行為 | 條件渲染、使用者互動 | Pagination.test.tsx, UserStatusBadge.test.tsx |
| 4 | 整頁 E2E | 通常用 Playwright,不算單元測試 | — |
原則:測「有邏輯的部分」,純 UI 排版通常不值得寫單元測試。24
12.3 強制寫測試時機
PR 合併前必須完成:25
- 新增前端 utility 函式
- Bug 修復:先寫失敗的測試,再修正程式碼
建議:Zustand Store 的新 action、React 元件的互動邏輯(Pagination / Modal 等)、Custom Hook 的狀態管理邏輯。
12.4 測試命名與原則
- 測試使用者行為,不測實作細節
- 使用
screen.getByRole()優先,避免getByTestId() - Mock 外部 API,不 Mock 內部模組26
12.5 覆蓋率目標
| 範圍 | 目標 | 說明 |
|---|---|---|
| Utility 函式 | 90%+ | 純函式,無副作用 |
| Store | 80%+ | 狀態管理邏輯 |
| 元件 | 60%+ | 著重互動邏輯 |
12.6 測試工具
| 工具 | 版本 | 用途 |
|---|---|---|
| Vitest | 2.1.5 | 測試框架(與 Vite 原生整合) |
@testing-library/react | 16.0.1 | React 元件測試 |
@testing-library/jest-dom | 6.6.3 | DOM 斷言擴充 |
@testing-library/user-event | 14.5.2 | 使用者互動模擬 |
| jsdom | 25.0.1 | 瀏覽器環境模擬 |
13. 效能規範
- Code Splitting:每個 feature 頁面使用
React.lazy()+Suspense - 虛擬滾動:超過 100 筆資料的列表使用
@tanstack/react-virtual - 圖片:使用 WebP 格式,搭配
loading="lazy" - Bundle 分析:定期使用
rollup-plugin-visualizer檢查 bundle 大小 - 首次載入:主 Bundle < 200KB (gzipped)
- 避免過早優化:
useMemo/useCallback僅在確認有 re-render 效能問題時使用,不要預設加上27
14. 無障礙(WCAG 2.1 Level AA)
證券業因合規需求,需符合 WCAG 2.1 Level AA:28
- 所有互動元素(按鈕、連結、表單輸入)必須可透過鍵盤操作
- icon-only 按鈕必須提供
aria-label - 表單輸入需搭配
<label>或aria-label,錯誤訊息使用aria-describedby關聯 - 顏色不得作為唯一的資訊傳達方式(漲跌須同時用顏色 + 符號 ↑↓)
- 使用 Radix UI 的 headless 元件時,框架已內建 ARIA 屬性
附錄:Quick Reference
DO:29
- 元件使用具名匯出 (named export)
- Page 元件使用 default export(
React.lazy要求) - Props 型別獨立定義
- Server State 用 TanStack Query
- 金額用
formatCurrency()格式化 - Feature 模組之間透過
shared/溝通 - Boolean 變數加
is/has/should前綴 - API 錯誤使用
ProblemDetails型別 - icon-only 按鈕加
aria-label
DON’T:29
- 使用 Ant Design 或任何中國來源套件
- 使用
React.FC定義元件 - 在非 Page 元件中使用 default export
- 在 Page 元件中直接呼叫
axios console.log輸出敏感資料- 單一元件超過 250 行
- 使用 CSS Modules / styled-components
- 使用 barrel file(
index.tsre-export) - API error 使用 inline 型別斷言
相關頁面
- FSTS 後端編碼規範 — 對應的後端規範(RFC 7807 ProblemDetails 共用)
- FSTS Vibe Coding 開發框架 — Multi-Agent Pipeline + Skills / Rules
- FSTS 系統架構 — 前後端拓樸
- FSTS 專案總覽 — 專案入口
補充資訊
來源補充:OMS Coding Rule & CI/CD 簡報(2026-03,OMS Team)
OMS Team 於 2026-03 對前端規範做了一份簡報版摘要。大多數內容與本頁主要規範一致(Radix UI + Tailwind、TanStack Query + Zustand 三層狀態、禁用中國大陸來源套件、ESLint + CI 強制命名檢核、金融業 formatCurrency() 與漲跌顏色+符號雙標示),但在建置工具 / 框架選型上與主要規範衝突,因此本頁 status 改為 contested,不主觀仲裁。
衝突內容:
| 面向 | 主要規範(Frontend-CodingRule v1.1,2026-03-02) | 簡報(OMS Coding Rule & CI/CD,2026-03) |
|---|---|---|
| 建置工具 / 框架 | Vite + React 18 + TypeScript 52 | Next.js 15 (App Router) + React 19 + TypeScript 530 |
| HTTP 請求 | axios Instance10 | API Routes + fetch30 |
補充(兩份來源一致的重點):
- Bulletproof React 架構理念(作者 Alan Alickovic,GitHub ★ 30k+):Feature-based 結構、明確模組邊界、關注點分離、可擴展性 — 與 Clean Architecture 精神一致。簡報點出 Bulletproof React 「填補了 React 社群長期缺乏官方專案結構的空缺」。31
- 禁止使用中國大陸來源套件清單(Ant Design / UMI / dva / dayjs / Taro / cnpm / tnpm),理由為「確保長期維護性與合規性」。32
- 模組邊界:features 之間禁止直接引用,共用元件必須經過
shared/;services 純技術層,不含業務邏輯;禁止 barrel file(index.tsre-export)以利 tree-shaking。33 - 命名規則由 ESLint + CI 自動檢核:違反者無法 push、PR 無法合併(pre-commit hook + GitHub Actions 雙重把關)。34
- 金融業特殊規範:金額一律用
formatCurrency()(禁止手動拼接);漲跌顯示用「顏色 + 符號(↑↓)」雙標示(無障礙要求);即時行情走 WebSocket 並處理斷線重連;Production 移除console.log並套用嚴格 CSP 政策。35
CI/CD 章節獨立成頁:CD Pipeline。