Files
skt-vuetify-templates/docs/frontend-layering.md
T

15 KiB
Raw Blame History

前端分層規則與目前結構

目的

這份文件用來同步目前專案前端分層的實際狀況,讓新增功能、搬移檔案、或拆分元件時有一致判斷基準。

這份文件有兩個用途:

  • 描述目前已落地的結構與責任邊界
  • 明確標示哪些地方仍是過渡狀態,避免把「現況」誤認成「目標架構」

目前專案的主要分層不是只有 views / components / composables / layouts,而是已經形成以下責任鏈:

  • router 決定 route 與 layout meta
  • App.vue 根據 route meta 組裝 app shell 與全域 UI
  • views 承接路由入口與頁面資料組裝
  • components 承接畫面組裝、頁面型元件、功能區塊與基礎元件
  • composables 承接可重用流程與 UI state
  • stores 承接跨頁狀態、快取與 UI 顯示狀態
  • services 承接 HTTP client、API 模組、token 與錯誤正規化

目前目錄的責任邊界

src/router

目前路由集中在:

責任:

  • 定義 route 與 route meta
  • 指定頁面使用哪種 layout
  • 串接導航守衛

目前 meta.layout 已經成為 app shell 切換的正式入口,這一點會影響 App.vue 與 layout 的責任切分。

src/App.vue

App.vue 目前不是單純的掛載殼層,而是實際的應用組裝層。

目前承擔的責任包含:

  • route.meta.layout 切換 SKAdminLayoutSKEmptyLayout
  • 組裝 breadcrumb / favorites / menu 等 layout props
  • 放置全域搜尋結果 dialog
  • 放置全域訊息中心 dialog
  • 放置全域 snackbar
  • 串接 layout event 與路由跳轉

判斷原則:

  • 與「整個 app shell」共享、且不屬於單一頁面的 UI,可留在 App.vue
  • 只屬於單一路由頁面的對話框或互動,不應再往 App.vue

src/views

views 目前整體方向是「路由入口 + 頁面組裝」,但尚未完全一致。

目前已接近薄 view 的頁面:

目前仍偏厚的頁面:

目前 views 應遵守的原則:

  • 可以持有 route、store、頁面資料組裝、頁面事件協調
  • 不應長期承擔大量可拆出的模板片段
  • 不應把可重用流程直接留在頁面內反覆複製

src/components

目前 components 已經分成四種角色,不能再用單一規則描述。

1. 頁面型元件

目前以下元件實際上扮演「page component」:

這些檔案目前的實際責任是:

  • 接收 view 組好的資料
  • 組裝頁面主畫面
  • 再往下使用較小的子元件

這代表它們不是 base,也不是 layout,而是現行專案的頁面型組裝層。

2. components/base

文件原先寫法是「base 只放真正通用元件」,但目前專案並不完全符合。

現在 components/base 內同時存在兩類東西:

因此目前對 base 的正確認知應該是:

  • 它已經不是純粹的「全域 base library」
  • 它同時包含「通用元件」與「頁面型元件拆出的子元件」
  • 新增檔案時不要因為方便就繼續把所有頁面子元件丟進 base

目前建議:

  • 真正跨頁重用的元件,才放在 components/base 根層
  • 若元件只服務單一頁面家族,優先放到對應資料夾或 feature/domain 資料夾

3. components/layouts

目前 layout 相關實作集中於:

目前主實作仍以 SKAdminLayout 為核心,子元件拆分集中在 sk-admin-layout

layout 應只承擔:

  • app shell
  • drawer / app bar / favorites / breadcrumb 等框架 UI
  • 與 layout 視覺結構直接相關的互動

layout 不應承擔:

  • 頁面專屬業務流程
  • 特定 domain 的資料規則

4. components/maintenance

這個目錄目前已經是最接近 feature folder 的區域:

結論:

  • components/maintenance 已實質扮演 domain component 層
  • 目前沒有必要為了形式硬搬到 components/features/maintenance

src/composables

目前已明確分成兩組:

  • composables/layout/*
  • composables/maintenance/*

代表性檔案:

目前 composables 的責任是正確的:

  • 放可重用流程
  • 放可測試的 UI state
  • 放與模板結構耦合較低的狀態機

src/stores

目前 store 已經成為正式分層的一部分,而不只是暫時狀態容器。

代表性檔案:

責任:

  • 承接跨頁共享狀態
  • 承接畫面快取與顯示狀態
  • 作為 view 與 services 之間的狀態收斂點

注意:

  • 目前存在 src/stores/stores/* 的重複目錄,這不是分層設計的一部分,應視為待整理結構噪音

src/services

services 現在已經是一層明確的資料存取邊界,不應再被視為附屬工具資料夾。

代表性檔案:

責任:

  • 提供 HTTP client
  • 封裝 API 模組
  • 統一 token、session 與錯誤處理

規則:

  • 元件不直接處理底層 HTTP 細節
  • 可共享的請求流程優先收斂到 store 或 composable,再由它們呼叫 service

目前已落地的分層模式

模式 1view -> page component -> base 子元件

已落地頁面:

  • Login
  • Dashboard
  • Analysis
  • RoleManagement
  • MenuManagement
  • DeptManagement

代表目前專案已經存在一種穩定模式:

  • view 負責資料準備與事件協調
  • page component 負責頁面畫面組裝
  • 較細的視覺區塊再拆到內部子元件

這是目前除 maintenance 外最明確的頁面分層。

模式 2view -> maintenance components + maintenance composables

已落地區域:

  • views/maint/*
  • components/maintenance/*
  • composables/maintenance/*

其中 EditableGridMnt.vue 是目前最接近目標狀態的 maintenance 頁面。

模式 3router meta -> App.vue -> layout

這一層目前已正式成立:

  • route 決定 layout 類型
  • App.vue 決定套用哪個 shell
  • layout 專注在骨架與共用框架 UI

這代表 layout 的責任邊界不應再回頭混入頁面內部流程。

現況偏差與文件修正

以下是文件與實際程式碼之間原本不一致的地方,這次同步後已改成以現況描述:

  • components/base 並非只放真正通用元件
  • 專案目前不只 maintenance 有分層,login / dashboard / analysis / management 也已形成 view -> page component 模式
  • storesservices 已經是正式架構層,不能繼續省略不寫
  • App.vue 目前實際承擔全域 UI 組裝責任,不能只把它視為掛載入口
  • 錯誤頁已明確收斂到 views/errors/*

目前仍待整理的區域

高優先度

原因:

  • 這些頁面仍保留大量模板、資料轉換或頁面內對話框協調邏輯

中優先度

原因:

  • 它們語意上已是頁面型元件,但仍放在 components 根目錄
  • 目前仍可接受,但新功能不應沿用這種命名與放置方式擴散

中低優先度

  • 清理 src/stores/stores/* 重複結構
  • 檢查 components/base/* 是否要把頁面家族子元件搬到更明確的資料夾
  • 檢查空資料夾 src/components/base/management 是否仍需要保留
  • 重新評估 SKSearchFilter.vueSKFormEditDialog.vueSKTreeTable.vue 是否仍保持跨頁通用

新增或修改檔案時的判斷準則

  1. 這個檔案是否直接被 route 載入?
    • 是:優先放 views
  2. 這個檔案是否負責某個完整頁面的主畫面組裝?
    • 是:放頁面型元件層,不要塞進 base
  3. 這段重複的是模板還是流程?
    • 模板:抽元件
    • 流程:抽 composable 或 store
  4. 這個狀態是否跨頁共享,或需要快取 / 全域顯示控制?
    • 是:優先考慮 store
  5. 這個邏輯是否在處理 API、token、session、錯誤正規化?
    • 是:放 services
  6. 這個元件是否只屬於單一 domain?
    • 是:優先放到該 domain 目錄,例如 components/maintenance
  7. 這個抽象是否真的降低重複與理解成本?
    • 否:不要抽