Package 的文件结构
学习一下 package 和 pub 命令的文件结构。
When you build a pub package, we encourage you to follow the conventions that this page describes. They describe how you organize the files and directories within your package, and how to name things.
Here's what a complete package (named
enchilada) that uses every corner of these
guidelines might look like:
-
enchilada/
- .dart_tool/*
-
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
- CHANGELOG.md
- LICENSE
- pubspec.yaml
- pubspec_overrides.yaml**
- pubspec.lock***
- README.md
* The .dart_tool/ directory exists after you've
run dart pub get. Don't check it into source
control. To learn more, see
Project specific caching for tools.
** The
pubspec_overrides.yaml
file, if present, overrides certain aspects of
pubspec.yaml. Usually you don't want to check
it into source control.
*** The pubspec.lock file exists after you've
run dart pub get. Leave it out of source
control unless your package is an
application packageApplication packageA Dart package that contains a runnable application.
Learn more.
**** The doc/api directory exists locally after
you've run
dart doc. Don't check the api directory into source
control.
The pubspec
#-
enchilada/
- pubspec.yaml
- pubspec.lock
Every package has a
pubspec, a file named pubspec.yaml, in the root
directory of the package. That's what makes
it a package.
Running
dart pub get,
dart pub upgrade, or
dart pub downgrade
on the package creates a lockfile, named
pubspec.lock. If your package is an
application packageApplication packageA Dart package that contains a runnable application.
Learn more, check the lockfile into source control. Otherwise, don't.
For more information, see the pubspec page.
LICENSE
#-
enchilada/
- LICENSE
If you're publishing your package, include a license file
named LICENSE. We recommend using an
OSI-approved license
such as
BSD-3-Clause,
so that others can reuse your work.
README.md
#-
enchilada/
- README.md
One file that's very common in open source is a
README file that describes the project. This is
especially important in pub. When you upload to the
pub.dev site,
your README.md file is shown—rendered as
Markdown—on the page for your package. This is the perfect place to
introduce people to your code.
For guidance on how to write a great README, see Writing package pages.
CHANGELOG.md
#-
enchilada/
- CHANGELOG.md
Include a CHANGELOG.md file that has a section
for each release of your package, with notes to help users
of your package upgrade. Users of your package often review
the changelog to discover bug fixes and new features, or to
determine how much effort it will take to upgrade to the
latest version of your package.
To support tools that parse CHANGELOG.md, use
the following format:
- Each version has its own section with a heading.
- The version headings are either all level 1 or all level 2.
- The version heading text contains a package version number, optionally prefixed with "v".
When you upload your package to the
pub.dev site,
your package's CHANGELOG.md file (if any)
appears in the Changelog tab, rendered as
Markdown.
Here's an example of a CHANGELOG.md file. As
the example shows, you can add subsections.
# 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.
Public directories
#
Two directories in your package are public to other
packages: lib and bin. You place
public libraries
in lib and
public tools
in bin.
Public libraries
#
The following directory structure shows the
lib portion of enchilada:
-
enchilada/
-
lib/
- enchilada.dart
- tortilla.dart
-
Many
packagesPackageA directory with a collection of Dart libraries,
resources, and a pubspec.yaml file describing them.
Learn more
define Dart libraries that other packages can import and
use. These public Dart library files go inside a directory
called lib.
Most packages define a single library that users can import.
In that case, its name should usually be the same as the
name of the package, like
enchilada.dart in the example here. But you can
also define other libraries with whatever names make sense
for your package.
When you do, users can import these libraries using the name of the package and the library file, like so:
import 'package:enchilada/enchilada.dart';
import 'package:enchilada/tortilla.dart';
If you want to organize your public libraries, you can also
create subdirectories inside lib. If you do
that, users will specify that path when they import it. Say
you have the following file hierarchy:
-
enchilada/
-
lib/
-
some/
-
path/
- olives.dart
-
-
-
Users import olives.dart as follows:
import 'package:enchilada/some/path/olives.dart';
Note that only libraries should be in
lib. Entrypoints—Dart scripts with a
main() function—cannot go in lib.
If you place a Dart script inside lib, you will
discover that any package: imports it contains
don't resolve. Instead, your entrypoints should go in the
appropriate
entrypoint directoryEntrypoint directoryA directory that contains Dart entrypoints.
Learn more.
For more information on packages, see Creating packages.
Public tools
#
Dart scripts placed inside of the bin directory
are public. If you're inside the directory of a package, you
can use
dart run to run
scripts from the bin
directories of any other package the package depends on.
From any directory, you can
run scripts
from packages that you have activated using
dart pub global activate.
If you intend for your package to be depended on, and you
want your scripts to be private to your package, place them
in the top-level tool directory. If you don't
intend for your package to be depended on, you can leave
your scripts in bin.
Public assets
#-
enchilada/
-
lib/
- guacamole.css
-
While most packages exist to let you reuse Dart code, you can also reuse other kinds of content. For example, a package for Bootstrap might include a number of CSS files for consumers of the package to use.
These go in the top-level lib directory. You
can put any kind of file in there and organize it with
subdirectories however you like.
Implementation files
#-
enchilada/
-
lib/
-
src/
- beans.dart
- queso.dart
-
-
The libraries inside lib are publicly visible:
other packages are free to import them. But much of a
package's code is internal implementation libraries that
should only be imported and used by the package itself.
Those go inside a subdirectory of lib called
src. You can create subdirectories in there if
it helps you organize things.
You are free to import libraries that live in
lib/src from within other Dart code in the
same package (like other libraries in
lib, scripts in bin, and tests)
but you should never import from another package's
lib/src directory. Those files are not part of
the package's public API, and they might change in ways that
could break your code.
How you import libraries from within your own package depends on the locations of the libraries:
-
When
reaching inside or outside
lib/(lint: avoid_relative_lib_imports), usepackage:. - Otherwise, prefer relative imports.
For example:
// When importing from within lib:
import 'src/beans.dart';
// When importing from outside lib:
import 'package:enchilada/src/beans.dart';
The name you use here (in this case enchilada)
is the name you specify for your package in its
pubspec.
Web files
#-
enchilada/
-
web/
- index.html
- main.dart
- style.css
-
For web packages, place entrypoint code—Dart scripts that
include
main() and supporting files, such as CSS or
HTML—under web. You can organize the
web directory into subdirectories if you like.
Put
library code
under lib. If the library isn't imported
directly by code under web, or by another
package, put it under lib/src. Put
web-based examples
under example. See
Public assets
for tips on where to put assets, such as images.
Command-line apps
#-
enchilada/
-
bin/
- enchilada
-
Some packages define programs that can be run directly from the command line. These can be shell scripts or any other scripting language, including Dart.
If your package defines code like this, put it in a
directory named bin. You can run that script
from anywhere on the command line, if you set it up using
dart pub global.
Tests and benchmarks
#-
enchilada/
-
test/
- enchilada_test.dart
- tortilla_test.dart
-
Every package should have tests. With pub, the convention is
that most of these go in a test directory (or
some directory inside it if you like) and have
_test at the end of their file names.
Typically, these use the test package.
-
enchilada/
-
integration_test/
- app_test.dart
-
Flutter app packages might also have special integration
tests, which use the
integration_test
package. These tests live in their own
integration_test directory.
Other packages might choose to follow a similar pattern, to
separate their slower integration tests from their unit
tests, but note that by default dart test
will not run these tests. You will have to explicitly run
them with
dart test integration_test.
-
enchilada/
-
benchmark/
- make_lunch.dart
-
Packages that have performance-critical code might also include benchmarks. These test the API not for correctness but for speed (or memory use, or maybe other empirical metrics).
Documentation
#-
enchilada/
-
doc/
- api/
- getting_started.md
-
If you have code and tests, the next piece you might want is
good documentation. That goes inside a directory named
doc.
When you run the
dart doc tool,
it places the API documentation, by default, under
doc/api. Since the API documentation is
generated from the source code, you should not place it
under source control.
Other than the generated api, we don't have any
guidelines about format or organization of the documentation
that you author. Use whatever markup format that you prefer.
Examples
#-
enchilada/
-
example/
- main.dart
-
Code, tests, docs, what else could your users want?
Standalone example programs that use your package, of
course! Those go inside the example directory.
If the examples are complex and use multiple files, consider
making a directory for each example. Otherwise, you can
place each one right inside example.
In your examples, use package: to import files
from your own package. That ensures that the example code in
your package looks exactly like code outside of your package
would look.
If you might publish your package, consider creating an example file with one of the following names:
example/example[.md]example[/lib]/main.dart-
example[/lib]/package_name.dart -
example[/lib]/package_name_example.dart example[/lib]/example.dartexample/README[.md]
When you publish a package that contains one or more of the
above files, the pub.dev site creates an
Example tab to display the first file it
finds (searching in the order shown in the list above). For
example, if your package has many files under its
example directory, including a file named
README.md, then your package's Example tab
displays the contents of example/README.md
(parsed as
Markdown).
Internal tools and scripts
#-
enchilada/
-
tool/
- generate_docs.dart
-
Mature packages often have little helper scripts and programs that people run while developing the package itself. Think things like test runners, documentation generators, or other bits of automation.
Unlike the scripts in bin, these are
not for external users of the package. If you have
any of these, place them in a directory called
tool.
Hooks
#-
enchilada/
-
hook/
- build.dart
-
Packages can define hooks to be invoked by the Dart and Flutter SDK. These hooks have a predefined CLI, and will be invoked by the SDK tools if present.
Because these hooks are invoked by the
dart and flutter tools on runs and
builds, the dependencies of these hooks must be normal
dependencies and not dev_dependencies.
To learn more about how to define hooks, refer to the build hooks documentation.
Project-specific caching for tools
#
The .dart_tool/ directory is created when you
run dart pub get and might be deleted at any
time. Various tools use this directory for caching files
specific to your project and/or local machine. The
.dart_tool/ directory should never be checked
into source control, or copied between machines.
It is also generally safe to delete the
.dart_tool/ directory, though some tools might
need recompute the cached information.
Example: The
dart pub get
tool will download and extract dependencies to a global
$PUB_CACHE directory, and then write a
.dart_tool/package_config.json file mapping
package names
to directories in the global
$PUB_CACHE directory. The
.dart_tool/package_config.json file is used by
other tools, such as the analyzer and compilers when they
need to resolve statements such as
import 'package:foo/foo.dart'.
When developing a tool that needs project-specific caching,
you might consider using the
.dart_tool/ directory because most users
already ignore it with .gitignore. When caching
files for your tool in a user's
.dart_tool/ directory, you should use a unique
subdirectory. To avoid collisions, subdirectories of the
form .dart_tool/<tool_package_name>/ are
reserved for the package named
<tool_package_name>. If your tool isn't
distributed through the
pub.dev site,
you might consider publishing a placeholder package in order
to reserve the unique name.
Example:
package:build
provides a framework for writing code generation steps. When
running these build steps, files are cached in
.dart_tool/build/. This helps speed-up future
re-runs of the build steps.