Skip to content

Speed up transforming assets #168629

Open
Open

Description

@Albert221

Hey!

In our project, we have a Design System package with many many icons, the SVG files. We wanted to use the vector_graphics_compiler to transform them into compiled form and save on SVG parsing on the device, but there is one problem.

The asset transformation happens for every flutter run for every asset. It's not cached in the build/ directory or anything like that. Transforming them once takes a good 5-10 minutes (on a not-bad M1 Pro MacBook). Well, that's the cost of this transformation, sure. But if the assets were cached, and e.g. their checksum checked first if they're not already transformed, it would save this time on hot-reloads, consequent builds/runs, and also we could put this cache directory under cache on CI/CD. Right now it's unusable with asset transformers.

The flutter_tool also spawns a big amount of processes to run on each asset. Maybe that could be optimized somehow to run as many as the machine's CPU has or something along these lines, if that could help the performance. The other solution would be to support transforming whole directories (which we too can pass in assets in pubspec, not only files one by one), so that the flutter_tool would spawn one process per asset definition and not file, hence saving at least on spinning-up the Dart executable and the script. That would of course also require a change of the specification of executables for transformers and a change in vector_graphics_compiler package. Just thinking out loud.

Image

Thanks

Flutter 3.29.3 • channel stable • https://github.com/flutter/flutter.git
Framework • revision ea121f8859 (4 weeks ago) • 2025-04-11 19:10:07 +0000
Engine • revision cf56914b32
Tools • Dart 3.7.2 • DevTools 2.42.3

Activity

  1. Albert221 commented on May 10, 2025

    @Albert221
    ContributorAuthor

    cc @andrewkolos, as I'm aware you're the one behind the transformers (thanks for the work on them!)

  2. added
    in triagePresently being triaged by the triage team
    toolAffects the "flutter" command-line tool. See also t: labels.
    a: assetsPackaging, accessing, or using assets
    team-toolOwned by Flutter Tool team
    and removed
    in triagePresently being triaged by the triage team
    on May 12, 2025
  3. jonahwilliams commented on May 13, 2025

    @jonahwilliams
    Contributor

    There is caching for the generated assets, but If I remember the way it works is that the entire bundle is cached as one unit. So its possible that small changes are invalidating it.

    That said, I've found that its often simpler to make the process faster than it is to get an effective caching strategy. The first thing I'd do is check to make sure that we're limiting the compilation process to something like half of available concurrency, then make sure that we're using compiled dart snapshots instead of running from source.

    If both of those are true, i'd look at more finely grained caching. Its possible that may not be much of a win - I'd expect that individually each vector graphic asset is only a bit slower (10x) to compile than reading the file and hashing it.

  4. jonahwilliams commented on May 13, 2025

    @jonahwilliams
    Contributor

    From checking it looks like we're using a max concurrency of 64, which is probably way too high. That number was based on only doing copying during asset transformation, we need to use a smaller limit for process execution.

  5. jonahwilliams commented on May 13, 2025

    @jonahwilliams
    Contributor
  6. Albert221 commented on May 16, 2025

    @Albert221
    ContributorAuthor

    With this addition, the asset transformation took 10 minutes (whole flutter run took 680,563ms). And my CPU usage was at 60%, and not 100%. Fans didn't even turn on :)

    Without this change, the asset transformation took less than 9 minutes (8:51; whole flutter run took 565,477ms).

    Both time measurements were after flutter clean, running flutter run and Cmd+C right when I started seeing in verbose output it started to asset transform, then once again flutter run that I measured.

    So looks like a pool of 4 transformers is making it longer

  7. andrewkolos commented on May 16, 2025

    @andrewkolos
    Contributor

    If I recall correctly, implementing caching for transformers would require a way to check whether the package doing the transformation has changed since the last build. Said another way, if a user uses a package as a transformer and they modify that package between builds1, how do we make sure that the asset is re-transformed?

    Perhaps we could calculate a checksum of the transformer package's directory? This would definitely not work for some edge cases2 but should work fine in the vast majority of scenarios.

    Footnotes

    1. This scenario seems unlikely but could be relevant in the case that a local path package is being used as a transformer (e.g. in a monorepo project) ↩

    2. Consider a hypothetical transformer that depends on machine state or some other directory, etc. ↩

  8. matanlurey commented on May 23, 2025

    @matanlurey
    Contributor

    I think it would be reasonable to:

    • Reduce the pool to 50% of CPUs (@jonahwilliams's suggestion)
    • Ensure the Dart snapshots are pre-compiled (they are run from source today using dart run)

    ... before investing in any (expensive to get right/support) caching strategies.

  9. self-assigned this
    on May 23, 2025
  10. added
    P3Issues that are less important to the Flutter project
    triaged-toolTriaged by Flutter Tool team
    on May 23, 2025
  11. changed the title [-][asset_transformers] Cache transformed assets[/-] [+]Speed up transforming assets[/+] on May 23, 2025
  12. matanlurey commented on May 23, 2025

    @matanlurey
    Contributor

    @Albert221 Would you mind giving #169386 a shot? It should use 1/2 the CPUs - which might be higher than 4 for your tests.

  13. davidmorgan commented on May 30, 2025

    @davidmorgan
    Contributor

    If I recall correctly, implementing caching for transformers would require a way to check whether the package doing the transformation has changed since the last build. Said another way, if a user uses a package as a transformer and they modify that package between builds1, how do we make sure that the asset is re-transformed?

    Perhaps we could calculate a checksum of the transformer package's directory? This would definitely not work for some edge cases2 but should work fine in the vast majority of scenarios.

    build_runner does exactly this: caching/invalidation over the Dart source code that is doing the transformation and the input files.

    But, it does not today support running multiple processes. So it would be able to do the invalidation/caching but you'd get much lower throughput.

    Scaling up to multiple processes according to what's available on the machine is exactly something I want it to be able to do. So, perhaps it will be a good option at some point.

    Filed dart-lang/build#4023 to look into it ... but not soon ... maybe later this year / some time next year :) ... could push that a bit sooner if there is particular interest from your side.

  14. matanlurey commented on May 30, 2025

    @matanlurey
    Contributor

    Filed dart-lang/build#4023 to look into it ... but not soon ... maybe later this year / some time next year :) ... could push that a bit sooner if there is particular interest from your side.

    @davidmorgan Thanks! To be clear, however confusing this is is - asset transformers shares no code with/does not use build.

  15. davidmorgan commented on Jun 2, 2025

    @davidmorgan
    Contributor

    Filed dart-lang/build#4023 to look into it ... but not soon ... maybe later this year / some time next year :) ... could push that a bit sooner if there is particular interest from your side.

    @davidmorgan Thanks! To be clear, however confusing this is is - asset transformers shares no code with/does not use build.

    I know :) sorry, I should have been clearer: the reason I mention build is because it already does one of the things Jonah+Andrew were discussing: it can determine if your transformer source changed. So instead of writing new code to do that, you could just use build. But, there are probably reasons today why it's not a fit. That's potentially good for me, as it gives me a list of things it would be useful to support, and I'm looking for things that would be useful to add/improve in build :)

  16. mosuem commented on Jun 2, 2025

    @mosuem
    Contributor

    @Albert221 We are currently in the process of shipping hooks for data assets to Flutter - this is experimental for now, but the intention is to replace asset transformers with this more general mechanism.

    So in the (hopefully near) future, you should be able to use a hook/build.dart file which will do the work for you, including caching and such, and of course using only one "run" thus eliminating performance issues.

  17. removed their assignment
    on Jun 2, 2025
  18. vm-px commented on Oct 8, 2026

    @vm-px

    Additional data point from Windows (Flutter 3.44.8): with 181 SVGs using the vector_graphics_compiler transformer, flutter widget-preview start (and any web build) drives memory usage to 70–90% of 32 GB and freezes the machine. Web asset bundling in bundle_builder.dart runs transformations through Pool(64), so up to 64 dart run vector_graphics_compiler processes run at once, while the native build target (build_system/targets/assets.dart) limits it to numberOfProcessors ~/ 2. Concurrent runs also fail on Windows with "file is used by another process" when reading the compiler snapshot from .dart_tool/pub/bin. Applying the same CPU-based limit to bundle_builder.dart would already make web builds and widget previews usable.

    PR #169386 applied the CPU-based limit only to build_system/targets/assets.dart; bundle_builder.dart (web builds, widget previews) still uses Pool(64)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projecta: assetsPackaging, accessing, or using assetsteam-toolOwned by Flutter Tool teamtoolAffects the "flutter" command-line tool. See also t: labels.triaged-toolTriaged by Flutter Tool team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions