build.yaml
file, you can configure builders to only run on some sources with generate_for
. Perhaps that helps to reduce build times already?
@simolus3 , thanks for the tip. I checked out our build.yaml
and you're right--someone since added several dependencies for packages we've installed. We need those other packages but their independent of the one I wrote.
When I run pub run builder_runner build
lots of code generation happens, including for json_serializableable
and some GraphQL packages. But when we generate files for the gen_lang
package we run pub run gen_lang:generate
and only the gen_lange files are generated and it takes a second or two. That's what I'm after. To run code generation for my package and not run all the other packages.
Below is our build.yaml. My package is specified at the bottom and called gen_keys
targets:
$default:
builders:
gql_build|schema_builder:
enabled: true
gql_build|ast_builder:
enabled: true
gql_build|data_builder:
enabled: true
options:
schema: ewp|lib/common/graphql/schema.graphql
gql_build|var_builder:
enabled: true
options:
schema: ewp|lib/common/graphql/schema.graphql
gql_build|serializer_builder:
enabled: true
options:
schema: ewp|lib/common/graphql/schema.graphql
ferry_generator|req_builder:
enabled: true
options:
schema: ewp|lib/common/graphql/schema.graphql
ewp|keys_file_builder:
enabled: true
builders:
ewp|keys_file_builder:
import: 'package:ewp/common/gen_key/builders/keys_file_builder.dart'
builder_factories: ['keysFileBuilder']
build_extensions: { ".dart": [".keys.dart"] }
auto_apply: dependents
build_to: source
ok I think I got it:
targets:
$default:
builders:
my_builder:builder:
enabled: false # disable the builder to prevent overlapping outputs error
my_package:other_target:
sources:
- data/**
It seems as though all targets are always processed so I don't need to specify anywhere which to execute?
$package$
etc). Since those can only exist in one target generally.
@jakemac53 I tried to include additional sources but it doesn't work properly. So, after any changes in assets
folder, all Builders are creating again, so if we use freezed or json_serializable, it take a lot of time. Also, if I renamed one file several times, it stoped working after 2-3 renames. So, I don't think that it's a good idea.
I found a way by using DirectoryWatcher, it looks good, but I don't know it is a good practice or not.
@jakemac53 how do u think, it it good idea to use DirectoryWatcher in the builder? I keep build
method empty because all I need it's starting my code by build_runner.
assets
, they either read from there in some indirect way or the assets aren't being cached properly for some reason. Can you post your build.yaml
?
.dart
-> .g.dart
builder and you delete a foo.dart
file, the build system should automatically delete the foo.g.dart
file as well.
DirectoryWatcher
manually, you'd also have to take care of how file changes might propagate through intermediate steps and so on. If you write a builder you can just read the assets that you depend on, write outputs only depending on them and the build system will take care of everything else.
BuildStep
apis for all file interactions
@simolus3 @jakemac53 So, build_runner works unclear to me.
If i run build_runner build
at the first time, build
method in my builder is invoking.
But if I change pubspec.yaml file and run build_runner build
again, build
method in my builder is NOT invoking.
Also, if I call findAssets(‘assets/**')
inside build
method, then build
method is invoking after changing something inside assets/**
but if I don’t call findAssets
then build
method will not be invoked after changes in assets/**
. It’s really unclear :(
So, $package$
doesn’t work properly as well. I can’t detect changes in pubspec.yaml and etc. :(
@jakemac53 @simolus3 So, I found a solution. To watch pubspec.yaml changes, we need to do this:
final pubspecAsset = await buildStep.findAssets(Glob(‘pubspec.yaml')).single;
await buildStep.digest(pubspecAsset);
digest
method lets build_runner know that we would like to subscribe the file changes. Also, we can compare digest
result with the previous digest
to know if the file was changed.
buildStep.canRead(AssetId(buildStep.inputId.package, 'pubspec.yaml'))
if you want your builder to be re-invoked after the pubspec.yaml
changes.
Yeah, basically what Simon said.
You MUST go through the build step apis for all file system access. If your builder never globs the assets
directory, then your builder can't depend on its contents, unless you were going outside the build system and directly listing it yourself, or invoking an external process which was itself listing the file system.
scratch_space
package if possible for your use case. That makes it a lot harder to do the wrong thing.
findAssets
, that will only re-run your builder if the results of the Glob changes. It will not re-run your builder if the contents of one of those files changes (because you haven't read the file).
canRead
api as Simon suggests to depend on the contents of any given asset, or you can similarly read the digest or actual file contents. In theory some day we could optimize canRead
to only re-run your builder if the visibility of the file changed, but it is unlikely (lots of builders depend on using it as a way of getting a dependency on the file contents).
.dart
files as an input (typically a compiler), it should run after code-generating builders of course. But for that ordering to work, it doesn't matter whether source_gen
has extensions defined as '.dart': ['.g.dart']
or '^lib/{{}}.dart': ['lib/generated/{{}}.g.dart']
. In both cases, the only thing relevant for ordering is that the extension ends with .dart
. You can contrive examples where this breaks, but I'll claim that as long as the extension stays the same you're in the clear.
build.yaml
to include the basic file extensions and then letting users customize that is fine.
@jakemac53 Thank you for a quick response.
Currently, we discuss the best solution here: dart-lang/build#3311
So if someone wants to vote or suggest your own solution please, join us in the discussion of the PR.
Thanks.