包依赖
依赖是 pub 包管理器的核心概念之一。依赖项是您的包正常工作所需的另一个包。依赖项在您的 pubspec 中指定。您只列出直接依赖项:您的包直接使用的软件。Pub 会为您处理传递依赖项。
本页面详细介绍了如何指定依赖项。最后列出了包依赖项的最佳实践。
概览
#对于每个依赖项,您需要指定所依赖包的名称以及允许的该包的版本范围。您还可以指定源。源告诉 pub 如何定位包。
例如,您可以按以下格式指定依赖项
dependencies:
transmogrify: ^1.0.0
此 YAML 代码创建了对 transmogrify
包的依赖,使用默认包仓库 (pub.dev),并允许从 1.0.0
到 2.0.0
(但不包括 2.0.0
)的任何版本。要了解此语法,请查看版本约束。
要指定除 pub.dev 之外的源,请使用 sdk
、hosted
、git
或 path
。例如,以下 YAML 代码使用 path
来告诉 pub 从本地目录获取 transmogrify
dependencies:
transmogrify:
path: /Users/me/transmogrify
下一节将介绍每个依赖项源的格式。
依赖来源
#Pub 可以使用以下源来定位包
托管包
#托管包是可以从 pub.dev 网站(或支持相同 API 的其他 HTTP 服务器)下载的包。以下是声明对托管包依赖的示例:
dependencies:
transmogrify: ^1.4.0
此示例指定您的包依赖于名为 transmogrify
的托管包,并且支持从 1.4.0 到 2.0.0(但不包括 2.0.0 本身)的任何版本。
如果您想使用自己的包仓库,可以使用 hosted
来指定其 URL。以下 YAML 代码使用 hosted
源创建了对 transmogrify
包的依赖:
environment:
sdk: '^2.19.0'
dependencies:
transmogrify:
hosted: https://some-package-server.com
version: ^1.4.0
版本约束是可选的,但建议使用。如果未指定版本约束,则默认为 any
。
Git 包
#有时您走在技术前沿,需要使用尚未正式发布的包。也许您的包本身仍在开发中,并且正在同时使用其他正在开发的包。为了简化此过程,您可以直接依赖存储在 Git 仓库中的包。
dependencies:
kittens:
git: https://github.com/munificent/kittens.git
这里的 git
表示此包是使用 Git 找到的,其后的 URL 是可用于克隆此包的 Git URL。
即使包仓库是私有的,您也可以配置 git
以使用HTTPS 访问密钥或SSH 密钥对访问仓库。然后,您可以使用仓库对应的 URL 依赖该包:
dependencies:
kittens:
# SSH URL:
git: git@github.com:munificent/kittens.git
dart pub
命令会调用 git clone
作为子进程,因此您只需提供一个在执行 git clone <url>
时能够正常工作的 <url>
。
如果您想依赖特定的提交、分支或标签,请在描述中添加一个 ref
键:
dependencies:
kittens:
git:
url: git@github.com:munificent/kittens.git
ref: some-branch
ref 可以是 Git 允许识别提交的任何内容。
Pub 假设包位于 Git 仓库的根目录。要指定仓库中的不同位置,请指定相对于仓库根目录的 path
:
dependencies:
kittens:
git:
url: git@github.com:munificent/cats.git
path: path/to/kittens
该路径是相对于 Git 仓库根目录的。
上传到 pub.dev 的包不允许使用 Git 依赖。
路径包
#有时您会同时处理多个相关包。也许您正在构建一个框架,同时也在开发一个使用该框架的应用程序。在这些情况下,在开发期间,您会希望依赖本地文件系统上该包的实时版本。这样,一个包中的更改会立即被依赖它的包检测到。
为了处理这种情况,pub 支持路径依赖。
dependencies:
transmogrify:
path: /Users/me/transmogrify
这表示 transmogrify
的根目录是 /Users/me/transmogrify
。对于此依赖项,pub 会直接为引用包目录的 lib
目录生成一个符号链接。您对依赖包所做的任何更改都会立即生效。您无需每次更改依赖包时都运行 pub。
允许使用相对路径,并将其视为相对于包含您的 pubspec 文件的目录。
路径依赖对于本地开发很有用,但在与外界共享代码时不起作用——并非所有人都能访问您的文件系统。因此,如果您的包在 pubspec 中有任何路径依赖,您就无法将其上传到 pub.dev 网站。
相反,典型的工作流程是
- 在本地编辑您的 pubspec 以使用路径依赖。
- 开发主包及其依赖的包。
- 一旦它们都能正常工作,就发布依赖包。
- 更改您的 pubspec,使其指向现在托管的依赖包版本。
- 如果需要,也发布您的主包。
SDK
#SDK 源用于随包一起发布的任何 SDK,这些 SDK 本身也可能是依赖项。目前,Flutter 是唯一受支持的 SDK。
语法如下所示
dependencies:
flutter_driver:
sdk: flutter
sdk:
后面的标识符表示该包来自哪个 SDK。如果它是 flutter
,则只要满足以下条件,该依赖项就可满足:
- Pub 在
flutter
可执行文件的上下文中运行 - Flutter SDK 包含具有给定名称的包
如果它是一个未知标识符,则该依赖项始终被视为未满足。
版本约束
#假设您的包 A 依赖于包 B。您如何向其他开发者表明包 B 的哪个版本与包 A 的给定版本兼容?
为了让开发者了解版本兼容性,请指定版本约束。您希望允许尽可能宽的版本范围,以提供包用户灵活性。该范围应排除不兼容或未经测试的版本。
Dart 社区使用语义化版本控制1。
从 Dart 2.19 开始,您可以使用传统语法或插入符语法来表达版本约束。两种语法都指定了兼容的版本范围。
传统语法提供了一个明确的范围,如 '>=1.2.3 <2.0.0'
。插入符语法提供了一个明确的起始版本 ^1.2.3
。
environment:
# This package must use a 3.x version of the Dart SDK starting with 3.2.
sdk: ^3.2.0
dependencies:
transmogrify:
hosted:
name: transmogrify
url: https://some-package-server.com
# This package must use a 1.x version of transmogrify starting with 1.4.
version: ^1.4.0
要了解更多关于 pub 的版本系统,请参阅包版本控制页面。
传统语法
#使用传统语法的版本约束可以使用以下任何值
值 | 允许 | 使用? | 备注 |
---|---|---|---|
任意 | 所有版本 | 否 | 用作空版本约束的明确声明。 |
1.2.3 | 仅给定版本 | 否 | 由于对使用您包的应用程序施加了额外限制,因此限制了您包的采用。 |
>=1.2.3 | 给定版本或更高版本 | 是 | |
>1.2.3 | 晚于给定版本的版本 | 否 | |
<=1.2.3 | 给定版本或更早版本 | 否 | |
<1.2.3 | 早于给定版本的版本 | 否 | 当您知道某个上限版本不兼容您的包时,请使用此项。此版本可能是引入某些破坏性变更的第一个版本。 |
您可以指定版本值的任意组合,只要它们的范围有交集。例如,如果您将版本值设置为 '>=1.2.3 <2.0.0'
,这将结合这两个限制,因此依赖项可以是 1.2.3
到 2.0.0
(不包括 2.0.0
本身)之间的任何版本。
插入符语法
#插入符语法以紧凑的方式表达版本约束。^version
意味着保证与给定版本向后兼容的所有版本范围。此范围将包括所有版本,直到下一个引入破坏性变更的版本。由于 Dart 使用语义化版本控制,对于任何 1.0 或更高版本的包,这将是下一个主要版本;对于任何早于 1.0 版本的包,这将是下一个次要版本。
版本值 | 范围涵盖至 | 插入符语法 | 传统语法 |
---|---|---|---|
>=1.0 | 下一个主要版本 | ^1.3.0 | '>=1.3.0 <2.0.0' |
<1.0 | 下一个次要版本 | ^0.1.2 | '>=0.1.2 <0.2.0' |
以下示例展示了插入符语法
dependencies:
# Covers all versions from 1.3.0 to 1.y.z, not including 2.0.0
path: ^1.3.0
# Covers all versions from 1.1.0 to 1.y.z, not including 2.0.0
collection: ^1.1.0
# Covers all versions from 0.1.2 to 0.1.z, not including 0.2.0
string_scanner: ^0.1.2
开发依赖
#Pub 支持两种类型的依赖:常规依赖和开发依赖。开发依赖与常规依赖的不同之处在于,您所依赖的包的开发依赖会被忽略。例如:
假设 transmogrify
包在其测试中(且仅在其测试中)使用了 test
包。如果有人只是想使用 transmogrify
——导入其库——那么它实际上并不需要 test
。在这种情况下,它会将 test
指定为开发依赖。它的 pubspec 会类似这样:
dev_dependencies:
test: ^1.25.0
Pub 会获取您的包所依赖的每个包,以及这些包所传递依赖的所有内容。它还会获取您包的开发依赖,但会忽略任何被依赖包的开发依赖。Pub 只获取您自己包的开发依赖。因此,当您的包依赖 transmogrify
时,它将获取 transmogrify
但不获取 test
。
决定使用常规依赖还是开发依赖的规则很简单:如果依赖项是从您的 lib
或 bin
目录中的内容导入的,则它需要是一个常规依赖。如果它只从 test
、example
等目录导入,则它可以而且应该是一个开发依赖。
使用开发依赖可以使依赖图更小。这使得 pub
运行更快,并且更容易找到满足所有约束的包版本集。
依赖覆盖
#您可以使用 dependency_overrides
来暂时覆盖所有对依赖项的引用。
例如,您可能正在更新已发布的包 transmogrify 的本地副本。Transmogrify 在您的依赖图中被其他包使用,但您不想在本地克隆每个包并更改每个 pubspec 以测试您本地的 transmogrify 副本。
在这种情况下,您可以使用 dependency_overrides
来覆盖依赖项,指定包含包本地副本的目录。
pubspec 文件看起来会像下面这样
name: my_app
dependencies:
transmogrify: ^1.2.0
dependency_overrides:
transmogrify:
path: ../transmogrify_patch/
当您运行 dart pub get
或 dart pub upgrade
时,pubspec 的 lockfile 会更新以反映您依赖项的新路径,并且无论何处使用 transmogrify,pub 都会使用本地版本。
您还可以使用 dependency_overrides
来指定包的特定版本:
name: my_app
dependencies:
transmogrify: ^1.2.0
dependency_overrides:
transmogrify: '3.2.1'
在包解析过程中,只考虑 包自身 pubspec 中的依赖覆盖。任何被依赖包内部的依赖覆盖都会被忽略。
因此,如果您将包发布到 pub.dev,请记住,您的包的依赖覆盖会被您包的所有用户忽略。
如果您正在使用 pub 工作区,则每个工作区包都可以有 dependency_overrides
,但在工作区中,单个包只能被覆盖一次。
pubspec_overrides.yaml
#如果您想更改 pubspec.yaml
文件解析的某些方面,但又不想更改实际文件,可以在 pubspec.yaml
旁边放置一个名为 pubspec_overrides.yaml
的文件。
该文件中的属性将覆盖 pubspec.yaml
中的属性。
可以覆盖的属性有
dependency_overrides
workspace
resolution
这有助于避免意外将临时覆盖提交到版本控制。它还可以更轻松地从脚本生成覆盖。
在 pub 工作区中,每个工作区包都可以有一个 pubspec_overrides.yaml
文件。
最佳实践
#积极主动地管理您的依赖项。尽可能确保您的包依赖于最新版本的包。如果您的包依赖于一个过时的包,那么该过时的包可能又依赖其依赖树中的其他过时包。过时的包版本可能对应用程序的稳定性、性能和质量产生负面影响。
我们建议以下包依赖最佳实践。
使用插入符语法
#使用插入符语法指定依赖项。这允许 pub 工具在包的新版本可用时选择它们。此外,它还对允许的版本设置了上限。
依赖最新的稳定包版本
#使用 dart pub upgrade
更新到 pubspec 允许的最新包版本。要识别您的应用或包中未处于最新稳定版本的依赖项,请使用 dart pub outdated
。
收紧开发依赖的版本约束
#开发依赖定义了您仅在开发时才需要的包。完成的应用程序不需要这些包。这些包的示例包括测试或代码生成工具。将 dev_dependencies
中包的版本约束设置为您的包所依赖的最新版本的下限。
收紧开发依赖的版本约束可能类似于以下内容
dev_dependencies:
build_runner: ^2.4.15
lints: ^5.1.1
test: ^1.25.15
此 YAML 将 dev_dependencies
设置为最新的补丁版本。
更新包依赖时进行测试
#如果您运行 dart pub upgrade
而不更新您的 pubspec,API 应该保持不变,并且您的代码应该像以前一样运行——但请务必测试以确保。如果您修改 pubspec 并更新到新的主要版本,那么您可能会遇到破坏性变更,因此需要更彻底地测试。
使用降级依赖进行测试
#在开发用于发布的包时,通常最好允许尽可能广泛的依赖约束。广泛的依赖约束减少了包使用者面临版本解析冲突的可能性。
例如,如果您依赖 foo: ^1.2.3
并且发布了 foo
的 1.3.0
版本,那么保留现有依赖约束 (^1.2.3
) 可能是合理的。但如果您的包开始使用在 1.3.0
中添加的功能,那么您将需要将约束提升到 ^1.3.0
。
然而,当需要提升依赖约束时,很容易忘记。因此,最佳实践是在发布之前针对降级依赖测试您的包。
要针对降级依赖进行测试,请运行 dart pub downgrade
并验证您的包在分析时没有错误并通过所有测试:
dart pub downgrade
dart analyze
dart test
使用降级依赖进行测试应与使用最新依赖进行正常测试同时进行。如果需要提升依赖约束,请自行更改它们或使用 dart pub upgrade --tighten
将依赖项更新到最新版本。
验证已下载包的完整性
#检索新依赖项时,使用 --enforce-lockfile
选项以确保提取的包内容与原始存档的内容匹配。在不修改 lockfile 的情况下,此标志仅在以下情况下解析新依赖项:
pubspec.yaml
满足要求pubspec.lock
不缺失- 包的内容哈希匹配