Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 10 additions & 74 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,13 @@
[![Dart CI](https://github.com/dart-lang/build/actions/workflows/dart.yml/badge.svg)](https://github.com/dart-lang/build/actions/workflows/dart.yml)
_Questions? Suggestions? Found a bug? Please
[file an issue](https://github.com/dart-lang/build/issues) or
[start a discussion](https://github.com/dart-lang/build/discussions)._

These packages provide libraries for generating, compiling and serving Dart code.
Code generation for Flutter and Dart packages.

[Getting started with build_runner](https://github.com/dart-lang/build/blob/master/docs/getting_started.md)
See the
[build_runner package documentation](https://pub.dev/packages/build_runner)
for how to use `build_runner` builders in your package to add serialization,
data classes, data binding, dependency injection, mocking and more.

[General FAQ](https://github.com/dart-lang/build/blob/master/docs/faq.md)

[Windows FAQ](https://github.com/dart-lang/build/blob/master/docs/windows_faq.md)

[FAQ for Builder authors](https://github.com/dart-lang/build/blob/master/docs/builder_author_faq.md).

[Additional Docs](https://github.com/dart-lang/build/blob/master/docs/)

## [build](https://github.com/dart-lang/build/blob/master/build/README.md)

Defines the interfaces for creating a `Builder` which is a way of doing codegen
that is compatible across build systems (pub, bazel, standalone runner).

For packages doing code generation this should generally be the only package
against which there is a public dependency. Packages may have a dev_dependency on
one or more of the other packages.

## [build_config](https://github.com/dart-lang/build/blob/master/build_config/README.md)

Support for parsing `build.yaml` files. Used by `build_runner`.

## [build_modules](https://github.com/dart-lang/build/blob/master/build_modules/README.md)

Support for discovering the sub-modules within packages and creating summaries
of those modules. Used by `build_web_compilers` but should not be used directly
by most users.

## [build_resolvers](https://github.com/dart-lang/build/blob/master/build_resolvers/README.md)

An implementation of the `Resolver` interface to use the analyzer during build
steps.

## [build_runner](https://github.com/dart-lang/build/blob/master/build_runner/README.md)

Provides utilities to enact builds and a way to automatically run builds based
on configuration.

This package should generally be a dev_dependency as it is used to run
standalone builds. The only exception would be wrapping the `build` and `watch`
methods with some other package.

## [build_test](https://github.com/dart-lang/build/blob/master/build_test/README.md)

Stub implementations for classes in `Build` and some utilities for running
instances of builds and checking their outputs.

This package generally only be a dev_dependency as it introduces a dependency on
package:test. The exception to that would be if you were creating another
testing-only package that wraps this one.

## [build_web_compilers](https://github.com/dart-lang/build/blob/master/build_web_compilers/README.md)

Provides the `dart2js` and `dartdevc` support for your package. To use this
package you should add it as a dev_dependency.

If you are using the automated build scripts, your project will automatically
start being compiled with dartdevc, and you can start developing with chrome
without any configuration.

<!--
TODO: scratch_space
-->

## Examples

The [example](https://github.com/dart-lang/build/tree/master/example)
directory has an example of a build with custom builders which generate outputs
into both the source tree and a hidden generated directory. Try a build with
`dart run build_runner build -o web:deploy` to see what the output looks like.

Most projects should not need custom builders.
See the [build package documentation](https://pub.dev/packages/build) to create
your own builder.
1 change: 1 addition & 0 deletions build/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## 3.0.2-wip

- Use `build_runner_core` 9.3.0.
- Documentation revamp.

## 3.0.1

Expand Down
164 changes: 48 additions & 116 deletions build/README.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,50 @@
Defines the basic pieces of how a build happens and how they interact.
_Questions? Suggestions? Found a bug? Please
[file an issue](https://github.com/dart-lang/build/issues) or
[start a discussion](https://github.com/dart-lang/build/discussions)._

## [`Builder`][dartdoc:Builder]
Package for writing code generators, called _builders_, that run with
[build_runner](https://pub.dev/packages/build_runner).

The business logic for code generation. Most consumers of the `build` package
will create custom implementations of `Builder`.
- [See also: source_gen](#see-also-source_gen)
- [The `Builder` interface](#the-builder-interface)
- [Using the analyzer](#using-the-analyzer)
- [Examples](#examples)

## [`BuildStep`][dartdoc:BuildStep]
## See also: source_gen

The way a `Builder` interacts with the outside world. Defines the unit of work
and allows reading/writing files and resolving Dart source code.
The [source_gen](https://pub.dev/packages/source_gen) package provides helpers
for writing common types of builder, for example builders that are triggered by
a particular annotation.

## [`Resolver`][dartdoc:Resolver] class
Most builders should use `source_gen`, but it's still useful to learn about the
underlying `Builder` interface that `source_gen` plugs into.

An interface into the dart [analyzer][pub:analyzer] to allow resolution of code
that needs static analysis and/or code generation.
## The `Builder` interface

## Implementing your own Builders

A `Builder` gets invoked one by one on it's inputs, and may read other files and
output new files based on those inputs.

The basic API looks like this:
A builder implements the
[Builder](https://pub.dev/documentation/build/latest/build/Builder-class.html)
interface.

```dart
abstract class Builder {
/// You can only output files that are configured here by suffix substitution.
/// You are not required to output all of these files, but no other builder
/// may declare the same outputs.
/// Declares inputs and outputs by extension.
Map<String, List<String>> get buildExtensions;

/// This is where you build and output files.
/// Builds all outputs for a single input.
FutureOr<void> build(BuildStep buildStep);
}
```

Here is an implementation of a `Builder` which just copies files to other files
with the same name, but an additional extension:
Its `buildExtensions` getter declares what inputs it runs on and what outputs
it might produce.

```dart
import 'package:build/build.dart';
During a build its `build` method gets called once per matching input.

It uses `buildStep` to read, analyze and write files.

/// A really simple [Builder], it just makes copies of .txt files!
For example, here is a builder that copies input `.txt` files to `.txt.copy` files:

```dart
class CopyBuilder implements Builder {
@override
final buildExtensions = const {
Expand All @@ -49,106 +53,34 @@ class CopyBuilder implements Builder {

@override
Future<void> build(BuildStep buildStep) async {
// Each `buildStep` has a single input.
var inputId = buildStep.inputId;
// Create the output ID from the build step input ID.
final inputId = buildStep.inputId;
final outputId = inputId.addExtension('.copy');

// Create a new target `AssetId` based on the old one.
var copy = inputId.addExtension('.copy');
var contents = await buildStep.readAsString(inputId);

// Write out the new asset.
await buildStep.writeAsString(copy, contents);
// Read from the input, write to the output.
final contents = await buildStep.readAsString(inputId);
await buildStep.writeAsString(outputId, contents);
}
}
```

It should be noted that you should _never_ touch the file system directly. Go
through the `buildStep#readAsString` and `buildStep#writeAsString` methods in
order to read and write assets. This is what enables the package to track all of
your dependencies and do incremental rebuilds. It is also what enables your
[`Builder`][dartdoc:Builder] to run on different environments.
Outputs are optional. For example, a builder that is activated by a particular
annotation will output nothing if it does not find that annotation.

### Using the analyzer

If you need to do analyzer resolution, you can use the `BuildStep#resolver`
object. This makes sure that all `Builder`s in the system share the same
analysis context, which greatly speeds up the overall system when multiple
`Builder`s are doing resolution.

Here is an example of a `Builder` which uses the `resolve` method:

```dart
import 'package:build/build.dart';

class ResolvingCopyBuilder implements Builder {
// Take a `.dart` file as input so that the Resolver has code to resolve
@override
final buildExtensions = const {
'.dart': ['.dart.copy']
};

@override
Future<void> build(BuildStep buildStep) async {
// Get the `LibraryElement` for the primary input.
var entryLib = await buildStep.inputLibrary;
// Resolves all libraries reachable from the primary input.
var resolver = buildStep.resolver;
// Get a `LibraryElement` for another asset.
var libFromAsset = await resolver.libraryFor(
AssetId.resolve(Uri.parse('some_import.dart'),
from: buildStep.inputId));
// Or get a `LibraryElement` by name.
var libByName = await resolver.findLibraryByName('my.library');
}
}
```

Once you have gotten a `LibraryElement` using one of the methods on `Resolver`,
you are now just using the regular `analyzer` package to explore your app.

### Sharing expensive objects across build steps

The build package includes a `Resource` class, which can give you an instance
of an expensive object that is guaranteed to be unique across builds, but may
be re-used by multiple build steps within a single build (to the extent that
the implementation allows). It also gives you a way of disposing of your
resource at the end of its lifecycle.

The `Resource<T>` constructor takes a single required argument which is a
factory function that returns a `FutureOr<T>`. There is also a named argument
`dispose` which is called at the end of life for the resource, with the
instance that should be disposed. This returns a `FutureOr<dynamic>`.

So a simple example `Resource` would look like this:

```dart
final resource = Resource(
() => createMyExpensiveResource(),
dispose: (instance) async {
await instance.doSomeCleanup();
});
```

You can get an instance of the underlying resource by using the
`BuildStep#fetchResource` method, whose type signature looks like
`Future<T> fetchResource<T>(Resource<T>)`.

**Important Note**: It may be tempting to try and use a `Resource` instance to
cache information from previous build steps (or even assets), but this should
be avoided because it can break the soundness of the build, and may introduce
subtle bugs for incremental builds (remember the whole build doesn't run every
time!). The `build` package relies on the `BuildStep#canRead` and
`BuildStep#readAs*` methods to track build step dependencies, so sidestepping
those can and will break the dependency tracking, resulting in inconsistent and
stale assets.
The `buildStep` passed to `build` gives easy access to the analyzer for
processing Dart source code.

## Features and bugs
Use `buildStep.resolver.compilationUnitFor` to parse a single source file, or
`libraryFor` to fully resolve it. This can be used to introspect the full API
of the source code the builder is running on. For example, a builder can learn
enough about a class's field and field types to correctly serialize it.

Please file feature requests and bugs at the [issue tracker][tracker].
## Examples

[tracker]: https://github.com/dart-lang/build/issues
There are some simple examples
[in the build repo](https://github.com/dart-lang/build/blob/master/example).

[dartdoc:Builder]: https://pub.dev/documentation/build/latest/build/Builder-class.html
[dartdoc:BuildStep]: https://pub.dev/documentation/build/latest/build/BuildStep-class.html
[dartdoc:Resolver]: https://pub.dev/documentation/build/latest/build/Resolver-class.html
[pub:analyzer]: https://pub.dev/packages/analyzer
For real examples of builders, see the list of popular builders in the
[build_runner package documentation](https://pub.dev/packages/build_runner).
1 change: 1 addition & 0 deletions build_config/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
for more information.
- Bump the min sdk to 3.7.0.
- Remove unused dep: `yaml`.
- Documentation revamp.

## 1.1.2

Expand Down
Loading
Loading