跳至主要内容

專案結構

本文檔說明基於 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.tsxproduct-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/)

模組用途
httpHTTP 客戶端(axios 封裝,自動日期轉換)
filter查詢過濾器建構(RSQL/FIQL 標準)
browser瀏覽器偵測、語言偵測
cnCSS 類別合併(Tailwind CSS)
cookieCookie 管理
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';

下一步

參考資源