关于 flutter-best-practices
面向 Flutter 开发者的应用架构与编码实践指南,覆盖分层、功能目录、状态建模、测试和项目评审。还提供按任务查阅参考资料的工作流。
主要功能
- 01分离 UI 与数据层
- 02按功能组织代码
- 03使用不可变显式状态
- 04遵循现代 Dart 编码实践
- 05按任务查阅架构参考资料
- 06提供功能开发与代码评审清单
适用场景
- 01规划新应用的架构与目录
- 02添加功能或新页面
- 03评审 Flutter 代码及测试
- 04处理多团队或多包项目
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ evanca/ flutter-ai-rules --skill flutter-best-practices安装后在 Claude Code 中输入/flutter-best-practices确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/architecture-layers.mddart-coding-practices.mdenterprise-scale.mdfeature-structure.mdlocalization-package-boundaries.md详细介绍
Flutter 最佳实践
构建易于维护的 Flutter 应用的规范,汇总自官方 Flutter 架构指南,以及 LeanCode 交付 40 多个 Flutter 项目的经验(包括一款由 30 名开发人员参与开发的银行应用)。编写新代码时请遵循这些规范;修改现有代码时,优先与周边代码库保持一致。如果现有代码与这些规范冲突,请指出冲突,而不要悄悄重写。
如何使用此技能
阅读与任务相匹配的参考文件。若任务涉及多个方面,请阅读多个文件(例如,新功能同时涉及结构和编码风格)。
| 任务 | 阅读 |
|---|---|
| 设计分层、确定逻辑归属、MVVM、仓库/服务 | references/architecture-layers.md |
| 创建/组织功能、文件夹结构、状态管理接线 | references/feature-structure.md |
| 编写或审查 Dart/Flutter 代码、组件、测试、lint | references/dart-coding-practices.md |
| 多团队/多包应用、monorepo、导航、本地化、API 契约、E2E 测试 | references/enterprise-scale.md |
| 应用本地化设置、可复用 UI 包的字符串归属、语言选择器可见性 | references/localization-package-boundaries.md |
对于简单任务(修复小组件、添加一行审查意见),仅遵循以下核心规则可能就足够了。
核心规则(始终遵循)
架构
- 分离 UI 与数据。 分为两个主要层:UI(视图 + 视图模型/cubit)和数据(仓库 + 服务)。依赖单向流动:
View → ViewModel → Repository → Service。底层绝不导入上层。仓库之间绝不相互依赖。 - 视图不包含业务逻辑。 组件可以包含显示/隐藏条件、动画、布局和简单的路由逻辑,但不能转换或判断数据。所有数据逻辑都放在视图模型(或 cubit/bloc)中,且视图模型无法访问
BuildContext。 - 按功能组织,而不是按层组织。 功能所需的一切——状态管理、组件、模型——都放在同一个功能目录下。不要创建顶层的
blocs/、widgets/、models/目录,把一个功能分散到整个目录树中。 - 状态不可变且明确。 将 UI 状态建模为 sealed/union 类型(initial / inProgress / failure / ready),以确保穷尽处理所有情况。一次性效果(如 snackbars、导航)应作为事件,而不是状态。
- 仅在确有价值时增加层。 从 view-model → API 客户端开始。需要缓存、离线支持或合并多个数据源时,再引入仓库。仅当逻辑需要合并多个仓库、确实复杂,或被多个视图模型复用时,才引入用例。
编码
- 优先使用表达意图的组件,而不是
Container。 使用Padding、SizedBox、ColoredBox、DecoratedBox、Center——它们可以声明为 const,且能清晰表达用途。只有在需要同时组合多个属性时,才使用Container。 - 使用现代 Dart。 使用模式匹配(
if (x case final v?))、可穷尽处理所有情况的 switch 表达式、records 和解构,以及集合if/for/spread 替代.add()循环;透传的异步函数使用表达式体(避免冗余的async/await)。 - 为返回 sliver 的组件添加
Sliver前缀,便于一眼发现其被误用于错误滚动上下文的情况。 - 让测试讲述一个故事。 使用表达力强的匹配器(
isEmpty、throwsA、isA、completion),并尽量减少依赖——测试 fixture 中优先使用普通的Text/SizedBox,而非设计系统组件。脱离组件树,单独测试 cubit/视图模型。 - 每个
// ignore:都必须在同一行或前一行说明原因。 使用专用的error/stackTrace参数记录错误,绝不要使用字符串插值。
工作流检查清单
添加新功能/屏幕
- 阅读 references/feature-structure.md, 并遵循现有项目的功能目录约定。
- 先将状态定义为联合类型,再定义 cubit/视图模型,最后编写 组件。通过构造函数注入依赖,并将其限定在功能的 组件子树内。
- 数据应通过仓库或类型化 API 客户端传入——绝不要在组件 内获取数据。
- 在连接 UI 细节之前,先为 cubit/视图模型逻辑添加单元测试。
审查 Flutter 代码
按重要性顺序检查:
- 逻辑是否位于正确的层(规则 1–2)?业务逻辑中是否有
BuildContext? - 状态是否建模为不可变联合类型,且所有情况都已处理?
- 功能是否自成一体,还是会访问其他功能的内部实现?
- 组件选择(规则 6)、现代 Dart(规则 7)、sliver 命名(规则 8)是否合适?
- 是否为逻辑编写了测试,且测试易读、依赖最少?
- 是否存在没有说明原因的
// ignore:、使用字符串插值的错误日志,或仍在扩散的弃用模式?
启动新项目
- 阅读 references/architecture-layers.md 了解分层蓝图,并阅读 references/feature-structure.md 了解 目录骨架。
- 如果涉及的团队超过约 2 个,或领域明显可分,则阅读 references/enterprise-scale.md,并考虑从第一天起就采用 Melos 单体仓库,按领域拆分为独立包。
- 尽早设置严格的 lint 规则(
leancode_lint或同类工具 + 自定义规则)——事后补上要昂贵得多。
软件包选型
本规范默认使用以下方案(如果代码库已有其他方案,可替换为项目本地的对应方案):
- 状态: 使用
bloc(Cubit)+freezed定义联合类型状态; 使用bloc_presentation处理一次性 UI 事件 - 依赖注入: 使用限定在组件子树内的
provider(接受其缺少编译时安全性的缺点,视为较轻的弊端) - 减少样板代码:
flutter_hooks - 单体仓库:
melos - 本地化:
flutter_localizations+intl,使用.arb文件 - Lint:
leancode_lint - E2E/UI 测试:
patrol
Flutter 官方指南不限定状态管理方案(MVVM 配合 ChangeNotifier 也可以);关键在于分层,而非所用软件包。关于理由和权衡,请参阅参考文件。
评论
支持 Markdown