跳到主內容

包佈局約定

在構建 pub 包時,我們鼓勵你遵循本頁描述的約定。它們描述瞭如何在包內組織檔案和目錄,以及如何命名事物。

以下是一個完整包(名為 enchilada),它使用了本指南的所有方面,看起來可能像這樣:

enchilada/
  .dart_tool/ *
  pubspec.yaml
  pubspec_overrides.yaml **
  pubspec.lock ***
  LICENSE
  README.md
  CHANGELOG.md
  benchmark/
    make_lunch.dart
  bin/
    enchilada
  doc/
    api/ ****
    getting_started.md
  example/
    main.dart
  hook/
    build.dart
  integration_test/
    app_test.dart
  lib/
    enchilada.dart
    tortilla.dart
    guacamole.css
    src/
      beans.dart
      queso.dart
  test/
    enchilada_test.dart
    tortilla_test.dart
  tool/
    generate_docs.dart
  web/
    index.html
    main.dart
    style.css

* 在執行 dart pub get 後會生成 .dart_tool/ 目錄。不要將其提交到版本控制。要了解更多資訊,請參閱工具的專案特定快取

** 如果存在 pubspec_overrides.yaml 檔案,它會覆蓋 pubspec.yaml 的某些方面。通常你不會想把它提交到版本控制。

*** 在執行 dart pub get 後會生成 pubspec.lock 檔案。除非你的包是應用包,否則不要將其提交到版本控制。

**** 在本地執行 dart doc 後會生成 doc/api 目錄。不要將 api 目錄提交到版本控制。

pubspec 檔案

#
enchilada/
  pubspec.yaml
  pubspec.lock

每個包在其根目錄中都有一個pubspec檔案,名為 pubspec.yaml。正是這個檔案使其成為一個包

對包執行 dart pub getdart pub upgradedart pub downgrade 會生成一個名為 pubspec.lock鎖定檔案。如果你的包是應用包,則應將此鎖定檔案提交到版本控制。否則,不要這樣做。

有關更多資訊,請參閱pubspec 頁面

LICENSE

#
enchilada/
  LICENSE

如果你要釋出包,請包含一個名為 LICENSE 的許可證檔案。我們推薦使用 OSI 批准的許可證,例如BSD-3-Clause,以便他人可以重複使用你的作品。

README.md

#
enchilada/
  README.md

開源專案中非常常見的一個檔案是描述專案的 README 檔案。這在 pub 中尤為重要。當你上傳到 pub.dev 站點時,你的 README.md 檔案將以 Markdown 格式渲染並顯示在你的包頁面上。這是向人們介紹你的程式碼的絕佳位置。

有關如何編寫出色的 README 的指南,請參閱編寫包頁面

CHANGELOG.md

#
enchilada/
  CHANGELOG.md

包含一個 CHANGELOG.md 檔案,其中包含包每個版本的章節,並附有幫助包使用者升級的說明。你的包使用者經常檢視更新日誌,以發現錯誤修復和新功能,或確定升級到包最新版本所需的工作量。

為了支援解析 CHANGELOG.md 的工具,請使用以下格式:

  • 每個版本都有自己的章節,並帶有標題。
  • 版本標題要麼全是 1 級標題,要麼全是 2 級標題。
  • 版本標題文字包含包版本號,可以選擇以“v”開頭。

當你將包上傳到 pub.dev 站點時,你的包的 CHANGELOG.md 檔案(如果存在)將顯示在更新日誌選項卡中,並以 Markdown 格式渲染。

這是一個 CHANGELOG.md 檔案的示例。如示例所示,你可以新增子章節。

markdown
# 1.0.1

* Fixed missing exclamation mark in `sayHi()` method.

# 1.0.0

* **Breaking change:** Removed deprecated `sayHello()` method.
* Initial stable release.

## Upgrading from 0.1.x

Change all calls to `sayHello()` to instead be to `sayHi()`.

# 0.1.1

* Deprecated the `sayHello()` method; use `sayHi()` instead.

# 0.1.0

* Initial development release.

公共目錄

#

包中有兩個目錄對其他包是公共的:libbin。你將公共庫放在 lib 中,將公共工具放在 bin 中。

公共庫

#

以下目錄結構顯示了 enchilada 包的 lib 部分:

enchilada/
  lib/
    enchilada.dart
    tortilla.dart

許多定義了其他包可以匯入和使用的 Dart 庫。這些公共 Dart 庫檔案放在一個名為 lib 的目錄中。

大多數包定義了一個使用者可以匯入的單個庫。在這種情況下,其名稱通常應與包的名稱相同,例如這裡的示例中的 enchilada.dart。但你也可以定義其他庫,使用對你的包有意義的任何名稱。

當你這樣做時,使用者可以使用包的名稱和庫檔案來匯入這些庫,如下所示:

dart
import 'package:enchilada/enchilada.dart';
import 'package:enchilada/tortilla.dart';

如果你想組織公共庫,你也可以在 lib 內部建立子目錄。如果你這樣做,使用者匯入時將指定該路徑。假設你有以下檔案層級:

enchilada/
  lib/
    some/
      path/
        olives.dart

使用者匯入 olives.dart 如下所示:

dart
import 'package:enchilada/some/path/olives.dart';

注意,lib 中只能放置。包含 main() 函式的 Dart 指令碼——入口檔案——不能放在 lib 中。如果你將 Dart 指令碼放在 lib 中,你會發現它包含的任何 package: 匯入都無法解析。相反,你的入口檔案應該放在適當的入口檔案目錄中。

有關包的更多資訊,請參閱建立包

公共工具

#

放在 bin 目錄中的 Dart 指令碼是公共的。如果你在包的目錄內,可以使用 dart run 執行該包依賴的任何其他包的 bin 目錄中的指令碼。從任何目錄,你可以執行使用 dart pub global activate 啟用的包中的指令碼。

如果你希望你的包被其他包依賴,並且希望你的指令碼只對你的包私有,請將它們放在頂層的 tool 目錄中。如果你不打算讓你的包被依賴,可以將指令碼留在 bin 中。

公共資源

#
enchilada/
  lib/
    guacamole.css

雖然大多數包的存在是為了讓你重用 Dart 程式碼,但你也可以重用其他型別的內容。例如,Bootstrap 的一個包可能包含許多 CSS 檔案供包的消費者使用。

這些檔案放在頂層的 lib 目錄中。你可以將任何型別的檔案放在其中,並根據需要使用子目錄進行組織。

實現檔案

#
enchilada/
  lib/
    src/
      beans.dart
      queso.dart

lib 內部的庫是公共可見的:其他包可以自由匯入它們。但是包的大部分程式碼是內部實現庫,它們應該只由包本身匯入和使用。這些檔案放在 lib 的一個子目錄中,名為 src。你可以在其中建立子目錄來幫助組織內容。

你可以在同一個包中的其他 Dart 程式碼(例如 lib 中的其他庫、bin 中的指令碼和測試)中自由匯入位於 lib/src 的庫,但絕不應該從另一個包的 lib/src 目錄匯入。這些檔案不是包公共 API 的一部分,它們可能會以破壞你的程式碼的方式發生變化。

如何從你自己的包內匯入庫取決於庫的位置:

例如:

lib/beans.dart
dart
// When importing from within lib:
import 'src/beans.dart';
test/beans_test.dart
dart
// When importing from outside lib:
import 'package:enchilada/src/beans.dart';

你在這裡使用的名稱(在本例中是 enchilada)是你在包的pubspec中為包指定的名稱。

Web 檔案

#
enchilada/
  web/
    index.html
    main.dart
    style.css

對於 web 包,將入口檔案程式碼(包含 main() 的 Dart 指令碼和支援檔案,如 CSS 或 HTML)放在 web 下。你可以根據需要將 web 目錄組織成子目錄。

庫程式碼放在 lib 下。如果該庫未被 web 下的程式碼或另一個包直接匯入,則將其放在 lib/src 下。將基於 Web 的示例放在 example 下。有關存放資源(如影像)的技巧,請參閱公共資源

命令列應用

#
enchilada/
  bin/
    enchilada

一些包定義了可以直接從命令列執行的程式。這些可以是 shell 指令碼或任何其他指令碼語言,包括 Dart。

如果你的包定義了這樣的程式碼,請將其放在名為 bin 的目錄中。如果使用 dart pub global 進行設定,你可以在命令列的任何位置執行該指令碼。

測試與基準測試

#
enchilada/
  test/
    enchilada_test.dart
    tortilla_test.dart

每個包都應該有測試。對於 pub,約定是大多數測試檔案放在 test 目錄中(或者如果你喜歡,也可以放在其內部的某個目錄中),並且檔名以 _test 結尾。

通常,這些測試使用 test 包。

enchilada/
  integration_test/
    app_test.dart

Flutter 應用包也可能有特殊的整合測試,它們使用 integration_test 包。這些測試位於它們自己的 integration_test 目錄中。

其他包可以選擇遵循類似的模式,將其較慢的整合測試與單元測試分開,但請注意,預設情況下 dart test 不會執行這些測試。你必須使用 dart test integration_test 顯式執行它們。

enchilada/
  benchmark/
    make_lunch.dart

具有效能關鍵程式碼的包也可能包含基準測試。這些測試並非為了驗證 API 的正確性,而是為了測試速度(或記憶體使用,或可能其他經驗指標)。

文件

#
enchilada/
  doc/
    api/
    getting_started.md

如果你有了程式碼和測試,下一步可能需要的是良好的文件。這些文件放在一個名為 doc 的目錄中。

當你執行 dart doc 工具時,它預設會將 API 文件放在 doc/api 下。由於 API 文件是從原始碼生成的,因此不應將其提交到版本控制。

除了生成的 api 之外,我們對你編寫的文件的格式或組織沒有特定指導。使用你偏好的任何標記格式即可。

示例

#
enchilada/
  example/
    main.dart

程式碼、測試、文件都有了,你的使用者可能還想要什麼?當然是使用你的包的獨立示例程式!這些示例程式放在 example 目錄中。如果示例比較複雜且使用了多個檔案,請考慮為每個示例建立一個目錄。否則,你可以直接將每個示例檔案放在 example 中。

在你的示例中,使用 package: 匯入你自己的包中的檔案。這樣可以確保你的包中的示例程式碼看起來與包外部的程式碼完全一樣。

如果你可能會發布包,請考慮建立一個具有以下名稱之一的示例檔案:

  • example/example[.md]
  • example[/lib]/main.dart
  • example[/lib]/package_name.dart
  • example[/lib]/package_name_example.dart
  • example[/lib]/example.dart
  • example/README[.md]

當你釋出包含上述一個或多個檔案的包時,pub.dev 站點會建立一個示例選項卡,以顯示它找到的第一個檔案(按照上面列表中的順序搜尋)。例如,如果你的包在其 example 目錄下有許多檔案,包括一個名為 README.md 的檔案,那麼你的包的示例選項卡將顯示 example/README.md 的內容(解析為 Markdown 格式)。

內部工具與指令碼

#
enchilada/
  tool/
    generate_docs.dart

成熟的包通常有一些小的輔助指令碼和程式,人們在開發包本身時會執行它們。想想測試執行器、文件生成器或其他一些自動化工具。

bin 中的指令碼不同,這些指令碼不是供包的外部使用者使用的。如果你有這些指令碼,請將它們放在一個名為 tool 的目錄中。

鉤子 (Hooks)

#
enchilada/
  hook/
    build.dart

包可以定義由 Dart 和 Flutter SDK 呼叫的鉤子。這些鉤子有一個預定義的 CLI 介面,如果存在,將被 SDK 工具呼叫。

由於這些鉤子在執行和構建時被 dartflutter 工具呼叫,因此這些鉤子的依賴項必須是正常的依賴項(dependencies),而不是開發依賴項(dev_dependencies)。

工具的專案特定快取

#

.dart_tool/ 目錄在你執行 dart pub get 時建立,並可能隨時被刪除。各種工具使用此目錄來快取特定於你的專案和/或本地機器的檔案。.dart_tool/ 目錄絕不應提交到版本控制,也不應在機器之間複製。

刪除 .dart_tool/ 目錄通常也是安全的,儘管某些工具可能需要重新計算快取的資訊。

示例: dart pub get 工具會將依賴項下載並解壓到全域性 $PUB_CACHE 目錄,然後寫入一個 .dart_tool/package_config.json 檔案,該檔案將包名對映到全域性 $PUB_CACHE 目錄中的對應目錄。其他工具,例如分析器和編譯器,在需要解析諸如 import 'package:foo/foo.dart' 之類的語句時,會使用 .dart_tool/package_config.json 檔案。

在開發需要專案特定快取的工具時,你可以考慮使用 .dart_tool/ 目錄,因為大多數使用者已經透過 .gitignore 忽略了它。在使用者的 .dart_tool/ 目錄中快取工具檔案時,你應該使用一個唯一的子目錄。為了避免衝突,形式為 .dart_tool/<tool_package_name>/ 的子目錄保留給名為 <tool_package_name> 的包使用。如果你的工具不是透過 pub.dev 站點分發的,你可能考慮釋出一個佔位符包來保留這個唯一的名稱。

示例: package:build 提供了一個用於編寫程式碼生成步驟的框架。在執行這些構建步驟時,檔案會快取在 .dart_tool/build/ 中。這有助於加快未來重新執行構建步驟的速度。