專案結構
本文檔說明基於 AppFuse Web 的專案結構,包含應用程式結構和框架內部結構。
應用程式結構
以下是使用 AppFuse Web 建構的應用程式推薦結構:
my-web-app/
├── public/ # 靜態資源
│ ├── mockServiceWorker.js # MSW Service Worker
│ └── vite.svg
├── src/
│ ├── applets/ # 業務功能模組
│ ├── components/ # 共用組件
│ ├── layouts/ # 佈局組件
│ ├── features/ # Redux slices
│ ├── services/ # API 服務層
│ ├── mocks/ # MSW mock handlers
│ ├── hooks/ # 自訂 hooks
│ ├── utils/ # 工具函數
│ ├── config/ # Applet 註冊表
│ ├── conf/ # 應用程式環境配置
│ ├── routes/ # 路由配置
│ ├── nls/ # 國際化資源
│ ├── types/ # TypeScript 類型定義
│ ├── store/ # Redux Store
│ ├── data/ # 靜態資料(如預設商品清單)
│ ├── pages/ # 獨立頁面(登入、錯誤頁等)
│ ├── assets/ # 靜態資源(圖片、SVG)
│ ├── App.tsx # 主應用程式組件
│ ├── main.tsx # 應用程式入口
│ └── tailwind.css # Tailwind CSS
├── index.html # HTML 模板
├── package.json # 專案配置
├── vite.config.ts # Vite 配置
├── tsconfig.json # TypeScript 配置
├── tsconfig.app.json # TypeScript 應用程式配置
└── eslint.config.js # ESLint 配置
核心目錄說明
applets/ - 業務功能模組
Applet 是獨立的業務功能模組,包含完整的 UI、狀態、邏輯:
applets/
├── product-applet/ # 商品管理 Applet
│ ├── product-applet.tsx
│ ├── product-finder.tsx
│ ├── product-detail.tsx
│ ├── product-editor.tsx
│ ├── product-form.tsx
│ ├── types.ts
│ ├── index.ts
│ ├── components/ # Applet 專屬組件
│ └── utils/ # Applet 專屬工具函數
├── customer-applet/ # 客戶管理 Applet
│ ├── customer-applet.tsx
│ ├── customer-finder.tsx
│ ├── customer-detail.tsx
│ ├── customer-editor.tsx
│ ├── customer-form.tsx
│ ├── types.ts
│ ├── index.ts
│ ├── components/
│ ├── hooks/
│ └── utils/
├── order-applet/ # 訂單管理 Applet
├── dashboard-applet/ # 儀表板 Applet
├── sales-applet/ # 銷售 Applet
├── delivery-applet/ # 配送 Applet
├── design-applet/ # 設計 Applet
└── shared/ # 跨 Applet 共用模組
Applet 特性:
- 獨立的路由入口
- 可包含子路由
- 使用
<AppletShell>提供標準佈局 - 透過 Application Launcher 註冊
檔案命名慣例:使用 kebab-case(如 product-applet.tsx、product-finder.tsx)
範例:參考 app-office/src/applets
components/ - 共用組件
存放專案內跨 Applet 共用的組件:
components/
├── applet-shell/ # Applet 外殼組件
│ ├── applet-shell.tsx
│ └── index.ts
├── application-launcher/ # 應用程式啟動器
│ ├── application-launcher.tsx
│ └── index.ts
├── splash-screen/ # 啟動畫面
│ ├── splash-screen.tsx
│ └── index.ts
├── loading-fallback/ # 載入中備援組件
│ ├── loading-fallback.tsx
│ └── index.ts
├── language-toggle.tsx # 語言切換
└── theme-toggle.tsx # 主題切換
使用時機:
- 框架元件庫未提供
- 多個 Applet 需要使用
- 專案特定的業務組件
原則:
- 優先使用
@appfuse/appfuse-web的組件 - 僅建立必要的自訂組件
- 避免過度抽象
layouts/ - 佈局組件
定義應用程式的整體佈局:
layouts/
├── main-layout.tsx # 主要佈局(含 Header、Sidebar)
├── header.tsx # 頂部導航列
├── user-menu.tsx # 使用者選單
├── menu-config.ts # 選單配置
└── index.ts # 匯出入口
職責:
- 定義頁面框架
- 整合導航元件
- 處理佈局狀態(sidebar 展開/收合)
features/ - Redux Slices
使用 Redux Toolkit 管理全域狀態:
features/
├── app/ # 應用程式狀態
│ ├── sys-slice.ts
│ └── index.ts
├── iam/ # 身分認證狀態
│ ├── me-slice.ts
│ └── index.ts
├── product/ # 商品狀態
│ ├── product-finder-slice.ts
│ ├── draft-products-slice.ts
│ └── index.ts
├── crm/ # 客戶狀態
│ ├── customer-finder-slice.ts
│ ├── draft-customers-slice.ts
│ └── index.ts
├── sales/ # 訂單狀態
│ ├── order-finder-slice.ts
│ ├── draft-orders-slice.ts
│ ├── product-slice.ts
│ └── index.ts
├── pinned/ # 釘選紀錄狀態
│ ├── pinned-records-slice.ts
│ └── index.ts
└── root-reducers.ts # 根 Reducer 組合
設計原則:
- 僅存放真正全域的狀態
- 局部狀態使用 React state 或 URL state
- 使用 RTK Query 處理 API 快取
services/ - API 服務層
封裝與後端的通訊,按領域分目錄:
services/
├── api-client.ts # API 客戶端配置
├── core/ # 核心服務
│ ├── environ-service.ts # 環境配置服務
│ ├── nls-service.ts # 國際化服務
│ ├── reference-data-service.ts # 參考資料服務
│ ├── query-keys.ts # React Query 快取鍵
│ └── index.ts
├── iam/ # 身分認證服務
│ ├── auth-service.ts
│ ├── me-service.ts
│ └── signup-service.ts
├── sales/ # 銷售服務
│ ├── product-service.ts
│ ├── product-queries.ts
│ ├── order-service.ts
│ └── order-queries.ts
├── crm/ # 客戶服務
│ ├── customer-service.ts
│ └── customer-queries.ts
└── dashboard/ # 儀表板服務
├── dashboard-service.ts
├── dashboard-queries.ts
└── index.ts
職責:
- 定義 API 端點
- 處理請求/回應轉換
- 統一錯誤處理
mocks/ - MSW Mock Handlers
定義 Mock API 回應:
mocks/
├── browser.ts # MSW 瀏覽器設定
├── handlers/ # Mock handlers
│ ├── index.ts # Handler 匯出入口
│ ├── auth.ts
│ ├── products.ts
│ ├── orders.ts
│ ├── customers.ts
│ ├── dashboard.ts
│ ├── files.ts
│ └── reference-data.ts
├── data/ # Mock 資料
│ ├── db.ts # 模擬資料庫
│ ├── seeds.ts # 種子資料
│ └── test-accounts.ts # 測試帳號
├── middleware/ # Mock 中介層
│ └── auth-middleware.ts
├── utils/ # Mock 工具
│ ├── error-helpers.ts
│ └── jwt.ts
└── types.ts # Mock 型別定義
使用方式:
// mocks/handlers/products.ts
import { http, HttpResponse } from 'msw';
export const productHandlers = [
http.get('/api/products', () => {
return HttpResponse.json(products);
}),
http.post('/api/products', async ({ request }) => {
const newProduct = await request.json();
return HttpResponse.json(newProduct, { status: 201 });
}),
];
Mock → 真實 API 切換:參考 Mock API 指南
config/ - Applet 註冊表
config/
└── applet-registry.ts # Applet 定義與權限配置
定義所有可用的 Applet,供 Application Launcher 顯示與導航。
conf/ - 應用程式環境配置
conf/
└── config.ts # 環境配置(API base URL、MSW 開關、i18n 等)
範例:
// conf/config.ts
import { type EnvironConfig } from '@appfuse/appfuse-web'
export type AppConfig = {
msw?: { enabled: boolean }
}
export type AppEnvironConfig = EnvironConfig<AppConfig>
export const config: AppEnvironConfig = {
app: {
name: 'App',
version: '1.0.0',
stage: import.meta.env.MODE,
basename: '/',
baseURL: '/',
msw: {
enabled: import.meta.env.DEV,
},
},
i18n: {
language: 'zh-TW',
fallback: 'en',
languages: ['en', 'zh-TW'],
},
}
routes/ - 路由配置
定義應用程式路由:
routes/
├── index.tsx # 主路由配置
├── protected-route.tsx # 受保護路由守衛
├── role-guard.tsx # 角色權限守衛
└── playground/ # 開發用沙箱路由
└── index.tsx
nls/ - 國際化資源
存放多語言資源檔,按用途分類,使用 TypeScript 格式:
nls/
├── term/ # 術語翻譯
│ └── zh-TW.ts
├── message/ # 訊息翻譯
│ └── zh-TW.ts
├── article/ # 文章翻譯(預留)
└── types.ts # NLS 型別定義
使用方式:參考 國際化指南
配置檔案
vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tsconfigPaths from 'vite-tsconfig-paths'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig((_) => {
return {
base: './',
plugins: [react(), tsconfigPaths(), tailwindcss()],
server: {
port: 3000,
},
build: {
sourcemap: true,
},
test: {
globals: true,
environment: 'jsdom',
setupFiles: ['./src/__tests__/setupTests.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'html'],
},
include: ['src/**/*.test.{ts,tsx}', 'src/**/*.spec.{ts,tsx}'],
},
}
})
src/tailwind.css
Tailwind v4 使用 CSS-based 配置,不再需要 tailwind.config.ts:
@source "../node_modules/@appfuse/appfuse-web/lib/**/*.{ts,tsx}";
@import 'tailwindcss';
/* DaisyUI 主題與自訂樣式 */
@source 指令掃描元件庫的原始碼,讓 Tailwind 統一生成 CSS。
最佳實踐
1. Import 路徑
使用路徑別名提高可讀性:
✅ 推薦:
import { Button } from '@appfuse/appfuse-web';
import { AppletShell } from '@/components/applet-shell';
import { usePermission } from '@/hooks';
❌ 避免:
import { Button } from '../../../node_modules/@appfuse/appfuse-web';
import { AppletShell } from '../../../components/applet-shell';
2. 狀態管理策略
局部狀態 → React useState
URL 狀態 → useSearchParams
全域狀態 → Redux Toolkit
伺服器狀態 → RTK Query
3. 檔案命名
- 組件目錄與檔案:
kebab-case(如product-applet/、product-finder.tsx) - Hooks:
kebab-case.ts(如use-permission.ts) - 工具函數:
kebab-case.ts(如jwt-utils.ts) - Redux Slices:
kebab-case.ts(如product-finder-slice.ts) - 類型定義:
types.ts
框架內部結構
以下是 @appfuse/appfuse-web 框架本身的結構,供進階參考:
appfuse-web/
├── lib/ # 框架層(發布為 @appfuse/appfuse-web)
│ ├── components/ # UI 元件庫(30+ 元件)
│ ├── form/ # 表單元件(react-hook-form 整合)
│ ├── utils/ # 工具函數(http, i18n, time 等)
│ ├── hooks/ # React Hooks
│ ├── messaging/ # 全域訊息系統(Toast + Dialog)
│ ├── docs/ # 框架文檔
│ ├── main.ts # 框架進入點
│ └── tailwind.css # 基礎 Tailwind CSS
│
├── src/ # 原型層(參考實作)
│ ├── applets/ # 功能模組(product, order, customer 等)
│ ├── services/ # API 服務層
│ ├── components/ # 共用元件
│ ├── layouts/ # 版面配置
│ ├── routes/ # React Router 路由
│ ├── mocks/ # MSW Mock API
│ ├── features/ # Redux Slices
│ ├── store/ # Redux Store
│ ├── config/ # 應用程式配置
│ ├── types/ # TypeScript 型別
│ ├── nls/ # 國際化資源
│ └── assets/ # 靜態資源
│
├── tests/ # E2E 測試(Playwright)
├── docs/ # 框架文檔
└── .storybook/ # Storybook 配置
框架元件庫 (lib/components/)
按功能分類的 UI 元件:
| 分類 | 路徑 | 包含元件 |
|---|---|---|
| 資料輸入 | data-input/ | Input, Select, Checkbox, Radio, Switch, Textarea, TagInput, FileInput, MediaInput, RichTextEditor |
| 資料顯示 | data-display/ | DataTable, VirtualTable, Icon, MediaViewer, AuthImage |
| 動作 | actions/ | Button |
| 圖表 | charts/ | LineChart, AreaChart, BarChart, PieChart, RadarChart, FunnelChart, ScatterPlot |
| 版面 | layout/ | CollapsibleCard |
| 導航 | navigation/ | Tabs |
| 回饋 | feedback/ | Toast, ToastContainer, Dialog |
| 覆蓋 | overlays/ | Dropdown |
框架工具函數 (lib/utils/)
| 模組 | 用途 |
|---|---|
http | HTTP 客戶端(axios 封裝,自動日期轉換) |
filter | 查詢過濾器建構(RSQL/FIQL 標準) |
browser | 瀏覽器偵測、語言偵測 |
cn | CSS 類別合併(Tailwind CSS) |
cookie | Cookie 管理 |
environ | 環境配置 |
i18n | 國際化 |
logger | 日誌系統 |
numeral | 數字格式化 |
template | 字串模板 |
time | 日期時間處理 |
框架匯入路徑
// 元件
import { Button, Input } from '@appfuse/appfuse-web/components';
// 表單元件
import { Input, Select } from '@appfuse/appfuse-web/form';
// 工具函數
import { createHttpClient } from '@appfuse/appfuse-web/utils';
import { time } from '@appfuse/appfuse-web/utils';
// Hooks
import { useTimeout } from '@appfuse/appfuse-web/hooks';
// 訊息系統
import { prompt } from '@appfuse/appfuse-web/messaging';
下一步
- 第一個 Applet - 建立你的第一個業務模組
- 狀態管理 - 深入了解狀態管理策略
- 表單處理 - 學習表單開發模式
參考資源
- app-office 專案結構 - 參考實作完整範例