跳過主內容

Pub 工作區(monorepo 支援)

在專案開發中,你可能會在同一個版本控制倉庫(即monorepo)中開發多個 Dart 包。

例如,你可能有一個如下的目錄結構:

/
  packages/
    shared/
      pubspec.yaml
      pubspec.lock
      .dart_tool/package_config.json
    client_package/
      pubspec.yaml
      pubspec.lock
      .dart_tool/package_config.json
    server_package/
      pubspec.yaml
      pubspec.lock
      .dart_tool/package_config.json

這種設定存在一些缺點:

  • 你需要為每個包分別執行一次 dart pub get
  • 你可能會為每個包得到不同版本的依賴項,從而在包之間切換上下文時造成混淆。
  • 如果你在 IDE 中開啟根資料夾,Dart 分析器將為每個包建立單獨的分析上下文,這會增加記憶體使用量。

Pub 允許你將倉庫組織為一個工作區,為所有包使用單一的共享解析。為大型倉庫使用工作區可以減少分析所需的記憶體量,從而提高效能。

建立工作區

  • 在倉庫根目錄下新增一個 pubspec.yaml 檔案,其中包含一個 workspace 條目,列舉倉庫中包的路徑(即工作區包)

    yaml
    name: _
    publish_to: none
    environment:
      sdk: ^3.6.0
    workspace:
      - packages/helper
      - packages/client_package
      - packages/server_package
  • 對於每個現有的 pubspec.yaml 檔案,請確保其 SDK 約束至少為 ^3.6.0,並新增一個 resolution 條目

    yaml
    environment:
      sdk: ^3.6.0
    resolution: workspace
  • 在倉庫中的任意位置執行 dart pub get。這將執行以下操作:

    • 在根 pubspec.yaml 旁邊建立一個單獨的 pubspec.lock 檔案,其中包含所有工作區包的 dependenciesdev_dependencies 的解析結果。
    • 建立一個單獨的共享 .dart_tool/package_config.json 檔案,將包名稱對映到檔案位置。
    • 刪除工作區包旁邊所有其他現有的 pubspec.lock.dart_tool/package_config.json 檔案。

現在檔案結構如下所示:

/
  packages/
    shared/
      pubspec.yaml
    client_package/
      pubspec.yaml
    server_package/
      pubspec.yaml
  pubspec.yaml
  pubspec.lock
  .dart_tool/package_config.json

散落檔案

#

當你將現有 monorepo 遷移到使用 Pub 工作區時,每個 pubspec 旁邊都會有現有的“散落” pubspec.lock.dart_tool/package_config.json 檔案。這些檔案會遮蔽放置在根目錄旁邊的 pubspec.lock.dart_tool/package_config.json 檔案。

因此,pub get 將刪除位於根目錄與任何工作區包之間(包括工作區包目錄本身)的所有 pubspec.lock.dart_tool/package_config.json 檔案。

/
  pubspec.yaml                       # Root
  packages/
    pubspec.lock                     # Deleted by `pub get`
    .dart_tool/package_config.json   # Deleted by `pub get`
    foo/
      pubspec.yaml                   # Workspace member
      pubspec.lock                   # Deleted by `pub get`
      .dart_tool/package_config.json # Deleted by `pub get`

如果工作區根目錄與工作區包之間的任何目錄包含一個不屬於該工作區的“散落” pubspec.yaml 檔案,pub get 將報告錯誤並解析失敗。這是因為解析這樣的 pubspec.yaml 檔案會建立一個 .dart_tool/package_config.json 檔案,從而遮蔽根目錄下的檔案。

例如:

/
  pubspec.yaml                      # Root `workspace: ['foo/']`
  packages/
    pubspec.yaml                    # Not workspace member => error
    foo/
      pubspec.yaml                  # Workspace member

工作區包之間的相互依賴

#

如果任何工作區包相互依賴,它們將自動解析為工作區中的包,無論其來源如何。

例如,packages/client_package/pubspec.yaml 可能依賴於 shared

yaml
dependencies:
  shared: ^2.3.0

在工作區內解析時,將使用 shared本地版本。

但是,shared 的本地版本仍然必須匹配約束(^2.3.0)。

但是,當包作為依賴項被使用且不屬於工作區時,將使用其原始來源(這裡隱含的是 hosted)。

因此,如果 client_package 釋出到 pub.dev 並且有人依賴它,他們將獲得 shared 的託管版本作為傳遞依賴項。

工作區中的依賴項覆蓋

#

工作區包中的所有 dependency_overrides 部分都將被遵守。你還可以將 pubspec_overrides.yaml 檔案放在任何工作區 pubspec.yaml 檔案的旁邊。

在一個工作區中,你只能覆蓋一個包一次。為了保持覆蓋的組織性,最好將 dependency_overrides 放在根 pubspec.yaml 中。

在特定工作區包中執行命令

#

一些 pub 命令,例如 dart pub adddart pub publish,會針對“當前”包操作。你可以更改目錄,或使用 -C 將 pub 指向某個目錄。

dart pub -C packages/client_package publish
# Same as
cd packages/client_package ; dart pub publish ; cd -

臨時在工作區外解析包

#

有時你可能希望單獨解析工作區中的包,例如為了驗證其依賴約束。

一種方法是建立一個 pubspec_overrides.yaml 檔案來重置 resolution 設定,如下所示:

yaml
# packages/client_package/pubspec_overrides.yaml
resolution:

現在在 packages/client_package 內部執行 dart pub get 將建立獨立的解析。

列出所有工作區包

#

你可以執行 dart pub workspace list 來列出工作區中的包。

dart pub workspace list
Package         Path                      
_               ./                        
client_package  packages/client_package/  
server_package  packages/server_package/  
shared          packages/shared/