0Pricing
Frontend Academy · 课时

基于功能的文件夹结构

按功能领域而不是按类型组织代码,将测试、样式和组件放在一起,并使用 eslint-plugin-boundaries 强制执行边界。

基于功能的文件夹结构 是 CoddyKit 上的免费 Frontend Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Frontend Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Frontend Academy 课程共包含 4 节课。

组织代码的两种方式

您可以按类型分组代码(components/、hooks/、services/、types/),也可以按功能分组(auth/、checkout/、dashboard/——每个目录都包含自己的组件、钩子等)。对于中大型应用,按功能组织更有优势。

按类型组织:默认陷阱

经典的 React 教程结构会按类型将所有内容分组。这种结构扩展性很差:每次修改文件都要涉及多个不相关的文件夹,而“查找所有结账代码”意味着要在整个目录树中搜索。

// Type-based (avoid for large apps):
src/
  components/
    Button.tsx
    LoginForm.tsx
    CartItem.tsx
  hooks/
    useAuth.ts
    useCart.ts
  services/
    auth.ts
    cart.ts
  types/
    User.ts
    CartItem.ts

按功能组织的结构

将与某项功能相关的所有内容放在同一个文件夹中。容易查找、容易删除,也容易理解。

src/
  features/
    auth/
      LoginForm.tsx
      SignupForm.tsx
      useAuth.ts
      auth.service.ts
      auth.types.ts
      auth.test.tsx
    cart/
      CartItem.tsx
      CartSummary.tsx
      useCart.ts
      cart.service.ts
      cart.types.ts
  shared/
    components/
      Button.tsx
    hooks/
      useDebounce.ts

功能内部的就近组织

一个功能文件夹包含:组件、钩子、服务、类型和测试——该领域所需的全部代码。新开发者想了解身份验证?打开 auth/。想删除身份验证?删除这个文件夹即可。

共享代码与功能代码

被两个或更多功能使用的代码移到 shared/(或 lib/)中。只被一个功能使用的代码留在该功能内部。不要因为“以后可能复用”就提前抽取——等到第二次使用时再抽取。

功能边界规则

功能不应直接相互导入。如果两个功能需要共享代码,就将共享部分移到 shared/。如果它们需要协调,就使用事件或应用层的共享存储。

使用 ESLint 强制执行边界

使用 eslint-plugin-boundaries 或 eslint-plugin-import 强制执行以下规则:功能可以从 shared 导入,但不能相互导入。

// .eslintrc.json
{
  "plugins": ["boundaries"],
  "settings": {
    "boundaries/elements": [
      { "type": "feature", "pattern": "src/features/*" },
      { "type": "shared",  "pattern": "src/shared/*" }
    ]
  },
  "rules": {
    "boundaries/element-types": ["error", {
      "default": "disallow",
      "rules": [
        { "from": "feature", "allow": ["shared"] },
        { "from": "shared",  "allow": ["shared"] }
      ]
    }]
  }
}

每个功能的公共 API

每个功能都通过 features/auth/index.ts 导出公共 API。其他代码从 '@/features/auth' 导入,而不是使用深层路径。这样可以重构内部实现,而不会破坏使用方。

// features/auth/index.ts
export { LoginForm } from './LoginForm';
export { useAuth } from './useAuth';
export type { User, AuthState } from './auth.types';

// Consumers:
import { LoginForm, useAuth } from '@/features/auth';
// NOT: import { LoginForm } from '@/features/auth/LoginForm';

嵌套子功能

大型功能可以包含子文件夹:dashboard/widgets/、dashboard/charts/。避免嵌套超过 2—3 层,否则搜索会变得非常痛苦。

路由放在哪里

页面和路由可以放在顶层的 pages/ 或 routes/ 文件夹中。它们应保持精简:从功能中引入组件和钩子,再将它们组合起来。

src/
  pages/
    Dashboard.page.tsx   // composes Dashboard widgets from features/dashboard/
    Cart.page.tsx        // composes from features/cart/
  features/
  shared/

迁移现有应用

只从新功能开始——将新代码放入 features/。不要一次性重构所有内容。修改旧文件时,再逐步迁移它们。ESLint 边界规则可以防止新结构逐渐退化。

按类型组织仍然适用的情况

对于非常小的应用(组件少于 30 个)或库,按类型组织没有问题。一旦出现明确的业务领域(身份验证、结账、账单、设置),就应采用按功能组织的方式。

快速检查

与按文件类型分组相比,按功能分组代码的主要组织优势是什么?

回顾:按功能组织的结构

features/ 包含特定领域的代码;shared/ 包含跨功能的工具。每个功能都导出一个公共 index.ts。功能之间不能相互导入,只能从 shared 导入。使用 eslint-plugin-boundaries 强制执行这些规则。页面和路由负责组合各个功能。应逐步迁移。对于小型应用,按类型组织没有问题。

常见问题解答

「基于功能的文件夹结构」课时是免费的吗?

是的 — 「基于功能的文件夹结构」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Frontend Academy 课程的其余内容,请升级到 CoddyKit PRO。 Frontend Academy 课程共包含 4 节课。

「基于功能的文件夹结构」这节课中我会学到什么?

按功能领域而不是按类型组织代码,将测试、样式和组件放在一起,并使用 eslint-plugin-boundaries 强制执行边界。 你通过在浏览器中直接运行的动手代码来练习 Frontend Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Frontend Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Frontend Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「基于功能的文件夹结构」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Frontend Academy 课中编写并运行代码吗?

能。每节 Frontend Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 原子设计:原子、分子与有机体
  2. 使用 Turborepo 设置单体仓库
  3. 微前端:模块联邦
  4. 基于功能的文件夹结构
← 返回 Frontend Academy