什么是 FSD?

FSD Feature-Sliced Design 功能切片设计 是一种用于构建前端应用程序的架构方法。

可以将其理解为前端项目结构、代码约定和规则的规范。

它的目的是让项目在应对不断变化的业务需求时,更加易于理解和组织,便于扩展和维护。

FSD 是否适合你的项目?

  • 这是只适用于前端项目的架构方法论,不适用与后端项目
  • 只适用于面向用户的应用程序,而不适用与库或者UI工具包
  • 小项目不需要 FSD,会额外提高项目的复杂性
  • 即使是特别复杂的项目,也依然可以应用 FSD 的架构模式
设计概念

在 FSD 架构中,一个项目由层 Layers 组成,每层 Layers 由切片 Slices 组成,每个切片由段 Segments 组成。

公共 API (统一导出索引)

FSD 有一种 Public API 的接口设计方法,通过提供可从外部层访问的入口点并将模块封装在 Slice 下,可以仅公开必要的功能,同时隐藏内部结构。

每个 slicessegments 都应该有一个公共 API,一般情况下为当前目录下的 index 文件。

公共 API 是索引文件中公共模块聚合的地方。您可以从切片和段中仅提取必要的函数,并分离不需要的函数。此外,对于外部文件,该索引文件充当入口点。

└── features/ # ├── auth-form / # feature 的内部结构 | ├── ui/ # | ├── model/ # | ├── {…}/ # | ├── index.ts # 入口点及其公共 API
异常模式一

外部接口直接访问模块内部的模式。

改进的好处:通过仅导入允许的内容,您可以一目了然地确定正在访问哪些模块。

// features/todo-create-form/index.ts export { TodoCreateForm } from "./ui/TodoCreateForm"
- import { TodoCreateForm } from "@features/todo-create-form/ui/TodoCreateForm" + import { TodoCreateForm } from "@/features/todo-create-form"
异常模式二

当模块的内部目录结构发生变化时,会影响从外部可见的公共 API 的情况。

改进好处:功能的内部结构不暴露给外部用户,移动或重命名组件不会影响外部用户。

- import { Form } from "features/todo-create-form/ui/form" + import { TodoCreateForm } from "features/todo-create-form"
异常模式三

导致名称冲突的情况

// /features/todo-create-form/index.ts - export { Form } from "./ui/TodoCreateForm" + export { Form as TodoCreateForm } from "./ui/TodoCreateForm"
// /features/todo-edit-form/index.ts - export { Form } from "./ui/TodoCreateForm" + export { Form as TodoEditForm } from "./ui/TodoCreateForm"

由于“公共 API”作为索引文件是该模块的入口点,因此应该遵循以下规则:

  • 应用程序的其他部分,只能使用在公共 API 中定义的,对外暴露的模块实体
  • 未在公共 API 中定义的 slice 或 segment 应该被视为隔离的,只能由模块本身访问

声明良好的公共接口应该方便应用程序的其余部分使用,并且可以适应模块内部的更改。

公共 API 简化了导入和导出的工作,在对项目进行修改时,可以方便的统一修改,而不需要更改代码中各处的导入。

FSD 主要解决的问题

FSD 的主要目的在于实现高内聚低耦合 , 它根据代码的作用以及对项目的贡献来决定它们的位置。

FSD 通过约定的方式,在文件结构层面就已经实现了 多态封装继承抽象 等概念,确保了代码的隔离、可重用性和多功能性。

在 FSD 中,较低的层一般是属于比较抽象的,它们可以在较高的层中重复、多次的使用,这样就实现了 抽象多态 因为高层可以重复使用低层,所以也实现了 继承。

通过公共 API index,统一模块对外的入口,限制对 Slice 和 Segment 内部的访问,实现了 封装

💡FSD 通过其概念和标准,可以避免常规架构存在的问题,但是需要前期的了解和学习
优点

目录管理清晰、耦合度适中

通过 FSD,已经有了分层、切片、分段的标准化管理方法。代码按影响范围(层)、领域(切片)和技术目的(段)进行组织。此外,层之间的依赖关系是单向的,并且切片始终是松散耦合的。

这创建了一个易于每个人理解的标准化架构。我个人觉得它融合了 layered architecturepackage by feature 两者的思想,很容易想象,也有一种统一感

业务和用户需求导向

当应用程序被分割成业务领域时,通过浏览代码就可以发现和深入的了解项目的所有功能

功能变化和重构时的稳定性

由于层与层之间的依赖关系以及公共 API 的思想,每个组件模块都有其目的和可预测的依赖关系。该设计允许我们可以安心地进行更改

拥有支持开发的工具

拥有相关的支持工具来加速开发,例如 Lint 和 IDE 插件和扩展

可以使用 feature-sliced/eslint-config 自动检查层之间的依赖关系和公共 API 规则

缺点
  • 与常规架构相比,需要转变思维去适应
  • 有一定的上手成本,需要团队统一规范和遵守
  • 文档中有很多空白页,文档的结构有时很难找到想要的信息
  • 不太适合 MVP 项目或者小的项目,需要付出额外的精力

写在最后,没有银弹

我认为前端架构没有正确的答案,Feature-Sliced 架构也并非适用于所有的前端项目

尤其当前大多数框架、库都提供了自己的官方标准模板,例如 NextJS 和 Sveltekit 等更是对目录结构的要求有一些限制。 同时,FSD 架构的应用还需要考虑到项目、团队等诸多因素

不过,FSD 也许并不是最适合你的项目架构,但是它的概念以及一些规范,也非常适合去学习和借鉴并应用到自己的项目中。

参考
https://github.com/feature-sliced/awesome