今天要來談談大型的 Flutter 項目會遇到的問題,當一個公司或團隊的技術慢慢堆疊,隨著時間的推移,可能會開發出多款不同的 App,或者一個大型的 App 會被分解成多個模組或子項目。這時就必須要會面對以下的困難:
這些可能都會讓開發的速度降低,必須花更多時間處理瑣碎的事情,所以這時候 Monorepo 就出現了。
Monorepo,也稱為單一倉庫策略,是指在一個版本控制系統中,所有的程式碼和項目都存放在同一個 repository 中。這意味著不同的項目、函式庫、工具和服務都共用一個版本控制系統的存儲庫。
舉個簡單的例子,假設一家公司有五個不同的專案,傳統的方式是為每個專案創建一個獨立的倉庫。但在 Monorepo 策略中,這五個專案都會存放在同一個倉庫中。
Monorepo 的優勢
在 Flutter 中,如果我們想要開始引入 Monorepo ,已經有很多大型專案開始使用這個套件:Melos,下面我們就來介紹一下 Melos 吧!
採用 Melos 的專案
以下是翻譯自官網的介紹:
將大型 Code base 分割成獨立的 pacakge 對於程式碼公用是非常好的方法。然而,在多個 repo 之間進行更改是混亂的,且難以追踪,而且跨存儲庫的測試變得複雜。Melos 通過允許多個 package 在一個 repo 內共同工作,同時彼此完全獨立,來幫助解決這些問題。
簡單來說,如果我們想要開始使用 Monorepo 整理我們的專案,必須自己去管理如何同步每個 package 之間互相依賴的問題,要整合測試流程,這些如果沒有 Melos 的幫助都要自己寫 Script 來完成。
那 Melos 到底如何使用呢?
全域安裝 Melos
dart pub global activate melos
先建立一個空的資料夾,並且放入 pubspec.yaml 的檔案
name: my_project_workspace
environment:
sdk: '>=2.18.0 <3.0.0'
然後加入 melos package
dart pub add melos --dev
接下來就可以放入我們的 Flutter 專案和 packages,目前先放在 apps 的資料夾底下:
├── apps
│ ├── README.md
│ ├── codelabs
│ ├── digital_art_toolkit
│ ├── flutter_day_10_build_runner
│ ├── flutter_day_10_shader
│ ├── flutter_day_11_shader
│ ├── flutter_day_14_hot_reload
│ ├── flutter_day_14_secure_storage
│ ├── flutter_day_15_performance
│ ├── flutter_day_21_tester
│ ├── flutter_day_23_storybook
│ ├── flutter_day_25_zone
│ ├── flutter_day_2_flavor
│ └── flutter_day_6_sentry
├── pubspec.lock
└── pubspec.yaml
接下來需要新增一個 melos.yaml 的檔案告訴 melos 我的資料夾格式,寫在 packages
下面
// melos.yaml
name: it_30_days
packages:
- apps/*
再來最重要的一步 bootstrap
:
$ melos bootstrap
# 或者 melos bs 也可以
bootstrap
會建立每個 package 的索引,如果你的 package 之間有互相依賴,他會用本地的 package path 取代原本對遠端的依賴,在你跑完 melos bootstrap
之後就會發現,你的每個 flutter 專案底下會多了一個 pubspec_overrides.yaml
的檔案,裡面的內容會把原本依賴於遠端的 package 改成依賴本地:
我有依賴到 digital_art_toolkit
這個 package 而它剛好是在這個 monorepo 裡面的話,就會生成 pubspec_overrides
的檔案,這樣做的最大好處就是能保證每個版本的改動沒有破壞到其他 app 的使用或依賴
# pubspec.yaml
name: flutter_day_23_storybook
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: '>=3.1.2 <4.0.0'
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
digital_art_toolkit: ^0.0.1
生成的 pubspec_overrides
# pubspec_overrides.yaml
# melos_managed_dependency_overrides: digital_art_toolkit
dependency_overrides:
digital_art_toolkit:
path: ../digital_art_toolkit
Melos Clean
除了 melos bootstrap
,melos 也有一個對應的 flutter clean
的功能,可以做到一樣的效果:
melos clean --flutter
甚至如果你有 clean 完要跟著做什麼行為,可以用 hook 來幫你解決,到 melos.yaml 檔案下設定:
# melos.yaml
...
command:
clean:
hooks:
post: rm packages/foo/lib/src/generated_file.g.dart
...
在 Monorepo 的使用情境下,很常會有自動化的部分需要靠自己跑 script 來解決,melos 也提供跑 shell script 的方法,使用的情境可以分成兩種
Run script:在 run script 的情境下,我們可以自己命名這個 script 然後設定他要 run 哪些 shell 指令即可,甚至可以自己寫環境變數:
# melos.yaml
...
scripts:
hello:
env:
GREETING: 'Hey'
goodbye: 'See ya'
run: echo "$GREETING"
...
# run script
$ melos hello
# print
'Hey'
Run exec:針對所有 package 都會跑一遍,所以如果你有 12 個專案,那他就會跑 12 次:
# melos.yaml
...
scripts:
hello-exec:
exec: echo 'Hello $(dirname $PWD)'
...
# run exec
$ melos hello-exec
# print
[digital_art_toolkit]: Hello /Users/dora
[flutter_day_10_build_runner]: Hello /Users/dora
[flutter_day_10_shader]: Hello /Users/dora
[flutter_day_14_hot_reload]: Hello /Users/dora
[flutter_day_14_secure_storage]: Hello /Users/dora
[flutter_day_15_performance]: Hello /Users/dora
[flutter_day_21_tester]: Hello /Users/dora
[flutter_day_23_storybook]: Hello /Users/dora
[flutter_day_25_zone]: Hello /Users/dora
[flutter_day_2_flavor]: Hello /Users/dora
[flutter_day_6_sentry]: Hello /Users/dora
這兩種指令可以分別對應整體跟每個 package 的情況,可以更自動化所有的流程!
如果你正在使用 Vscode 也可以考慮使用 melos 的 plugin,他有更快的指令還有一個畫出依賴圖的功能,有興趣可以裝來玩玩看,可以更視覺化的找出是否有不當的依賴哦:
melos 的功能介紹的差不多了,但是目前使用上有遇到兩個小小的問題,可能還需要未來的版本解決:
在大型項目的發展與管理上,Monorepo 策略無疑提供了一個革命性的解決方案。它不僅促使版本的統一管理,減少了程式碼的重複,也使得跨專案的協作更為簡單和順暢。Melos,作為 Flutter 中的一個重要工具,進一步簡化了 Monorepo 的實施過程,使得開發者能夠更專注於功能開發,而不是持續地處理版本和協作的問題。
但正如我們所提及的,Monorepo 和 Melos 雖然帶來了很多便利,但仍有其局限性和挑戰。對於存儲庫的大小,我們需要注意隨著時間的推移,如何維持其效能;對於權限管理,我們需要建立更為完善的策略以確保代碼的安全性。這些都是在實際使用過程中需要持續觀察和優化的部分。
總的來說,Monorepo 策略及 Melos 的引入,對於 Flutter 的大型項目開發,確實帶來了巨大的助益。但如同任何技術選擇,開發者在選用之前都需要根據項目的具體需求進行詳細的評估。只有真正理解其優勢與挑戰,才能充分發揮其效用,並使得項目發展更加順利。希望這篇探索之旅,能為各位在 Flutter 的大型項目開發上提供一些有益的參考和啟示。