Skip to content

[flutter_tools] Allow asset transformers to register additional input dependencies for hot reload #187051

Description

@bdero

Use case

Asset transformers (docs) run a Dart package over one declared asset file. They have no way to tell flutter_tools about other files they read while transforming. So if a transformer reads file B while transforming declared asset A, editing B does not retrigger the transform. During flutter run the output stays stale until you touch A itself.

This breaks hot reload for any transformer that reads more than its single input. Examples:

  • A transformer that compiles a shader bundle from a manifest: the manifest lists several shader files, and those shaders #include more files. None of the referenced files are watched.
  • Any compiler-style transformer that follows imports or includes.

The user-visible result is confusing. You edit a referenced file, save, and nothing happens. You then have to edit the top-level declared asset (even a whitespace change) before the update shows up.

Today flutter_tools invokes a transformer as a subprocess with --input, --output, and any args declared in pubspec (packages/flutter_tools/lib/src/build_system/tools/asset_transformer.dart:114-120). There is no channel for the transformer to report which other files it read, so the dev loop only notices a change when the declared asset's own bytes change.

Alternatives considered: build hooks already have first-class dependency tracking (the hook reports a dependencies set), so the shader bundle case can be solved there. But build hooks are heavier (they require a hook/build.dart), and asset transformers are the natural lightweight, per-asset, composable option. This cannot be solved by a package on pub.dev, because the missing piece is in flutter_tools' own transformer invocation and file-watch loop.

Proposal

Let the transformer package report the files it read, and have flutter_tools watch them. The transformer is the only thing that knows its real inputs (the manifest entries it followed, the headers it included), so it produces the dependency list. flutter_tools only supplies a destination and consumes the result:

  1. flutter_tools passes a --depfile=<path> flag to the transformer subprocess. This is a write destination, not data: it tells the transformer where to put its dependency list.
  2. The transformer writes that file, listing every file it read (the declared asset plus anything it pulled in). A transformer that wraps a compiler can forward this straight through. impellerc, for example, already emits exactly this file ([ImpellerC] Write a depfile when --shader-bundle is in use #186341, Compiler::CreateDepfileContents).
  3. After a successful transform, flutter_tools reads the depfile and adds the listed files to the dev-loop watch set, so editing any of them retriggers the transform.

The format is the trivial single-line Ninja form <outputs>: <input1> <input2> ..., and flutter_tools already has a Dart parser for it (DepfileService.parse in build_system/depfile.dart), which it already uses to consume depfiles emitted by other separate-process compilers such as the Dart frontend server and dart2js. So no new parser or format is introduced; this reuses the dependency format the tool already speaks.

Transformers that do not write a depfile keep today's behavior, so this is backward compatible.

Today's asset watch set is effectively static (one entry per declared asset). To watch transformer-reported dependencies it needs to become dynamic. This is the same requirement called out in #186343 for tracking FragmentProgram #include headers, so one change can cover both.

Related

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work lista: assetsPackaging, accessing, or using assetsc: new featureNothing broken; request for a new capabilityc: proposalA detailed proposal for a change to Flutterteam-toolOwned by Flutter Tool teamtoolAffects the "flutter" command-line tool. See also t: labels.triaged-toolTriaged by Flutter Tool team

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions