跳到主要内容

包依赖

依赖是 pub 包管理器的核心概念之一。依赖是你的包工作所需的另一个包。依赖在你的 pubspec 中指定。你仅列出直接依赖:你的包直接使用的软件。Pub 为你处理传递依赖

此页面包含有关如何指定依赖的详细信息。末尾列出了包依赖的最佳实践

概述

#

对于每个依赖,你指定你依赖的包的名称和允许的该包的版本范围。你还可以指定来源。来源告诉 pub 如何找到包。

例如,你在以下格式中指定依赖

yaml
dependencies:
  transmogrify: ^1.0.0

此 YAML 代码创建对 transmogrify 包的依赖,使用默认包仓库 (pub.dev) 并允许从 1.0.02.0.0 的任何版本(但不包括 2.0.0)。要了解有关此语法的更多信息,请查看版本约束

要指定 pub.dev 以外的来源,请使用 sdkhostedgitpath。例如,以下 YAML 代码使用 path 告诉 pub 从本地目录获取 transmogrify

yaml
dependencies:
  transmogrify:
    path: /Users/me/transmogrify

下一节描述了每个依赖来源的格式。

依赖来源

#

Pub 可以使用以下来源来查找包

托管包

#

托管包是可以从 pub.dev 站点(或另一个说相同 API 的 HTTP 服务器)下载的包。以下是声明对托管包的依赖的示例

yaml
dependencies:
  transmogrify: ^1.4.0

此示例指定你的包依赖于名为 transmogrify 的托管包,并且可以使用从 1.4.0 到 2.0.0 的任何版本(但不包括 2.0.0 本身)。

如果你想使用你自己的包仓库,你可以使用 hosted 来指定其 URL。以下 YAML 代码使用 hosted 来源创建对 transmogrify 包的依赖

yaml
environment:
  sdk: '^2.19.0'

dependencies:
  transmogrify:
    hosted: https://some-package-server.com
    version: ^1.4.0

版本约束是可选的,但建议使用。如果未给出版本约束,则假定为 any

Git 包

#

有时你处于前沿,需要使用尚未正式发布的包。也许你的包本身仍在开发中,并且正在使用同时开发的其他包。为了使这更容易,你可以直接依赖存储在 Git 仓库中的包。

yaml
dependencies:
  kittens:
    git: https://github.com/munificent/kittens.git

此处的 git 表示此包是使用 Git 找到的,之后的 URL 是可用于克隆包的 Git URL。

即使包仓库是私有的,你也可以配置你的 git 设置以使用 HTTPS 访问密钥SSH 密钥对访问仓库。然后,你可以通过使用仓库的相应 URL 来依赖该包

yaml
dependencies:
  kittens:
    # SSH URL:
    git: git@github.com:munificent/kittens.git

dart pub 命令调用 git clone 作为子进程,因此你只需要提供一个当执行 git clone <url> 时有效的 <url>

如果要依赖特定的 commit、分支或 tag,请将 ref 键添加到描述中

yaml
dependencies:
  kittens:
    git:
      url: git@github.com:munificent/kittens.git
      ref: some-branch

ref 可以是 Git 允许的任何标识 commit 的内容。

Pub 假定包位于 Git 仓库的根目录中。要指定仓库中不同的位置,请指定相对于仓库根目录的 path

yaml
dependencies:
  kittens:
    git:
      url: git@github.com:munificent/cats.git
      path: path/to/kittens

路径相对于 Git 仓库的根目录。

Git 依赖不允许作为上传到 pub.dev 的包的依赖。

路径包

#

有时你会发现自己同时处理多个相关的包。也许你在创建一个框架,同时构建一个使用它的应用程序。在这些情况下,在开发期间,你真的想依赖本地文件系统上该包的实时版本。这样,一个包中的更改会立即被依赖它的包拾取。

为了处理这个问题,pub 支持路径依赖

yaml
dependencies:
  transmogrify:
    path: /Users/me/transmogrify

这表示 transmogrify 的根目录是 /Users/me/transmogrify。对于此依赖,pub 直接为引用的包目录的 lib 目录生成一个符号链接。你对依赖包所做的任何更改都会立即看到。你无需每次更改依赖包都运行 pub。

允许使用相对路径,并且被认为是相对于包含你的 pubspec 的目录。

路径依赖对于本地开发很有用,但在与外界共享代码时不起作用——并非每个人都可以访问你的文件系统。因此,如果包的 pubspec 中有任何路径依赖,则无法将该包上传到 pub.dev 站点

相反,典型的工作流程是

  1. 在本地编辑你的 pubspec 以使用路径依赖。
  2. 处理主包及其依赖的包。
  3. 一旦它们都工作正常,发布依赖包。
  4. 更改你的 pubspec 以指向其依赖的包的现在托管的版本。
  5. 如果需要,也发布你的主包。

SDK

#

SDK 来源用于与包一起提供的任何 SDK,这些 SDK 本身可能是依赖项。目前,仅支持 Flutter SDK。

语法如下所示

yaml
dependencies:
  flutter_driver:
    sdk: flutter

sdk: 之后的标识符指示包来自哪个 SDK。如果是 flutter,则只要满足以下条件,依赖关系就是可满足的

  • Pub 在 flutter 可执行文件的上下文中运行
  • Flutter SDK 包含具有给定名称的包

如果是未知的标识符,则始终认为依赖关系不满足。

版本约束

#

假设你的包 A 依赖于包 B。你如何告知其他开发人员哪个版本的包 B 仍然与给定版本的包 A 兼容?

为了让开发人员了解版本兼容性,请指定版本约束。你希望允许尽可能广泛的版本范围,以便为你的包用户提供灵活性。该范围应排除不起作用或未经测试的版本。

Dart 社区使用语义化版本控制1

你可以使用传统语法或从 Dart 2.19 开始的caret 语法来表达版本约束。两种语法都指定了兼容版本的范围。

传统语法提供了一个显式范围,如 '>=1.2.3 <2.0.0'。Caret 语法提供了一个显式起始版本 ^1.2.3

yaml
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 版本系统的更多信息,请参阅包版本控制页面

传统语法

#

使用传统语法的版本约束可以使用以下任何值

允许使用?注释
any所有版本用作空版本约束的显式声明。
1.2.3仅给定的版本由于它对使用你的包的应用施加了额外的限制,因此限制了你的包的采用。
>=1.2.3>=version给定版本或更高版本
>1.2.3
<=1.2.3>version
<1.2.3晚于给定版本的版本<=version

给定版本或更早版本

Caret 语法

#

当你了解与你的包兼容的上限版本时,请使用此项。此版本可能是第一个引入一些破坏性更改的版本。

你可以指定版本值的任何组合,因为它们的范围相交。例如,如果你将版本值设置为 '>=1.2.3 <2.0.0',这将结合两个限制,因此依赖项可以是 1.2.32.0.0 之间的任何版本,但不包括 2.0.0 本身。 警告如果在版本约束中包含大于 (>) 字符,请引用整个约束字符串。这可以防止 YAML 将字符解释为 YAML 语法。例如:永远不要使用 >=1.2.3 <2.0.0。使用 '>=1.2.3 <2.0.0'^1.2.3Caret 语法以紧凑的方式表达版本约束。^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'

Caret 语法

yaml
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

开发依赖

#

传统语法

下一个主要版本

yaml
dev_dependencies:
  test: ^1.25.0

下一个次要版本

以下示例显示了 caret 语法

Pub 支持两种类型的依赖:常规依赖和开发依赖。开发依赖与常规依赖的不同之处在于你依赖的包的开发依赖将被忽略。这是一个例子

依赖覆盖

#

假设 transmogrify 包在其测试中且仅在其测试中使用 test 包。如果有人只想使用 transmogrify——导入其库——它实际上不需要 test。在这种情况下,它将 test 指定为开发依赖。它的 pubspec 将包含类似

Pub 获取你的包依赖的每个包,以及这些包传递依赖的所有内容。它还会获取你的包的开发依赖,但它会忽略任何依赖包的开发依赖。Pub 仅获取你的包的开发依赖。因此,当你的包依赖于 transmogrify 时,它将获取 transmogrify 但不获取 test

决定使用常规依赖还是开发依赖的规则很简单:如果依赖是从你的 libbin 目录中的某些内容导入的,则它需要是常规依赖。如果仅从 testexample 等导入,则它可以并且应该是一个开发依赖。

使用开发依赖可以使依赖图更小。这使 pub 运行更快,并使找到一组满足所有约束的包版本更容易。

yaml
name: my_app
dependencies:
  transmogrify: ^1.2.0
dependency_overrides:
  transmogrify:
    path: ../transmogrify_patch/

你可以使用 dependency_overrides 临时覆盖对依赖的所有引用。

例如,也许你正在更新已发布包 transmogrify 的本地副本。Transmogrify 被你的依赖图中的其他包使用,但你不想在本地克隆每个包并更改每个 pubspec 以测试你的 transmogrify 本地副本。

yaml
name: my_app
dependencies:
  transmogrify: ^1.2.0
dependency_overrides:
  transmogrify: '3.2.1'

pubspec 看起来会像下面这样

当你运行 dart pub getdart pub upgrade 时,pubspec 的 lockfile 将更新以反映你的依赖项的新路径,并且在任何使用 transmogrify 的地方,pub 都将使用本地版本。

你还可以使用 dependency_overrides 来指定包的特定版本

pubspec_overrides.yaml

#

使用依赖覆盖存在一定的风险。例如,使用覆盖来指定包声明支持范围之外的版本,或使用覆盖来指定具有意外行为的包的本地副本,可能会破坏你的应用程序。

在包解析期间,仅考虑包自己的 pubspec 中的依赖覆盖。任何依赖包内部的依赖覆盖都将被忽略。

因此,如果你将包发布到 pub.dev,请记住你的包的依赖覆盖将被你的包的所有用户忽略。

  • 如果你正在使用 pub 工作区,你可以在每个工作区包中都有 dependency_overrides,但单个包在工作区中只能被覆盖一次。
  • 如果你想更改 pubspec.yaml 文件的某些解析方面,但不希望更改实际文件,则可以将名为 pubspec_overrides.yaml 的文件放在 pubspec.yaml 旁边。
  • 来自该文件的属性将覆盖 pubspec.yaml 中的属性。

可以覆盖的属性是

dependency_overrides

最佳实践

#

workspace

resolution

使用 Caret 语法

#

这对于避免意外地将临时覆盖检入到版本控制中很有用。它还可以更轻松地从脚本生成覆盖。

依赖最新的稳定包版本

#

pub 工作区中,每个工作区包都可以有一个 pubspec_overrides.yaml 文件。

收紧开发依赖的版本约束

#

积极主动地管理你的依赖项。确保你的包在可能的情况下依赖最新版本的包。如果你的包依赖于过时的包,则该过时的包可能在其依赖树中依赖于其他过时的包。过时版本的包可能会对你的应用程序的稳定性、性能和质量产生负面影响。

我们建议以下包依赖的最佳实践。

yaml
dev_dependencies:
  build_runner: ^2.4.13
  lints: ^2.1.1
  test: ^1.25.8

使用caret 语法指定依赖项。这允许 pub 工具在较新版本可用时选择较新版本。此外,它对允许的版本设置了上限。

每次更新包依赖时进行测试

#

使用 dart pub upgrade 更新到你的 pubspec 允许的最新包版本。要识别你的应用程序或包中不处于最新稳定版本的依赖项,请使用 dart pub outdated

使用降级的依赖进行测试

#

开发依赖定义了你仅在开发时才需要的包。完成的应用将不需要这些包。这些包的示例包括测试或代码生成工具。在 dev_dependencies 中设置包的版本约束,使其下限为你包所依赖的最新版本。

收紧你的开发依赖的版本约束可能类似于以下内容

此 YAML 将 dev_dependencies 设置为最新的补丁版本。

如果你在不更新 pubspec 的情况下运行 dart pub upgrade,则 API 应该保持不变,并且你的代码应该像以前一样运行——但要进行测试以确保。如果你修改 pubspec 并更新到新的主要版本,那么你可能会遇到破坏性更改,因此你需要进行更彻底的测试。

dart pub downgrade
dart analyze
dart test

在开发要发布的包时,通常最好允许尽可能广泛的依赖约束。宽泛的依赖约束降低了包使用者面临版本解析冲突的可能性。

验证下载包的完整性

#

使用降级的依赖项进行测试应与使用最新依赖项的正常测试一起进行。如果需要提升依赖约束,请自行更改它们,或使用 dart pub upgrade --tighten 将依赖项更新到最新版本。

  • 注意
  • 使用 dart pub downgrade 进行测试使你能够找到你可能没有发现的不兼容性。但这并不能排除不兼容性的可能性。
  • 通常有太多不同的版本组合,以至于测试所有版本都不可行。你的依赖约束允许的旧版本也可能由于包本身或你的 dev_dependencies 的相互不兼容的版本约束而无法解析。