Flutter 项目,我更推荐 Feature-First
Layer-First 优先按技术层组织代码。Feature-First 以功能为顶层组织单位,将同一功能相关的实现和测试聚合到同一个模块。
我更推荐 Feature-First:让功能有明确的归属和对外入口,再由主应用按需组合。
用 package 封装功能,主应用负责组合
以 auth package 和宿主应用 mobile_app 为例:
text
project/
├── apps/mobile_app/ # 宿主应用
├── packages/auth/ # 功能 package
│ ├── lib/
│ │ ├── auth.dart # 对外入口
│ │ └── src/ # 内部实现
│ ├── test/
│ └── pubspec.yaml
└── pubspec.yaml
auth 通过 auth.dart 暴露供外部使用的能力;mobile_app 声明依赖、接入页面并配置导航。功能的内部实现留在所属 package 中。
需要平台相关能力时,功能包可以依赖 plugin。plugin 是包含 Dart 接口和平台实现的一类 package。
用 Pub workspaces 管理这些包
Pub workspaces 让同一仓库中的多个包统一解析依赖、共享根锁文件,各包仍保留自己的依赖声明。
先在根目录的 pubspec.yaml 中登记成员:
yaml
name: app_workspace
publish_to: none
environment:
sdk: ^3.6.0
workspace:
- apps/mobile_app
- packages/auth
再让成员启用 resolution: workspace,并声明实际使用的依赖。例如 mobile_app 引用 auth:
yaml
# apps/mobile_app/pubspec.yaml
name: mobile_app
resolution: workspace
environment:
sdk: ^3.6.0
dependencies:
flutter:
sdk: flutter
auth:
path: ../../packages/auth
auth 包也需要启用 resolution: workspace。根包和成员包的 SDK 约束下限至少为 Dart 3.6.0,已有更高下限时保持原值;path 是这里采用的本地引用方式。
最后在根目录运行 flutter pub get。应用通过 package:auth/auth.dart 使用模块,再接入自己的页面和导航。工作区管理包,依赖声明连接包,主应用组合功能。