1- Defines the basic pieces of how a build happens and how they interact.
1+ _ Questions? Suggestions? Found a bug? Please
2+ [ file an issue] ( https://github.com/dart-lang/build/issues ) or
3+ [ start a discussion] ( https://github.com/dart-lang/build/discussions ) ._
24
3- ## [ ` Builder ` ] [ dartdoc:Builder ]
5+ Package for writing code generators, called _ builders_ , that run with
6+ [ build_runner] ( https://pub.dev/packages/build_runner ) .
47
5- The business logic for code generation. Most consumers of the ` build ` package
6- will create custom implementations of ` Builder ` .
8+ - [ See also: source_gen] ( #see-also-source_gen )
9+ - [ The ` Builder ` interface] ( #the-builder-interface )
10+ - [ Using the analyzer] ( #using-the-analyzer )
11+ - [ Examples] ( #examples )
712
8- ## [ ` BuildStep ` ] [ dartdoc:BuildStep ]
13+ ## See also: source_gen
914
10- The way a ` Builder ` interacts with the outside world. Defines the unit of work
11- and allows reading/writing files and resolving Dart source code.
15+ The [ source_gen] ( https://pub.dev/packages/source_gen ) package provides helpers
16+ for writing common types of builder, for example builders that are triggered by
17+ a particular annotation.
1218
13- ## [ ` Resolver ` ] [ dartdoc:Resolver ] class
19+ Most builders should use ` source_gen ` , but it's still useful to learn about the
20+ underlying ` Builder ` interface that ` source_gen ` plugs into.
1421
15- An interface into the dart [ analyzer] [ pub:analyzer ] to allow resolution of code
16- that needs static analysis and/or code generation.
22+ ## The ` Builder ` interface
1723
18- ## Implementing your own Builders
19-
20- A ` Builder ` gets invoked one by one on it's inputs, and may read other files and
21- output new files based on those inputs.
22-
23- The basic API looks like this:
24+ A builder implements the
25+ [ Builder] ( https://pub.dev/documentation/build/latest/build/Builder-class.html )
26+ interface.
2427
2528``` dart
2629abstract class Builder {
27- /// You can only output files that are configured here by suffix substitution.
28- /// You are not required to output all of these files, but no other builder
29- /// may declare the same outputs.
30+ /// Declares inputs and outputs by extension.
3031 Map<String, List<String>> get buildExtensions;
3132
32- /// This is where you build and output files .
33+ /// Builds all outputs for a single input .
3334 FutureOr<void> build(BuildStep buildStep);
3435}
3536```
3637
37- Here is an implementation of a ` Builder ` which just copies files to other files
38- with the same name, but an additional extension:
38+ Its ` buildExtensions ` getter declares what inputs it runs on and what outputs
39+ it might produce.
3940
40- ``` dart
41- import 'package:build/build.dart';
41+ During a build its ` build ` method gets called once per matching input.
42+
43+ It uses ` buildStep ` to read, analyze and write files.
4244
43- /// A really simple [Builder], it just makes copies of .txt files!
45+ For example, here is a builder that copies input ` .txt ` files to ` .txt.copy ` files:
46+
47+ ``` dart
4448class CopyBuilder implements Builder {
4549 @override
4650 final buildExtensions = const {
@@ -49,106 +53,34 @@ class CopyBuilder implements Builder {
4953
5054 @override
5155 Future<void> build(BuildStep buildStep) async {
52- // Each `buildStep` has a single input.
53- var inputId = buildStep.inputId;
56+ // Create the output ID from the build step input ID.
57+ final inputId = buildStep.inputId;
58+ final outputId = inputId.addExtension('.copy');
5459
55- // Create a new target `AssetId` based on the old one.
56- var copy = inputId.addExtension('.copy');
57- var contents = await buildStep.readAsString(inputId);
58-
59- // Write out the new asset.
60- await buildStep.writeAsString(copy, contents);
60+ // Read from the input, write to the output.
61+ final contents = await buildStep.readAsString(inputId);
62+ await buildStep.writeAsString(outputId, contents);
6163 }
6264}
6365```
6466
65- It should be noted that you should _ never_ touch the file system directly. Go
66- through the ` buildStep#readAsString ` and ` buildStep#writeAsString ` methods in
67- order to read and write assets. This is what enables the package to track all of
68- your dependencies and do incremental rebuilds. It is also what enables your
69- [ ` Builder ` ] [ dartdoc:Builder ] to run on different environments.
67+ Outputs are optional. For example, a builder that is activated by a particular
68+ annotation will output nothing if it does not find that annotation.
7069
7170### Using the analyzer
7271
73- If you need to do analyzer resolution, you can use the ` BuildStep#resolver `
74- object. This makes sure that all ` Builder ` s in the system share the same
75- analysis context, which greatly speeds up the overall system when multiple
76- ` Builder ` s are doing resolution.
77-
78- Here is an example of a ` Builder ` which uses the ` resolve ` method:
79-
80- ``` dart
81- import 'package:build/build.dart';
82-
83- class ResolvingCopyBuilder implements Builder {
84- // Take a `.dart` file as input so that the Resolver has code to resolve
85- @override
86- final buildExtensions = const {
87- '.dart': ['.dart.copy']
88- };
89-
90- @override
91- Future<void> build(BuildStep buildStep) async {
92- // Get the `LibraryElement` for the primary input.
93- var entryLib = await buildStep.inputLibrary;
94- // Resolves all libraries reachable from the primary input.
95- var resolver = buildStep.resolver;
96- // Get a `LibraryElement` for another asset.
97- var libFromAsset = await resolver.libraryFor(
98- AssetId.resolve(Uri.parse('some_import.dart'),
99- from: buildStep.inputId));
100- // Or get a `LibraryElement` by name.
101- var libByName = await resolver.findLibraryByName('my.library');
102- }
103- }
104- ```
105-
106- Once you have gotten a ` LibraryElement ` using one of the methods on ` Resolver ` ,
107- you are now just using the regular ` analyzer ` package to explore your app.
108-
109- ### Sharing expensive objects across build steps
110-
111- The build package includes a ` Resource ` class, which can give you an instance
112- of an expensive object that is guaranteed to be unique across builds, but may
113- be re-used by multiple build steps within a single build (to the extent that
114- the implementation allows). It also gives you a way of disposing of your
115- resource at the end of its lifecycle.
116-
117- The ` Resource<T> ` constructor takes a single required argument which is a
118- factory function that returns a ` FutureOr<T> ` . There is also a named argument
119- ` dispose ` which is called at the end of life for the resource, with the
120- instance that should be disposed. This returns a ` FutureOr<dynamic> ` .
121-
122- So a simple example ` Resource ` would look like this:
123-
124- ``` dart
125- final resource = Resource(
126- () => createMyExpensiveResource(),
127- dispose: (instance) async {
128- await instance.doSomeCleanup();
129- });
130- ```
131-
132- You can get an instance of the underlying resource by using the
133- ` BuildStep#fetchResource ` method, whose type signature looks like
134- ` Future<T> fetchResource<T>(Resource<T>) ` .
135-
136- ** Important Note** : It may be tempting to try and use a ` Resource ` instance to
137- cache information from previous build steps (or even assets), but this should
138- be avoided because it can break the soundness of the build, and may introduce
139- subtle bugs for incremental builds (remember the whole build doesn't run every
140- time!). The ` build ` package relies on the ` BuildStep#canRead ` and
141- ` BuildStep#readAs* ` methods to track build step dependencies, so sidestepping
142- those can and will break the dependency tracking, resulting in inconsistent and
143- stale assets.
72+ The ` buildStep ` passed to ` build ` gives easy access to the analyzer for
73+ processing Dart source code.
14474
145- ## Features and bugs
75+ Use ` buildStep.resolver.compilationUnitFor ` to parse a single source file, or
76+ ` libraryFor ` to fully resolve it. This can be used to introspect the full API
77+ of the source code the builder is running on. For example, a builder can learn
78+ enough about a class's field and field types to correctly serialize it.
14679
147- Please file feature requests and bugs at the [ issue tracker ] [ tracker ] .
80+ ## Examples
14881
149- [ tracker ] : https://github.com/dart-lang/build/issues
82+ There are some simple examples
83+ [ in the build repo] ( https://github.com/dart-lang/build/blob/master/example ) .
15084
151- [ dartdoc:Builder ] : https://pub.dev/documentation/build/latest/build/Builder-class.html
152- [ dartdoc:BuildStep ] : https://pub.dev/documentation/build/latest/build/BuildStep-class.html
153- [ dartdoc:Resolver ] : https://pub.dev/documentation/build/latest/build/Resolver-class.html
154- [ pub:analyzer ] : https://pub.dev/packages/analyzer
85+ For real examples of builders, see the list of popular builders in the
86+ [ build_runner package documentation] ( https://pub.dev/packages/build_runner ) .
0 commit comments