(九)Dart Libraries(库)、package(包)
库可以使用 Dart package 工具部署。参考 Pub Package 和 Asset Manager 来获取关于 pub(Dart 的包管理工具) 的更多信息。
使用 import
和 library
指令可以帮助你创建 模块化的可分享的代码。库不仅仅提供 API, 还是一个私有单元:以下划线 (_
) 开头的标识符只有在库 内部可见。每个 Dart app 都是一个库, 即使没有使用 library
命令也是一个库。
一、Using libraries(使用库)
使用 import
来指定一个库如何使用另外 一个库。
例如, Dart web 应用通常使用 dart:html 库,然后可以这样导入库:
import 'dart:html';
import 必须参数为库 的 URI。 对于内置的库,URI 使用特殊的 dart:
scheme。 对于其他的库,你可以使用文件系统路径或者 package:
scheme。package:
scheme 指定的库通过包管理器来提供, 例如 pub 工具。
import 'dart:io';
import 'package:mylib/mylib.dart';
import 'package:utils/utils.dart';
注意: URI 代表 uniform resource identifier。 URLs (uniform resource locators) 是一种常见的 URI。
二、Specifying a library prefix(指定库前缀)
如果你导入的两个库具有冲突的标识符, 则你可以使用库的前缀来区分。 例如,如果 library1 和 library2 都有一个名字为 Element 的类, 你可以这样使用:
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// ...
Element element1 = new Element(); // 使用lib1的Element .
lib2.Element element2 = new lib2.Element(); // 使用lib2的Element.
三、Importing only part of a library(导入库的一部分)
如果你只使用库的一部分功能,则可以选择需要导入的 内容。例如:
// 仅导入 foo.
import 'package:lib1/lib1.dart' show foo;
// 除了 foo,其他都导入.
import 'package:lib2/lib2.dart' hide foo;
四、Lazily loading a library(延迟载入库)
Deferred loading (也称之为 lazy loading) 可以让应用在需要的时候再 加载库。 下面是一些使用延迟加载库的场景:
- 减少 APP 的启动时间。
- 执行 A/B 测试,例如 尝试各种算法的 不同实现。
- 加载很少使用的功能,例如可选的屏幕和对话框。
要延迟加载一个库,需要先使用 deferred as
来 导入:
import 'package:deferred/hello.dart' deferred as hello;
当需要使用的时候,使用库标识符调用 loadLibrary() 函数来加载库:
greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
在前面的代码, 使用 await
关键字暂停代码执行一直到库加载完成。 关于 async
和 await
的更多信息请参考第十章。
在一个库上你可以多次调用 loadLibrary()
函数。 但是该库只是载入一次。
使用延迟加载库的时候,请注意一下问题:
1、延迟加载库的常量在导入的时候是不可用的。 只有当库加载完毕的时候,库中常量才可以使用。
2、在导入文件的时候无法使用延迟库中的类型。 如果你需要使用类型,则考虑把接口类型移动到另外一个库中, 让两个库都分别导入这个接口库。
3、Dart 隐含的把loadLibrary()
函数导入到使用deferred as *的命名空间*
中。loadLibrary()
方法返回一个Future
(详情见第十章)。
五、package(包)Implementing libraries(实现库)
在 Dart 生态中, 库通过包的方式来创建和分发。 Dart 有两种类型的包: 应用包 和 库包
5.1.应用包
5.2.库包
5.2.1.What makes a library package(库包做了啥)
下面显示了最简单的库包的 目录结构:
最简单的库包的 目录结构对于一个最简单的库需要如下内容:
-
pubspec file
库的pubspec.yaml
文件和应用包的一样 —并没有特别的标志表明包是 一个库。 -
lib directory
库包的代码位于 lib 目录中, 在其他包中可以访问这里面的代码。 在 lib 目录下可以创建任意的目录结构。 通常情况下都把实现代码放到 lib/src 目录中。 位于 lib/src 下面的代码被认为是私有的; 其他包不应该直接导入src/...
里面的代码。 要分享 lib/src 下的 API,你可以在 lib 目录下 创建一个文件,在这个文件中导入 lib/src 中的代码。
注意: 当没有指定
library
指令的时候,根据每个库 的路径和文件名会为每个库生成一个唯一的标签。 所以,我们 建议你不要在代码中使用library
指令, 除非你想 生成库的 API 文档(详见本文下面的Documenting a library)
在 lib 目录下创建一个主要的库文件( lib/<package-name>.dart),并且在该文件中 导出所有公开的 API。 这样使用你的库的用户就可以只导入一个 文件就可以使用所有的功能了。
lib 目录还可以包含其他重要的非代码文件。例如, 你的库是跨平台的,你创建 了不同平台使用 dart:io 的库。 有些包有几个分开的库需要分别导入, 每个库都使用不同的前缀。
下面是 shelf 库的目录结构。 shelf 库提供了一种简单的方式来创建 web 服务器, shelf 的目录结构是 Dart 库包目录结构 的常见形式:
shelf 的目录结构在 lib 目录下有个主要的库文件 shelf.dart
,该文件导出了 lib/src 目录下的几个文件:
export 'src/cascade.dart';
export 'src/handler.dart';
export 'src/handlers/logger.dart';
export 'src/hijack_exception.dart';
export 'src/middleware.dart';
export 'src/pipeline.dart';
export 'src/request.dart';
export 'src/response.dart';
export 'src/server.dart';
export 'src/server_handler.dart';
shelf 库还包含了一个迷你库: shelf_io。 这个适配器处理 dart:io 中的 HttpRequest 对象。
5.2.2.Organizing a library package
当库包非常小的时候,是非常容易维护、扩展和测试的, 这样的库被称之为 迷你库。 在大部分情况下,每个类都应该位于一个迷你库中, 除非当两个类紧紧耦合在一起的时候需要放到同一个库中。
注意: 你可能已经知道
part
指令了,该指令 可以把一个库分开到多个 Dart 文件中。我们推荐你 使用迷你库,而不要使用该指令。
5.2.3.Importing library files
可以使用 package:
指令并指定文件的 URI 来 导入库文件。
import 'package:utilities/utilities.dart';
当两个文件都位于 lib 目录中 或者目录 lib 之外的时候, 可以使用相对路径来导入库文件。
然后,当导入的文件和使用的文件不在 同一个库的时候,需要使用 package:
指令。 当你不知道如何选择的时候,就使用 package:
指令。
下面显示了在 lib 和 web 库中如何导入 lib/src/foo/a.dart
。
5.2.4.Providing additional files
良好的库应该很容易测试。 我们推荐你使用 test 库来编写测试代码, 把测试代码放到 test
目录 下。
如果你创建了一个可执行的工具,则可以把 这些工具放到 bin
目录,该目录是公开可访问的。 使用 pub global activate
来启用命令行运行工具的功能。 在 executables 部分 列出所有可执行文件, 可以让用户直接运行该命令,而不用通过 pub global run
来执行。
在库中包含使用你的库的示例代码也是非常有用的,把这些代码 放到 example
目录下。
你在开发的时候创建的其他不应该共享的工具则可以 放到 tool
目录。
当你把库提交到 pub.dartlang.org 的时候,需要包含 README 、 CHANGELOG 等文件, 在 发布包 页面对这些文件有介绍。 同时还请参考 Pub 包约定目录结构 来了解该如何布局包中的文件 目录。
六、Documenting a library(生成库的 API 文档)
使用 dartdoc 工具可以 为库生成 API 文档。 Dartdoc 从代码中解析 使用 ///
语法的 文档注释。
/// The event handler responsible for updating the badge in the UI.
void updateBadge() {
...
}
参考 shelf 文档 来查看生成的 API 文档格式。
注意: 要包含 库的文档需要使用
library
指令。 参考 issue 1082 了解详情。
七、Distributing a library
当把库项目提交到版本库中的时候,请注意有些 文件是不需要提交的。对于库 不要提交 .packages
、 pubspec.lock
文件, 也不要提交 packages
目录。详情请参考: 哪些文件不需要提交到版本库。
使用 pub publish 工具可以在 pub.dartlang.org 上 分享你的库。
发布一个库 描述了一个库需要包含哪些文件。
dartdocs.org 生成器 提供了一些好用的服务供发布到 pub.dartlang.org 的开发者使用。 这些服务追踪库的版本发布,当有新版本发布的时候会自动 生成新的 API 文档,文档在 dartdocs.org 可以查看。 在发布你的库之前,请先运行 dartdoc 看看生成 的文档是否满足你的要求。 如果你的库的文档在 dartdocs.org 中查找不到,请 查看 dartdocs.org/failed 来了解原因。
为了避免版本发布引起的问题, 当引用 dartdocs.org 地址的时候, 可以指定 “latest” 版本来替代具体的版本号。 例如: https://www.dartdocs.org/documentation/shelf/latest/.