不知不觉 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 中的远程仓库没什么区别。每个模块之间是独立的,它们可以各自依赖其他的包,比如现在 modules1
和 modules2
需要依赖计算模块 calculator
。那就需要 同时在两个 modules 中增加本地对 calculator
的依赖;
如果 toly_flutter 也需要依赖 calculator
,那就要写三份依赖关系。如果 calculator
是一个 pub 三方库,那么三者依赖的 calculator
版本可以写的不一样,这就会使得依赖变得复杂,增加依赖版本冲突的概率。
而且如果想要升级依赖,需要一个个模块进行修改,非常繁琐。
对于项目中的模块和依赖关系而言,如何统一进行组织,让它们更好地工作,这就是工作空间 workspace 的必要性。
3. workspace 重磅登场
工作空间可以大大简化模块依赖关系,总得来说有两点优势:
[1]
: 工作空间依赖的三方库,可以被其子模块访问。
[2]
: 工作空间中的子模块可以相互访问。
比如 toly_flutter 作为工作空间, modules1
和 modules2
作为其子模块,那么当 toly_flutter
依赖 flutter_calculator
和 tolyui
;那么两个 modules 就可以直接导入 flutter_calculator
和 tolyui
的内容进行使用。另外 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 的关注和支持,我会继续维护它,丰富它 ~