FlutterUnit | 切换到 workspace 结构

1,165 阅读6分钟

ext.png

不知不觉 Flutter 诞生已经 10 年了,进入大众的视野也历经七年之痒。Dart 语言在 Flutter 的加持逐步迭代,从 空安全模式匹配、再到对 ffi 的支持,如今 workspace 的推出,已经即将支持的宏,正在让 dart 完成蜕变,我也很高兴看着 Dart 一步步地成长。


1. workspace 是干嘛的

终于,Flutter 在 dart sdk 3.5及以上版本,支持了 workspace 管理项目子模块。也是我期盼已久的一个特性,本文将带大家看一下 workspace 的用途,并将我的 FlutterUnit 开源项目改变成 workspace 结构:

首先,通过命令行查看一下 flutter 版本,需要保证你的 Dart sdk 是 3.5+

--[· flutter --version

Flutter 3.24.3 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 2663184aa7 (8 weeks ago) • 2024-09-11 16:27:48 -0500
Engine • revision 36335019a8
Tools • Dart 3.5.3 • DevTools 2.37.3

我们先通过 toly_flutter 的项目,了解 workspace 的用途。通过下面的命令:

  • 创建 toly_flutter 主项目;
  • 项目中创建一个 modules 文件夹,盛放子模块;
  • 创建 modules1、modules2 两个子模块。

--[· flutter create toly_flutter --org com.toly994

--[· cd toly_flutter
--[· mkdir modules
--[· cd modules
--[· flutter create --template=package modules1
--[· flutter create --template=package modules2

2. 以前本地模块的依赖关系

我们此时分别在 modules1 和 modules2 中提供两个方法:

---->[modules/modules1/lib/modules1.dart]---
library modules1;

class Modules1 {
  String get version => 'v0.0.1';
  String get name => 'modules1';
  String get display => '$name:$version';
}

---->[modules/modules1/lib/modules2.dart]---
library modules2;

class Modules2 {
  String get version => 'v0.0.1';
  String get name => 'modules2';
  String get display => '$name:$version';
}

主项目如果想要使用两个模块中的内容,在之前可以通过 dependencies 将两个模块进行本地依赖:

---->[pubspec.yaml]---
dependencies:
  modules1:
    path: modules/modules1
  modules2:
    path: modules/modules2

这样,引入模块文件,就可以使用独立模块中的类、对象、方法。

---->[lib/main.dart]---
import 'package:modules1/modules1.dart';
import 'package:modules2/modules2.dart';

void main() {
  String m1 = Modules1().display;
  String m2 = Modules2().display;
}

此时 modules1 和 modules2 和发布在 pub 中的远程仓库没什么区别。每个模块之间是独立的,它们可以各自依赖其他的包,比如现在 modules1modules2 需要依赖计算模块 calculator。那就需要 同时在两个 modules 中增加本地对 calculator 的依赖;

如果 toly_flutter 也需要依赖 calculator ,那就要写三份依赖关系。如果 calculator 是一个 pub 三方库,那么三者依赖的 calculator 版本可以写的不一样,这就会使得依赖变得复杂,增加依赖版本冲突的概率。

而且如果想要升级依赖,需要一个个模块进行修改,非常繁琐。

对于项目中的模块和依赖关系而言,如何统一进行组织,让它们更好地工作,这就是工作空间 workspace 的必要性。


3. workspace 重磅登场

工作空间可以大大简化模块依赖关系,总得来说有两点优势:

[1]: 工作空间依赖的三方库,可以被其子模块访问。
[2]: 工作空间中的子模块可以相互访问。

比如 toly_flutter 作为工作空间, modules1modules2 作为其子模块,那么当 toly_flutter 依赖 flutter_calculatortolyui ;那么两个 modules 就可以直接导入 flutter_calculatortolyui 的内容进行使用。另外 modules1 也可以直接导入访问 modules2 的内容。
工作空间打破了包与包之间的次元壁,让它们可以更便捷地为互相沟通。


workspace 使用起来也非常简单,首先在 toly_flutter 的 pubspec.yaml 最外层增加 workspace 节点,其下声明工作空间中的模块:

---->[pubspec.yaml]---
workspace:
  - modules/modules1
  - modules/modules2
  
dependencies:
  flutter_calculator: 0.0.4
  tolyui: 0.0.3+2

然后两个子模块中最外层增加 resolution 节点,置为 workspace 即可。这样你就完成了一个工作空间,是不是非常简单。

---->[modules/modules1/pubspec.yaml]----
resolution: workspace

---->[modules/modules2/pubspec.yaml]----
resolution: workspace

目前对于比较大的项目来说, 开发过程中 dart 的代码分析会占据很大内存,动辄三四个 G, 据说 workspace 会更利于解析,而减低内存消耗,切换到 workspace 后,大家也可以关注一下。


4. FlutterUnit 切换到 workspace

FlutterUnit 在设计之初就一直践行着模块独立划分,所以迁移到 workspace 非常简单。如下所示,FlutterUnit 的模块按照功能放置在 modules 文件夹内:

只要在最外层的 pubspec.yaml 中增加 workspace 节点,然后件各模块配置其中。注意 sdk 需要 3.5.0+

---->[pubspec.yaml]---
environment:
  sdk: ">=3.5.0 <4.0.0"
  
workspace:
  - modules/basic_system/app
  - modules/basic_system/app_update
  - modules/basic_system/authentication
  - modules/basic_system/components
  - modules/basic_system/l10n
  - modules/basic_system/storage
  - modules/basic_system/toly_ui
  - modules/basic_system/utils

  - modules/knowledge_system/algorithm
  - modules/knowledge_system/artifact
  - modules/knowledge_system/awesome
  - modules/knowledge_system/layout

  - modules/painting_system/draw_system

  - modules/tools_system/treasure_tools

  - modules/widget_system/widget_module
  - modules/widget_system/widgets

其他子模块的 pubspec.yaml 增加 resolution: workspace

---->[其他子模块/pubspec.yaml]----
environment:
  sdk: ">=3.5.0 <4.0.0"
  flutter: ">=1.17.0"
  
resolution: workspace

然后子模块之前的依赖就可以全部去掉,将所有的三方依赖集中到工作空间中,从而实现依赖版本的统一。以后想要更新三方依赖版本,在工作空间中处理即可。立马清爽 ~

---->[pubspec.yaml]---
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  cupertino_icons: ^1.0.4

  # 路由与状态管理
  go_router: ^14.2.0  # 路由管理
  flutter_bloc: ^8.1.6 # 状态管理

  ## fx 架构
  fx_platform_adapter: ^0.0.2+1 # 平台适配器
  fx_go_router_ext: 0.0.3 # 路由
  fx_dao: 0.0.1+2 # 数据库
  fx_boot_starter: 0.1.1 # app 启动器

  # 数据与持久化
  dio: ^5.4.3+1 # 网络请求
  shared_preferences: ^2.2.2 # xml 固化
  jwt_decoder: ^2.0.1 # jwt 解析
  path_provider: ^2.1.3  # 路径

  # 平台功能
  connectivity_plus: ^6.0.3 # 网络状态
  url_launcher: ^6.1.14 # url
  archive: ^3.6.1 # 解压
  file_picker: ^8.0.5 # 文件选择器
  share_plus: ^10.0.1 # 文字分享

  # 视图展示
  tolyui: 0.0.2+19   # tolyui
  refresh: ^1.0.1 # 下拉刷新
  dash_painter: ^1.0.2 # 虚线
  flutter_star: ^1.0.2 # 星星组件
  flutter_spinkit: ^5.2.0 # loading
  toggle_rotate: ^1.0.1 # 点击旋转
  wrapper: ^1.0.2 # 气泡包裹
  webview_flutter: ^4.2.4 # webview
  flutter_markdown: ^0.7.2+1 # markdown
  
  # 逻辑处理
  image: ^4.0.17 # 图像处理
  equatable: ^2.0.5 # 相等辅助

5. 目前使用 workspace 需要注意

官方好像还没有正式宣布 workspace 的支持,现在只是尝鲜体验。目前 AndroidStudio 的插件识别还不太行,无法自动导包和识别,需要手动处理。 不过这点随着功时间推荐,肯定会支持完善。

另外,对于 需要发布到 pub 的模块,需要保证它可以被 独立解析。也就是说,它脱离工作空间,依旧可以独立存在。毕竟其他人没有你的工作空间环境,所以向别人提供功能的包,在工作空间中需要保持独立性: 要做到:

不能依赖工作空间的依赖,或者本地模块。

最后 ,这个文档 记录了 workspace 的功能和讨论,感兴趣的可以去看看。那本文就到这里,感谢大家对 FlutterUnit 的关注和支持,我会继续维护它,丰富它 ~