内容

包布局约定

构建 pub 包 时,我们建议您遵循本页介绍的约定。它们描述了您如何在包中组织文件和目录,以及如何命名事物。

以下是一个使用这些指南的所有方面的完整包(名为 enchilada)的示例

enchilada/
  .dart_tool/ *
  pubspec.yaml
  pubspec.lock **
  LICENSE
  README.md
  CHANGELOG.md
  benchmark/
    make_lunch.dart
  bin/
    enchilada
  doc/
    api/ ***
    getting_started.md
  example/
    main.dart
  hook/
    build.dart
  integration_test/
    app_test.dart
  lib/
    enchilada.dart
    tortilla.dart
    guacamole.css
    src/
      beans.dart
      queso.dart
  test/
    enchilada_test.dart
    tortilla_test.dart
  tool/
    generate_docs.dart
  web/
    index.html
    main.dart
    style.css

* .dart_tool/ 目录是在您运行 dart pub get 后存在的。请勿将其检入源代码管理。要了解更多信息,请参阅 针对工具的项目特定缓存

** pubspec.lock 文件是在您运行 dart pub get 后存在的。除非您的包是 应用程序包,否则请将其从源代码管理中排除。

*** doc/api 目录是在您运行 dart doc 后在本地存在的。请勿将 api 目录检入源代码管理。

Pubspec

#
enchilada/
  pubspec.yaml
  pubspec.lock

每个包都有一个 pubspec,一个名为 pubspec.yaml 的文件,位于包的根目录中。这才是让它成为一个包的原因。

在包上运行 dart pub getdart pub upgradedart pub downgrade 会创建一个名为 pubspec.lock锁文件。如果您的包是 应用程序包,请将锁文件检入源代码管理。否则请勿检入。

有关更多信息,请参阅 pubspec 页面

LICENSE

#
enchilada/
  LICENSE

如果您要发布您的包,请包含一个名为 LICENSE 的许可证文件。我们建议使用 OSI 批准的许可证,例如 BSD-3-Clause,以便其他人可以使用您的工作成果。

README.md

#
enchilada/
  README.md

开源中非常常见的另一个文件是 README 文件,用于描述项目。这在 pub 中尤其重要。当您上传到 pub.dev 网站 时,您的 README.md 文件将显示在您的包页面上,并以 Markdown 形式呈现。这是向人们介绍您的代码的最佳位置。

有关如何编写优秀的 README 的指南,请参阅 编写包页面

CHANGELOG.md

#
enchilada/
  CHANGELOG.md

包含一个 CHANGELOG.md 文件,其中包含每个包版本的节,并附带帮助包用户升级的说明。包用户通常会查看更改日志以发现错误修复和新功能,或者确定升级到最新版本的包需要多少工作量。

为了支持解析 CHANGELOG.md 的工具,请使用以下格式

  • 每个版本都有一个带有标题的节。
  • 版本标题要么都是一级标题,要么都是二级标题。
  • 版本标题文本包含一个包版本号,可选地以“v”为前缀。

当您将您的包上传到 pub.dev 网站 时,您的包的 CHANGELOG.md 文件(如果有)会显示在更改日志选项卡中,并以 Markdown 形式呈现。

以下是一个 CHANGELOG.md 文件的示例。如示例所示,您可以添加子节。

markdown
# 1.0.1

* Fixed missing exclamation mark in `sayHi()` method.

# 1.0.0

* **Breaking change:** Removed deprecated `sayHello()` method.
* Initial stable release.

## Upgrading from 0.1.x

Change all calls to `sayHello()` to instead be to `sayHi()`.

# 0.1.1

* Deprecated the `sayHello()` method; use `sayHi()` instead.

# 0.1.0

* Initial development release.

公共目录

#

您的包中的两个目录对其他包是公开的:libbin。您将 公共库 放入 lib 中,将 公共工具 放入 bin 中。

公共库

#

以下目录结构显示了 enchilada 的 lib 部分

enchilada/
  lib/
    enchilada.dart
    tortilla.dart

许多 定义了 Dart 库,其他包可以导入和使用这些库。这些公共 Dart 库文件位于名为 lib 的目录中。

大多数包定义了一个单一库,用户可以导入和使用它。在这种情况下,它的名称通常应该与包的名称相同,例如此示例中的 enchilada.dart。但您也可以定义其他库,并使用对您的包有意义的任何名称。

这样一来,用户就可以使用包的名称和库文件来导入这些库,例如

dart
import 'package:enchilada/enchilada.dart';
import 'package:enchilada/tortilla.dart';

如果您想组织您的公共库,您也可以在 lib 中创建子目录。如果您这样做,用户将在导入库时指定该路径。假设您有以下文件层次结构

enchilada/
  lib/
    some/
      path/
        olives.dart

用户将 olives.dart 导入如下

dart
import 'package:enchilada/some/path/olives.dart';

请注意,只有应该放在 lib 中。入口点(包含 main() 函数的 Dart 脚本)不能放在 lib 中。如果您将 Dart 脚本放在 lib 中,您会发现它包含的任何 package: 导入都无法解析。相反,您的入口点应该放在适当的 入口点目录 中。

有关包的更多信息,请参阅 创建包

公共工具

#

放置在 bin 目录中的 Dart 脚本是公开的。如果您位于包的目录中,可以使用 dart run 运行来自任何其他包的 bin 目录的脚本,该包是该包所依赖的。从任何目录,您可以 运行脚本,这些脚本来自使用 dart pub global activate 激活的包。

如果您希望您的包被依赖,并且您希望您的脚本对您的包是私有的,请将其放在顶层的 tool 目录中。如果您不希望您的包被依赖,您可以将您的脚本保留在 bin 中。

公共资产

#
enchilada/
  lib/
    guacamole.css

虽然大多数包的存在是为了让您重用 Dart 代码,但您也可以重用其他类型的内容。例如,一个用于 Bootstrap 的包可能会包含许多 CSS 文件供包的使用者使用。

这些文件放在顶层的 lib 目录中。您可以将任何类型文件放在其中,并使用子目录对其进行组织,具体取决于您的喜好。

实现文件

#
enchilada/
  lib/
    src/
      beans.dart
      queso.dart

lib 中的库是公开可见的:其他包可以自由地导入它们。但是,包中的许多代码都是内部实现库,应该只由包本身导入和使用。这些库放在 lib 的一个名为 src 的子目录中。如果您需要进行组织,也可以在其中创建子目录。

您可以自由地从同一包中的其他 Dart 代码(如 lib 中的其他库、bin 中的脚本和测试)导入位于 lib/src 中的库,但您永远不应该从另一个包的 lib/src 目录中导入。这些文件不是包的公共 API 的一部分,它们可能会以可能破坏您代码的方式发生更改。

您如何从自己的包中导入库取决于库的位置

例如

lib/beans.dart
dart
// When importing from within lib:
import 'src/beans.dart';
test/beans_test.dart
dart
// When importing from outside lib:
import 'package:enchilada/src/beans.dart';

您在此处使用的名称(在本例中为 enchilada)是您在包的 pubspec 中为您的包指定的名称。

Web 文件

#
enchilada/
  web/
    index.html
    main.dart
    style.css

对于 Web 包,请将入口代码(包含main()的 Dart 脚本以及支持文件,例如 CSS 或 HTML)放在web目录下。如果需要,您可以将web目录组织成子目录。

库代码放在lib目录下。如果库不是由web目录下的代码或其他包直接导入的,则将其放在lib/src目录下。将基于 Web 的示例放在example目录下。有关资产(例如图像)的放置位置,请参见公共资产

命令行应用

#
enchilada/
  bin/
    enchilada

一些包定义了可以直接从命令行运行的程序。这些程序可以是 shell 脚本或任何其他脚本语言,包括 Dart。

如果您的包定义了此类代码,请将其放在名为bin的目录中。如果您使用dart pub global进行了设置,您可以在命令行的任何位置运行该脚本。

测试和基准测试

#
enchilada/
  test/
    enchilada_test.dart
    tortilla_test.dart

每个包都应该有测试。在 pub 中,惯例是将大部分测试放在test目录中(或您喜欢的目录中),并且文件名的结尾为_test

通常,这些测试使用test包。

enchilada/
  integration_test/
    app_test.dart

Flutter 应用程序包也可能具有特殊的集成测试,这些测试使用integration_test包。这些测试位于它们自己的integration_test目录中。

其他包可以选择遵循类似的模式,以将它们较慢的集成测试与单元测试分开,但请注意,默认情况下,dart test不会运行这些测试。您必须使用dart test integration_test显式地运行它们。

enchilada/
  benchmark/
    make_lunch.dart

具有性能关键代码的包也可能包含基准测试。这些测试并非为了正确性,而是为了速度(或内存使用情况,或可能的其他经验指标)。

文档

#
enchilada/
  doc/
    api/
    getting_started.md

如果您有代码和测试,您可能需要的下一个部分是好的文档。这些文档位于名为doc的目录中。

当您运行dart doc工具时,它会默认将 API 文档放在doc/api目录下。由于 API 文档是从源代码生成的,因此您不应该将其放在源代码管理中。

除了生成的api之外,我们没有关于您编写的文档的格式或组织的任何指南。使用您喜欢的任何标记格式。

示例

#
enchilada/
  example/
    main.dart

代码、测试、文档,还有什么您的用户可能需要?当然是使用您包的独立示例程序!这些程序放在example目录中。如果示例很复杂并且使用多个文件,请考虑为每个示例创建一个目录。否则,您可以将每个示例直接放在example中。

在您的示例中,使用package:导入您自己包中的文件。这将确保您包中的示例代码看起来与包外部的代码完全一样。

如果您可能发布您的包,请考虑创建一个包含以下名称之一的示例文件

  • example/example[.md]
  • example[/lib]/main.dart
  • example[/lib]/package_name.dart
  • example[/lib]/package_name_example.dart
  • example[/lib]/example.dart
  • example/README[.md]

当您发布包含一个或多个上述文件的包时,pub.dev 网站会创建一个示例选项卡来显示它找到的第一个文件(按照列表中显示的顺序进行搜索)。例如,如果您的包在其example目录下有许多文件,包括一个名为README.md的文件,那么您的包的示例选项卡将显示example/README.md的内容(解析为Markdown)。

内部工具和脚本

#
enchilada/
  tool/
    generate_docs.dart

成熟的包通常有一些小的辅助脚本和程序,人们在开发包本身时运行它们。想想测试运行器、文档生成器或其他一些自动化部分。

bin中的脚本不同,这些脚本不是供包的外部用户使用。如果您有任何这些脚本,请将其放在名为tool的目录中。

钩子

#
enchilada/
  hook/
    build.dart

包可以定义要在 Dart 和 Flutter SDK 中调用的钩子。这些钩子具有预定义的 CLI,如果存在,将由 SDK 工具调用。

由于这些钩子是在运行和构建时由dartflutter工具调用的,因此这些钩子的依赖项必须是普通依赖项,而不是dev_dependencies

针对工具的项目特定缓存

#

.dart_tool/目录是在您运行dart pub get时创建的,并且可能在任何时候被删除。各种工具使用此目录来缓存特定于您的项目和/或本地计算机的文件。.dart_tool/目录不应检入源代码管理,也不应在计算机之间复制。

通常,删除.dart_tool/目录也是安全的,尽管一些工具可能需要重新计算缓存的信息。

示例:dart pub get工具将下载并将依赖项提取到全局$PUB_CACHE目录中,然后写入一个.dart_tool/package_config.json文件,该文件将包名称映射到全局$PUB_CACHE目录中的目录。.dart_tool/package_config.json文件由其他工具(例如分析器和编译器)使用,当它们需要解析诸如import 'package:foo/foo.dart'之类的语句时。

在开发需要项目特定缓存的工具时,您可能需要考虑使用.dart_tool/目录,因为大多数用户已经使用.gitignore忽略了它。当在用户的.dart_tool/目录中缓存工具的文件时,您应该使用唯一的子目录。为了避免冲突,.dart_tool/<tool_package_name>/形式的子目录为名为<tool_package_name>的包保留。如果您的工具不是通过pub.dev 网站发布的,您可能需要考虑发布一个占位符包以保留唯一的名称。

示例:package:build提供了一个用于编写代码生成步骤的框架。在运行这些构建步骤时,文件将缓存在.dart_tool/build/中。这有助于加快将来重新运行构建步骤的速度。