前端工程化 - 看起来“很合理”的feature目录结构

看起来“很合理”的feature目录结构

src/
 ├─ feature/
 │   └─ Order/
 │       ├─ index.vue
 │       ├─ components/
 │       │   ├─ OrderTable.vue
 │       │   ├─ FilterForm.vue
 │       │   ├─ AdvancedFilter.vue
 │       │   ├─ ExportButton.vue
 │       │   ├─ StatusSelect.vue
 │       │   └─ OrderDetailDialog.vue
 │       ├─ hooks/
 │       │   ├─ useOrder.ts
 │       │   └─ usePermission.ts
 │       ├─ api.ts
 │       └─ utils.ts
<template>
  <div class="order-page">
    <FilterForm
      :filters="filters"
      @change="onFilterChange"
    />

    <AdvancedFilter
      v-if="showAdvanced"
      :filters="filters"
      @change="onAdvancedChange"
    />

    <div class="actions">
      <ExportButton
        :orders="orderList"
        :permission="permission"
      />
      <StatusSelect
        :selected="selectedOrders"
        @change="onStatusChange"
      />
    </div>

    <OrderTable
      :data="orderList"
      @row-click="openDetail"
    />

    <OrderDetailDialog
      v-if="showDetail"
      :order-id="currentOrderId"
      @close="showDetail = false"
    />
  </div>
</template>

<script setup lang="ts">
import FilterForm from './components/FilterForm.vue'
import AdvancedFilter from './components/AdvancedFilter.vue'
import ExportButton from './components/ExportButton.vue'
import StatusSelect from './components/StatusSelect.vue'
import OrderTable from './components/OrderTable.vue'
import OrderDetailDialog from './components/OrderDetailDialog.vue'

import { useOrder } from './hooks/useOrder'
import { usePermission } from './hooks/usePermission'

const {
  orderList,
  filters,
  fetchOrders,
  onFilterChange,
  onAdvancedChange,
  selectedOrders,
  onStatusChange,
  openDetail,
  showDetail,
  currentOrderId
} = useOrder()

const permission = usePermission()
</script>

表面看:

  • 目录清晰
  • 按类型拆
  • 每个东西都有地方放

👉 但这是一个“工程灾难的温床”。

错误1:

一个业务需求会横跨所有目录

如: 高级筛选条件变更,同时影响导出逻辑

在这个目录结构下,需要改:

  • components/AdvancedFilter.tsx
  • services/orderApi.ts
  • hooks/useOrder.ts
  • components/ExportButton.tsx

一个需求,改4个层级,而不是一个业务单元

边界不是按类型,而是按变化

错误2:

所有能力默认都是同级的

在这个结构里

  • 订单列表
  • 导出
  • 状态变更
  • 高级筛选

在结构上是完全平级的,但是在业务上,他们的重要性完全不同

后果:

  • 所有组件都在首屏被 import
  • 所有逻辑都会进主 bundle
  • lazy 很难加(因为到处有依赖)

技术上”lazy”,业务上完全不”lazy”

错误3:

通常这个面会这么写:

const OrderPage = lazy(() => import('./pages/OrderPage'))

然后会说:

我们已经做了懒加载了

但在orderPage 的chunk里:

  • OrderTable
  • AdvancedFilter
  • ExportButton
  • OrderDetailModal
  • 所有 hooks
  • 所有 api

这不是拆分,这是延迟加载一坨代码

错误4:

业务逻辑 被UI吸走了

典型现象:

<!-- ExportButton.vue -->
<script setup>
if (permission.canExport && filters.status === 'completed') {
  enableExport.value = true
}
</script>

<!-- StatusSelect.vue -->
<script setup>
if (userRole === 'admin') {
  allowChange.value = true
}
</script>

权限,规则散落在各个组件

后果:

  • 改规则 = 全页面搜 if
  • 新人不敢动
  • 测试成本爆炸

这是边界彻底失效的信号

错误5

hook 变成”上帝对象”

// useOrder.ts
export function useOrder() {
  // 拉列表
  // 权限判断
  // 高级筛选逻辑
  // 导出状态
  // 详情弹窗控制
}

看似 “逻辑被抽出来了”

实际只是把混轮从组件挪到了hook

hook 不是边界, 只是函数形式的容器

posted @ 2026-02-11 14:06  MT-Jaxon  阅读(3)  评论(0)    收藏  举报