FSA全栈行动 FSA全栈行动
首页
  • 移动端文章

    • Android
    • iOS
    • Flutter
  • 学习笔记

    • 《Kotlin快速入门进阶》笔记
    • 《Flutter从入门到实战》笔记
    • 《Flutter复习》笔记
前端
后端
  • 学习笔记

    • 《深入浅出设计模式Java版》笔记
  • 逆向
  • 分类
  • 标签
  • 归档
  • LinXunFeng
  • GitLqr

公众号:FSA全栈行动

记录学习过程中的知识
首页
  • 移动端文章

    • Android
    • iOS
    • Flutter
  • 学习笔记

    • 《Kotlin快速入门进阶》笔记
    • 《Flutter从入门到实战》笔记
    • 《Flutter复习》笔记
前端
后端
  • 学习笔记

    • 《深入浅出设计模式Java版》笔记
  • 逆向
  • 分类
  • 标签
  • 归档
  • LinXunFeng
  • GitLqr
  • AndroidUI

  • Android第三方SDK

  • Android混淆

  • Android仓库

  • Android新闻

  • Android系统开发

  • Android源码

  • Android注解AOP

  • Android脚本

  • AndroidTv开发

  • AndroidNDK

  • Android音视频

  • Android热修复

  • Android性能优化

  • Android云游戏

  • Android插件化

  • iOSUI

  • iOS工具

  • iOS底层原理与应用

  • iOS组件化

  • iOS音视频

  • iOS疑难杂症

  • iOS之Swift

  • iOS之RxSwift

  • iOS开源项目

  • iOS逆向

  • Flutter开发

    • Dart - 抽象类的实例化
    • Flutter - 打印好用的Debug日志
    • Flutter - 混合开发
    • Flutter - 解决混合开发iOS脚本打包遇到的问题
    • Flutter - 低版本在iOS14上遇到的问题与解决方案
    • Flutter - 解决原生弹窗的触摸事件被Flutter响应的问题
    • Flutter - 实现列表上下拉切换header
    • Flutter - 获取ListView当前正在显示的Widget信息
    • Flutter - 列表滚动定位超强辅助库,墙裂推荐!🔥
    • Flutter - 快速实现聊天会话列表的效果,完美💯
    • Flutter - 聊天输入框更新文本时的必备优化点🔖
    • Flutter - 我给官方提PR,解决run命令卡住问题 😃
    • Flutter - 探索run命令到底做了什么 🤔
    • Flutter - 引擎调试(iOS篇)🛠
    • Flutter - 引擎调试bug到提交PR实战 🐞
    • Flutter - 船新升级😱支持观察第三方构建的滚动视图💪
    • Flutter - 瀑布流交替播放视频 🎞
    • Flutter - IM保持消息位置大升级(支持ChatGPT生成式消息) 🤖
    • Flutter - 滚动视图中的表单防遮挡 🗒
    • Flutter - 秒杀1/2曝光统计 📊
    • 一天内加入 Flutter 和 FlutterCandies 两大组织是什么体验 🧐
    • Flutter - 如何快速搓一个微信通讯录列表(azlist) 📓
    • Flutter - 混编项目集成Shorebird热更新🐦(安卓篇)
    • Flutter - 混编项目集成Shorebird热更新🐦(iOS篇)
    • Flutter - 解决返回原生页面时dispose方法未被触发的问题 🐞
    • Flutter - 升级3.19之后页面多次rebuild?🤨
    • Flutter - 热更新 Shorebird 1.0 正式版来了 🐦
    • Flutter - 使用Pigeon实现视频缓存插件 🐌
    • Flutter - 轻松搞定屏幕旋转功能 😎
    • Flutter - 解决Connection closed before full header was received
    • Flutter - 实现聊天键盘与功能面板的丝滑切换 🍻
    • Flutter - 支持观察NestedScrollView,兼容性更强 😈
    • Flutter - 聊天键盘与面板丝滑切换的强势升级 🍻
    • Flutter - 升级到3.24后页面还会多次rebuild吗?🧐
    • Flutter - 轻松实现PageView卡片偏移效果
    • Flutter - 轻松搞定炫酷视差(Parallax)效果
    • Flutter - 危!3.24版本苹果审核被拒!
    • Flutter - 子部件任意位置观察滚动数据
    • Flutter - iOS编译加速
    • Flutter - Xcode16 还原编译速度
    • Flutter - GetX Helper 助你规范应用 tag
    • Flutter - GetX Helper 如何应用于旧页面
    • Flutter - 聊天面板库动画生硬?这次让你丝滑个够
    • Flutter - 使用本地 DevTools 验证 SVG 加载优化
    • Flutter - 详情页 TabBar 与模块联动?秒了!
    • Flutter - 详情页初始锚点与优化
    • Flutter - Melos Pub workspaces 实践
    • Flutter webview 崩溃率上升怎么办?我的分析与解决方案
    • Flutter 多仓库本地 Monorepo 方案与体验优化
      • 一、前言
      • 二、调整
        • .gitignore
        • 工作区结构
      • 三、辅助命令与脚本
        • 项目运行
        • 隐藏无用项目
        • 优化代码分析压力
        • 打包
      • 四、最后
  • 移动端
  • Flutter开发
LinXunFeng
2025-10-25
目录

Flutter 多仓库本地 Monorepo 方案与体验优化

欢迎关注微信公众号:[FSA全栈行动 👋]

# 一、前言

在上一篇 Flutter - Melos Pub workspaces 实践 中我们探讨了 Monorepo 实践,但这与我们当前多仓库、多业务包的现状不符。我们希望在维持多仓库管理模式的同时,也能利用 Melos 和 Pub workspaces 的优势。

本文的主题 —— “拼好包”,就是为解决这一问题而提出的方案。

https://github.com/LinXunFeng/local_pub_workspace (opens new window)

# 二、调整

延用上一篇的工作区 lxf_workspace,不同之处在于,我们会按需将其他独立仓库的 app 工程和业务包通过 Git 拉取放置在 apps 和 packages 目录下,但这些文件仅存放于本地,并不会提交到工作区仓库。

# .gitignore

在 apps 和 packages 目录下都创建名为 .gitkeep 的空白文件,并将如下内容添加至 .gitignore。

# .gitignore

!apps/.gitkeep
!packages/.gitkeep

这样可保持这两个空目录同步至 lxf_workspace 仓库,别人拉下来就不用再手动创建他们了。

# 工作区结构

这里以上一篇中的工作区仓库为例,结构如下

.
├── README.md
├── analysis_options.yaml
├── apps
│   ├── .gitkeep
│   └── app_a
├── melos.yaml
├── packages
│   ├── .gitkeep
│   ├── package_a
│   ├── package_b
│   ├── package_c
│   └── ...
├── pubspec.lock
├── pubspec.yaml
├── script
│   └── apply_app_pubspec_overrides.sh
└── tool
    ├── README.md
    ├── commands
    │   ├── dependency_overrides.dart
    │   ├── setup_workspace.dart
    │   ├── update_analysis_options.dart
    │   ├── update_app_pubspec_overrides.dart
    │   ├── update_launch_json.dart
    │   └── update_settings_json.dart
    ├── core
    │   └── workspace_manager.dart
    └── main.dart
文件(夹) 作用
analysis_options.yaml Dart 代码分析配置文件,主要用来减少不必要的分析
apps 【本地】 存放壳工程,或其它 app 工程
packages 【本地】 存放各个仓库的工程,如:业务工程,组件库
pubspec.yaml 声明 workspace,重写依赖,定义 Melos 脚本
script 存放了各种辅助脚本
tool 存放了各种辅助命令

在 tool 目录下,存放了一些十分有用的辅助命令,基本上都是在 melos bs 后自动执行的,无须手动操作。

# pubspec.yaml

melos:
  scripts:
    prepare: melos bootstrap
    clean: melos clean
    pub_upgrade:
        run: flutter pub upgrade
    # 更新工作区的 launch.json 文件
    update_launch_json: dart tool/main.dart update-launch
    # 更新工作区的 settings.json 文件
    update_settings_json: dart tool/main.dart update-settings
    # 更新工作区的 analysis_options.yaml 文件
    update_analysis_options_yaml: dart tool/main.dart update-analysis
    # 更新所有 app 工程的 pubspec_overrides.yaml 文件
    update_app_pubspec_overrides: dart tool/main.dart update-pubspec-overrides
    # dependency_overrides 本地仓库执行 flutter pub get
    deps_overrides_get: dart tool/main.dart dependency-overrides --get
    # dependency_overrides 本地仓库执行 flutter pub upgrade
    deps_overrides_upgrade: dart tool/main.dart dependency-overrides --upgrade
    # 设置工作空间依赖
    setup_workspace: dart tool/main.dart setup-workspace
    setup_workspace_no: dart tool/main.dart setup-workspace --no-workspace

  command:
    bootstrap:
      hooks:
        # 在 bootstrap 执行后执行
        post: |
          echo "更新 VSCode settings.json 配置..."
          melos run update_settings_json
          echo "更新 VSCode launch.json 配置..."
          melos run update_launch_json
          echo "更新 analysis_options.yaml 配置..."
          melos run update_analysis_options_yaml
          # melos run deps_overrides_get
          melos run deps_overrides_upgrade

注意,因为在研发过程中,我们只关心当前被集成的包,如本地 packages 目录下有十几个包,但我的需求只需要我处理 package_a,则工作区的 pubspec.yaml 需做如下调整

# pubspec.yaml
workspace:
  - apps/app_a
  - packages/package_a
  - packages/package_a/example
  # - packages/package_b
  # - packages/package_b/example
  ...

建议把 packages 下的业务包都列出来,这样大家拉下来后只需要做取消注释操作,而不需要自己手动添加。

以下内容均以该配置进行说明!

# 三、辅助命令与脚本

# 项目运行

VSCode 虽提供自动生成 launch.json 的便捷功能(删除旧文件后点击创建 launch.json 文件),但对于包含多个 Flutter 包的 Monorepo 项目而言,这种自动生成方式会导致:

  1. 配置冗长混乱:  生成的运行配置列表过于庞大。
  2. 项目难以区分:  当多个包内存在同名 example 目录时,调试选项会变得模糊不清,严重影响开发效率。

为解决上述问题,我实现了 update-launch 命令,该命令旨在提供一个简洁、高效的调试配置管理方案:

  1. 智能解析:  自动解析项目根目录 pubspec.yaml 文件中的 workspace 配置。
  2. 精准生成:  为工作区内的每个 Flutter 包生成命名清晰、易于辨识的运行配置。生成时,优先为包的 example 目录创建配置;若无 example 目录,则直接为包本身创建配置。例如,只会保留 apps/app_a 和 packages/package_a/example 的配置,如果 package_a 没有 example,则为 packages/package_a。

通过在 melos 中设置钩子,update-launch 脚本会在执行 melos bs 命令后自动运行。这确保了 .vscode/launch.json 文件始终保持动态更新,从而在 VSCode 的“运行和调试”面板中呈现一个精简、有序且易于选择的调试选项列表,极大提升了 Monorepo 环境下的开发体验。

# 隐藏无用项目

为了保持工作区整洁,避免 packages 目录下项目过多造成干扰,我们可以通过配置 .vscode/settings.json 中的 files.exclude 选项来隐藏当前开发任务不需要的包。例如,将 package_b 的路径加入该配置即可在文件浏览器中隐藏它,从而让我们更专注于相关代码。

{
  "files.exclude": {
    // "**/apps/app_a/**": true,
    // "**/packages/package_a/**": true,
    "**/packages/package_b/**": true,
    "**/packages/package_c/**": true,
    "**/packages/package_d/**": true,
    "**/packages/package_e/**": true
  },
}

当项目包增多时,手动修改 settings.json 切换文件可见性效率低下,而 update-settings 命令可自动化此过程!

它会读取 pubspec.yaml 的 workspace 配置,并在 settings.json 中动态注释/取消注释 files.exclude 规则,只显示当前工作区所需项目。

该脚本已配置为在 melos bs 命令后自动运行,无需手动干预。

# 优化代码分析压力

随着 packages 数量的增加,即使在 VSCode 中隐藏了不相关的项目,Dart 分析器仍会分析所有代码,这会导致分析速度显著变慢,影响开发效率。

解决方案:通过在 analysis_options.yaml 文件中配置 analyzer.exclude,明确排除不需要分析的目录。

示例:若要排除 package_b,可按如下方式配置:

analyzer:
  exclude:
    # - apps/app_a/**
    # - packages/package_a/**
    - packages/package_b/**

为了简化此过程,我已实现自动化。

update-analysis 脚本会在 melos bs 执行后自动运行,根据当前工作区动态更新 analysis_options.yaml 文件,确保分析器始终保持高效。

# 打包

Monorepo 架构能有效提升代码复用和管理效率。然而,当项目采用多仓库、多业务包模式时,如何将 Monorepo 的优势与现有工作流结合,并解决特定打包难题,是我们需要面对的挑战。

本文聚焦于 app_a 的打包问题,并提出一套基于 pubspec_overrides.yaml 的解决方案。

app_a 打包面临的挑战

在当前的多仓库 Monorepo 环境下,app_a 的打包流程面临两大核心挑战:

  1. Pub workspaces 限制与 resolution: workspace 冲突: app_a 的 pubspec.yaml 中声明了 resolution: workspace,这表示它依赖于工作区内的包。然而,当 app_a 被单独拉取或在非 Monorepo 环境下构建时,由于无法解析 workspace 依赖,会导致依赖拉取失败。为了解决这个问题,在打包时需要将此配置注释掉或重写。
  2. 功能分支开发与 Git 依赖管理: app_a 通常依赖于 master 分支上的业务包,例如:
# app_a/pubspec.yaml
environment:
  sdk: ">=3.6.0 <4.0.0"
resolution: workspace

dependencies:
  package_a:
    git:
      url: git@code.gitlab.com:lxf/package_a.git
      ref: master

当需要对 package_a 进行功能开发时(例如在 feature/拼好包分支 上),传统的做法是在 app_a 的 dependency_overrides 中重写 package_a 的依赖,并提交到版本库。

然而,在 app_a 和 package_a 都处于 workspace 下的 Monorepo 结构中,这种直接重写会导致冲突和报错,无法正常打包。


解决方案:pubspec_overrides.yaml 动态配置

为了解决上述挑战,我采用了基于 pubspec_overrides.yaml 的动态配置方案,它将开发与打包时的依赖管理进行分离:

1、生成预备配置 (update_app_pubspec_overrides) :

在开发阶段,通过执行 update_app_pubspec_overrides 命令,为每个 app 工程(例如 app_a)生成一个 pubspec_overrides.yaml 文件。这个文件包含了所有打包所需的重写规则,例如修正 resolution 配置、指定 Git 分支依赖等。关键在于,这些规则在生成时全部被注释掉。此文件会随需求分支一同提交到版本控制系统。

生成的 pubspec_overrides.yaml 示例内容如下:

# resolution:
# dependency_overrides:
# # ====== app 工程中的 dependency_overrides
# # ====== workspace 和 dependency_overrides 项目的 git 依赖
#   package_a:
#     git:
#       url: git@code.gitlab.com:lxf/package_a.git
#       ref: feature/拼好包分支

该文件主要包含以下几类重写:

  • 重写 resolution: 配置。
  • 同步 app 工程下 pubspec.yaml 中定义的 dependency_overrides。
  • 同步工作区 pubspec.yaml 中 workspace 和 dependency_overrides 部分的 Git 依赖。

2、打包时应用配置 (apply_app_pubspec_overrides.sh) :

在 Jenkins 打包流程开始前,执行 apply_app_pubspec_overrides.sh 脚本。该脚本会自动取消 pubspec_overrides.yaml 文件中的注释,使其中定义的打包专用重写规则生效。这样,打包系统就能正确解析依赖,顺利完成构建。

当需求分支合并到 master 后,pubspec_overrides.yaml 文件应还原为初始的注释状态(例如只包含 # resolution:)。update-app-pubspec-overrides --restore 提供了还原功能,建议通过 CI/CD 流程自动完成此还原操作。

当然,这里的打包只是个简单的解决思路,请结合自身情况处理即可。

# 四、最后

通过 pubspec_overrides.yaml 动态配置方案,我们实现了开发与打包流程的解耦,有效解决了 app_a 在 Monorepo 环境下的依赖管理和打包难题。

研发流程:

  1. 更新 workspace 配置,取消需求涉及的包的注释。
  2. 执行 melos bs,自动完成包依赖解析和配置更新。
  3. 专注于功能开发。

打包流程:

  1. 执行 melos run update_app_pubspec_overrides。
  2. 提交 app 下更新的 pubspec_overrides.yaml。
  3. 触发 Jenkins 打包,apply_app_pubspec_overrides.sh 脚本将自动激活打包配置。

好了,本篇到此结束,这两篇 Monorepo 的应用只是结合我自身使用场景去阐述的,如有不同意见,以你的为准,欢迎在评论区留下你的见解。

#Dart#Flutter#Melos#Pub workspaces#Monorepo
上次更新: 2025/10/26, 06:32:15
Flutter webview 崩溃率上升怎么办?我的分析与解决方案

← Flutter webview 崩溃率上升怎么办?我的分析与解决方案

最近更新
01
Flutter webview 崩溃率上升怎么办?我的分析与解决方案
10-19
02
Flutter - Melos Pub workspaces 实践
10-12
03
Flutter - 详情页初始锚点与优化
08-24
更多文章>
Theme by Vdoing | Copyright © 2020-2025 FSA全栈行动
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×