目录

创建包

Dart 生态系统使用 包 来共享软件,例如库和工具。此页面介绍如何创建一个标准的共享 包 。

创建新的包

#

要创建包的初始目录和结构,请使用 dart create 命令和 package 模板:

$ dart create -t package <PACKAGE_NAME>

包的构成

#

下图显示了包的最简单布局:

根目录包含 pubspec.yaml 和 lib/file.dart

库的最低要求是:

pubspec 文件
库的 pubspec.yaml 文件与 应用程序包 的相同——没有特殊的标识来指示该包是库。
lib 目录
正如您可能预期的那样,库代码位于 lib 目录下,并且对其他包是公开的。您可以根据需要在 lib 下创建任何层次结构。按照惯例,实现代码放在 lib/src 下。lib/src 下的代码被认为是私有的;其他包永远不需要导入 src/... 。要使 lib/src 下的 API 公开,您可以从直接位于 lib 下的文件导出 lib/src 文件。

包的组织

#

当您创建小的、独立的库(称为 小型库 )时,包最易于维护、扩展和测试。在大多数情况下,每个类都应该在其自己的小型库中,除非您遇到两个类紧密耦合的情况。

直接在 lib 下创建一个“主”库文件, lib/<package-name>.dart ,它导出所有公共 API。这允许用户通过导入单个文件来获得库的所有功能。

lib 目录还可以包含其他可导入的非 src 库。例如,您的主库可能跨平台工作,但您创建了依赖于 dart:io 或 dart:js_interop 的单独库。有些包有单独的库,当主库不存在时,这些库需要使用前缀导入。

让我们看看一个真实世界包的组织:shelf。 shelf 包提供了一种使用 Dart 创建 Web 服务器的简单方法,其布局是 Dart 包常用的结构:

shelf 根目录包含 example、lib、test 和 tool 子目录

直接在 lib 下,主库文件 shelf.dart 从 lib/src 中的多个文件导出 API。为了避免暴露超出预期的 API——并为开发人员提供整个包的公共 API 概述—— shelf.dart 使用 show 精确指定要导出的符号:

lib/shelf.dart
dart
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 包还包含一个小型库:shelf_io。此适配器处理来自 dart:io 的 HttpRequest 对象。

导入库文件

#

从另一个包导入库文件时,使用 package: 指令指定该文件的 URI。

dart
import 'package:utilities/utilities.dart';

从您自己的包导入库文件时,如果两个文件都在 lib 内部,或者两个文件都在 lib 外部,则使用相对路径。当导入的文件在 lib 中而导入者在外部时,使用 package: 。

下图显示了如何从 lib 和 web 导入 lib/foo/a.dart 。

lib/bar/b.dart 使用相对导入;web/main.dart 使用包导入

有条件地导入和导出库文件

#

如果您的库支持多个平台,那么您可能需要有条件地导入或导出库文件。一个常见的用例是支持 Web 和原生平台的库。

要进行有条件的导入或导出,您需要检查 dart:* 库的存在。这是一个有条件导出代码的示例,该代码检查 dart:io 和 dart:js_interop 的存在:

lib/hw_mp.dart
dart
export 'src/hw_none.dart' // 存根实现
    if (dart.library.io) 'src/hw_io.dart' // dart:io 实现
    if (dart.library.js_interop) 'src/hw_web.dart'; // package:web 实现

这段代码的作用如下:

  • 在可以使用 dart:io 的应用程序中(例如,命令行应用程序),导出 src/hw_io.dart 。
  • 在可以使用 dart:js_interop 的应用程序中(Web 应用程序),导出 src/hw_web.dart 。
  • 否则,导出 src/hw_none.dart 。

要根据条件导入文件,请使用与上述相同的代码,但将 export 更改为 import 。

所有有条件导出的库都必须实现相同的 API。例如,这是 dart:io 实现:

lib/src/hw_io.dart
dart
import 'dart:io';

void alarm([String? text]) {
  stderr.writeln(text ?? message);
}

String get message => 'Hello World from the VM!';

这是默认实现,它使用抛出 UnsupportedError 的存根:

lib/src/hw_none.dart
dart
void alarm([String? text]) => throw UnsupportedError('hw_none alarm');

String get message => throw UnsupportedError('hw_none message');

在任何平台上,您都可以导入具有条件导出代码的库:

dart
import 'package:hw_mp/hw_mp.dart';

void main() {
  print(message);
}

提供其他文件

#

精心设计的包易于测试。我们建议您使用 test 包编写测试,并将测试代码放在包顶部的 test 目录中。

如果您创建任何旨在供公众使用的命令行工具,请将它们放在公共的 bin 目录中。使用 dart pub global activate 启用从命令行运行工具。在pubspec的 executables 部分 中列出该工具,允许用户直接运行它,而无需调用 dart pub global run 。

如果您包含如何使用库的示例会很有帮助。这将进入包顶部的 example 目录。

在开发过程中创建的任何不供公众使用的工具或可执行文件都放在 tool 目录中。

如果您将库发布到 pub.dev 站点,则需要其他文件,例如 README.md 和 CHANGELOG.md ,这些文件在 发布包 中进行了描述。有关如何组织包目录的更多信息,请参阅 pub 包布局约定 。

文档化库

#

您可以使用 dart doc 工具为库生成 API 文档。 dart doc 解析源代码以查找 文档注释 ,这些注释使用 /// 语法:

dart
/// 负责更新 UI 中徽章的事件处理程序。
void updateBadge() {
  ...
}

有关生成的文档示例,请参阅 shelf 文档。

要在生成的文档中包含任何 库级 文档,请添加 library 指令并将注释直接附加在其上方。有关文档化库的如何以及为何,请参阅 Effective Dart:文档 。

分发开源库

#

如果您的库是开源的,我们建议您在 pub.dev 网站 上共享它。要发布或更新库,请使用 pub publish ,它将上传您的包并创建或更新其页面。例如,请参阅 shelf 包 的页面。有关如何准备包以进行发布的详细信息,请参阅 发布包 。

pub.dev 网站不仅托管您的包,还生成和托管您包的 API 参考文档。包的“关于”框中包含指向最新生成的文档的链接;例如,请参阅 shelf 包的 API 文档。 包页面的“版本”选项卡中包含指向先前版本文档的链接。

要确保您的包的 API 文档在 pub.dev 网站上看起来不错,请按照以下步骤操作:

  • 在发布包之前,运行 dart doc 工具以确保您的文档成功生成并按预期显示。
  • 发布包后,检查“版本”选项卡以确保文档已成功生成。
  • 如果文档根本没有生成,请单击“版本”选项卡中的“失败”以查看 dart doc 输出。

资源

#

使用以下资源来了解有关包的更多信息: