建立 package
建立一個新的 package
Package 的組成
組織 Package 的程式碼結構
匯入庫檔案
條件匯入或條件匯出 Library 檔案
提供額外檔案
為 Library 製作文件
分發開源 Library
資源
在 Dart 生態系統中使用 packages 實現共享軟體,比如一些函式庫和工具。本章將透過最常見的 Package 來介紹如何建立一個 Package。
建立一個新的 package
若要為 package 建立一個初始化的目錄和結構,使用 dart create
命令,並加入 package
作為命令引數來建立:
$ dart create -t package <PACKAGE_NAME>
Package 的組成
下圖展示了最簡單的 Package 的結構:
Package 的最基本要求包括:
pubspec 檔案
Package 的 pubspec.yaml
檔案與應用程式的
pubspec.yaml
檔案相同— pubspec.yaml
檔案中並沒有特別的指出這個 Package 是一個函式庫。
lib 目錄
如你所料,庫的程式碼位於 lib 目錄下,且對於其他 Package 是公開的。你可以根據需要在 lib 下任意建立組織檔案結構。按照慣例,實現程式碼會放在 lib/src 目錄下。
lib/src 目錄下的程式碼被認為是私有的。其他 Package 應該永遠不需要匯入 src/...
目錄下程式碼。透過匯出 lib/src 目錄的檔案到一個 lib 目錄的檔案,實現對 lib/src 目錄中 API 的公開。
組織 Package 的程式碼結構
在建立一個小的,獨立的 Package 時(稱之為 Mini Library),它非常容易維護,擴充和測試。大多數情況下,除非存在兩個類緊密耦合的情況,否則每個類都應該將自己視為一個 Mini Library 。
直接在 lib 目錄下建立“主” Library 檔案,lib/<package-name>.dart,該檔案匯出所有的公開的 API 。這樣就可以允許使用者匯入單個檔案就能夠獲得 Library 的所有功能。
lib 目錄還可能包含其他可匯入的非 src 程式碼。例如,主 Library 可能是跨平臺的,但建立的獨立 Library 依賴於 dart:io 或 dart:html 。 Some packages have separate libraries that are meant to be imported with a prefix, when the main library is not.(無法確切理解含義,暫未翻譯)
這裡讓我們來看下一個真實 Library Package 的組織結構:shelf 。 shelf Package 提供了一種使用 Dart 建立 Web 伺服器的簡便方法,它是一種 Dart Package 的常用結構:
主 Library 檔案 shelf.dart
在 lib 目錄下,透過 shelf.dart
檔案匯出 lib/src 目錄下的若干檔案。為了不匯出過多的 API,並且為開發者提供公開的 API 的概覽,
shelf.dart
使用了 show
來指定哪些內容需要匯出:
export 'src/cascade.dart' show Cascade;
export 'src/handler.dart' show Handler;
export 'src/hijack_exception.dart' show HijackException;
export 'src/middleware.dart' show Middleware, createMiddleware;
export 'src/middleware/add_chunked_encoding.dart' show addChunkedEncoding;
export 'src/middleware/logger.dart' show logRequests;
export 'src/middleware_extensions.dart' show MiddlewareExtensions;
export 'src/pipeline.dart' show Pipeline;
export 'src/request.dart' show Request;
export 'src/response.dart' show Response;
export 'src/server.dart' show Server;
export 'src/server_handler.dart' show ServerHandler;
在 shelf Package 中同樣包含了 Mini Library:shelf_io 。介面卡用來處理來自 dart:io
的 HttpRequest 物件。
匯入庫檔案
在從其他 package 匯入庫檔案時,使用 package:
命令來指定檔案的 URI 。
import 'package:utilities/utilities.dart';
在兩個檔案都在 lib 目錄中,或兩個檔案都在 lib 目錄外,我們都可以使用相對路徑的方式匯入 Library 。但是,如果兩個檔案不都在 lib 目錄中,需要對 lib 內或者 lib 外進行查詢,那麼此時必須要使用 package:
匯入。如果對當前使用存在疑惑,那麼直接 package:
; package:
滿足所有情況。
下面圖片展示分別從 lib 和 web 目錄中匯入 lib/foo/a.dart
。
條件匯入或條件匯出 Library 檔案
如果你的 library 支援多平臺,那麼你應該會用到條件匯入或條件匯出 library 檔案。常見的使用案例是,一個函式庫同時支援 Web 和 Native 平台。
為了使用條件匯入或條件匯出,你需要檢查是否存在 dart:*
庫。下面是一個條件匯出程式碼的範例,它將檢查是否存在 dart:io
and dart:html
庫:
export 'src/hw_none.dart' // Stub implementation
if (dart.library.io) 'src/hw_io.dart' // dart:io implementation
if (dart.library.html) 'src/hw_html.dart'; // dart:html implementation
該程式碼的作用如下:
-
在一個可以使用
dart:io
的 app 中(例如一個命令列應用),匯出src/hw_io.dart
。 -
在一個 web 應用中可以使用
dart:html
匯出src/hw_html.dart
。 -
若是其他情況,則匯出
src/hw_none.dart
。
要條件匯入一個檔案可以使用和上面一樣的方式,僅需將 export
改為 import
即可。
所有條件匯出的函式庫必須實現相同的 API。下面是 dart:io
實現的一個例子:
import 'dart:io';
void alarm([String? text]) {
stderr.writeln(text ?? message);
}
String get message => 'Hello World from the VM!';
這是一個預設實現,它會導致丟擲 UnsupportedErrors
:
void alarm([String? text]) => throw UnsupportedError('hw_none alarm');
String get message => throw UnsupportedError('hw_none message');
在任何平臺上,你都可以匯入具有條件匯出程式碼的函式庫:
import 'package:hw_mp/hw_mp.dart';
void main() {
print(message);
}
提供額外檔案
一個設計良好的 Package 很容易被測試。我們建議使用 test Package
編寫測試使用案例,並將測試程式碼放到 Package 根目錄的 test
目錄中。
如果要建立一個公用的命令列工具,應該將這些工具放到公共目錄 bin
中。使用 dart pub global activate
命令列來執行工具。在 pubspec 的 executables
部分
列出的工具允許使用者直接執行它而無需呼叫
dart pub global run
。
在 Library 中包含一個 example 程式示範如何使用 Library 是非常有用的。
example 程式在 Package 根目錄的 example
目錄中。
在開發過程中任何非公開的工具或可執行程式,應該放到 tool
資料夾。
如果要將 Library 釋出到 Pub 網站還要求一些其他的檔案來描述 釋出的 Package ,例如:README.md
和 CHANGELOG.md
檔案。更多關於如何組織 Package 目錄的內容,參見 Pub Package 佈局約定。
為 Library 製作文件
使用 [dartdoc][] 可以為 Library 產生 API 文件。
dartdoc 解析原始檔去查詢使用 ///
語法標註的
文件註釋:
/// The event handler responsible for updating the badge in the UI.
void updateBadge() {
...
}
文件產生範例,參見 shelf 文件。
若要自動產生任何庫級別的文件,請新增一個 library
指令並直接在其上方附加註釋。更多詳情,請參閱文件
Effective Dart: Documentation。
分發開源 Library
如果 Library 是開源的,我們建議將他共享到 Pub 網站。使用 pub publish 來發布或者更新 Library,該命令將會上傳 Package 並建立或更新其頁面。範例參見 shelf Package 頁面。有關如何準備釋出 Package 的詳細內容,參見 釋出 Package。
Pub.dev 網站不僅僅是 Dart Packages 的釋出網站, Pub 網站不僅用於託管 Package ,還能夠產生託管 Package 的 API 參考文件。最新產生的文件的連結位於 Package 的 About 選項卡中; 範例參見 shelf Package 的 API 文件。連結到以前版本的文件,位於 Package 頁面的 Versions 選項卡中。
為了確保 Package 的 API 文件在 Pub 網站上看起來更美觀,請遵循以下步驟:
-
在釋出 Package 前,請透過執行
dart doc
工具確保文件能夠產生成功且符合預期。 -
在釋出 Package 後,請檢查 Versions 選項卡,確保文件產生成功。
-
如果文件沒有產生,點選 Versions 選項卡中的 failed 檢視 dartdoc 的輸出。
資源
透過運用以下資源來了解學習更多關於 Library Package 的內容:
-
在 庫及可見性 中涵蓋了庫檔案使用的內容。
-
Package 文件非常有用,尤其是 Package 結構約定.
-
什麼不應該被提交包含了關於什麼檔案不應該被提交到原始碼儲存庫的介紹。
-
dart-lang 組織下的最新 Package 常常是最佳實踐的提現。可以參考學些以下這些例項: dart_style, path, shelf, source_gen 以及 test 。