Skip to content

Support --tree-shake-icons for the web #57181

Closed

Description

@jonahwilliams

Currently --tree-shake-icons is on by default for mobile & desktop and disabled for the web.

Background

--tree-shake-icons uses the const_finder binary to parse the tree-shaken kernel file produced by frontend_server/TFA before it is fed to gen_snapshot for release builds. This kernel file should contain const references to all IconData used within an application. By collecting the set of code points and font families, we can thin the set of bundled fonts.

Problem

Unlike mobile/desktop, web release builds do not use the frontend_server or gen_snapshot, instead the entire process is handled by dart2s, from source to JavaScript. While dart2js supports tree-shaking as well, it never surfaces the tree-shaken kernel from the build process so it can be parsed by const finder. Initially it seemed like we could run with --cfe-only on dart2js, but this produces an un-tree-shaken kernel file, meaning it likely contains many more icons than are actually used.

Solutions

A few possible solutions were discussed, and some we dismissed:

  1. Use a frontend_server generated kernel file with TFA applied.

It's not clear if this would actually work, since the VM and dart2js platforms have different entrypoints, which could lead to different code being retained. A more trivial case would be something like a conditional import which contained different icons in vm/javascript branches. It would also require two almost identical compilations.

  1. Add dart2js kernel target to frontend_server

This is a less hacky version of (1). If we use the right kernel target and platform, then in theory we remove some of the obvious cases where tree shaking is wrong. This still leaves the possibility that there are non-trivial edge cases where dart2js tree-shaking and TFA tree-shaking differ. I haven't yet proven to myself this is an issue

  1. Teach dart2js to TFA

This seems like it would be a rather intrusive change to the compilers, and not clear that it would actually be better. Any decision to use TFA in dart2js would need to be made by the Dart web compilers team.

  1. Teach dart2js to write tree-shaken kernel to file

According to discussion with the Dart web compilers team, this doesn't really exist in dart2js today .

Activity

  1. mkustermann commented on May 15, 2020

    @mkustermann
    Member
  2. added
    platform-webWeb applications specifically
    c: new featureNothing broken; request for a new capability
    toolAffects the "flutter" command-line tool. See also t: labels.
    on Dec 1, 2020
  3. added
    P3Issues that are less important to the Flutter project
    on Dec 3, 2020
  4. ciriousjoker commented on May 26, 2021

    @ciriousjoker

    Any progress on this? Manually filtering and bundling specific icon fonts quickly becomes tedious.

  5. added
    P1High-priority issues at the top of the work list
    and removed
    P3Issues that are less important to the Flutter project
    on Jun 20, 2022
  6. guidezpl commented on Jun 20, 2022

    @guidezpl
    Member

    Raising the priority as this will become blocking in the coming months as Material Symbols (Material Icons' replacement) is introduced. Material Symbols will be delivered in 3 variable font files totalling 15MB. Material Icons currently total 1.6MB.

  7. christopherfujino commented on Jul 19, 2022

    @christopherfujino
    Contributor

    Adding dependecy:dart as it sounds like the fix will involve new features in dart2js

  8. kevmoo commented on Jul 20, 2022

    @kevmoo
    Contributor

    Is this going to affect current users who just upgrade to the next stable flutter release? Is this going to be something folks opt into?

    This is a brand new request for dart2js.

  9. guidezpl commented on Jul 21, 2022

    @guidezpl
    Member

    Is this going to affect current users who just upgrade to the next stable flutter release? Is this going to be something folks opt into?

    This is a brand new request for dart2js.

    Material Symbols will be in a new, opt-in package (rather than in the framework) for this and other reasons.

  10. 2 remaining items

  11. jacobsimionato commented on Sep 9, 2022

    @jacobsimionato
    Contributor

    Even though Material Symbols is opt-in, I think this bug is still important because I suspect many apps would consider Material Symbols unusable on Web at ~5 MB minimum cost. Also, stripping out the majority of the existing 1.6MB cost of loading icons is maybe the lowest hanging fruit of all the potential binary size / cold page load optimizations that we could do.

  12. christopherfujino commented on Sep 10, 2022

    @christopherfujino
    Contributor

    Notes from sync meeting:

    Options:

    1. Use TFA for dart2js - many challenges here, mainly in that the analysis is not designed to consider JSInterop, so it's unsound out of the box
    2. Exporting a tree-shaking .dill from dart2js that can later be consumed to tree-shake icons. This is doable, but not currently supported out of the box. Concerns are that the compiler currently relies on the kernel tree not being mutated to preserve consistency of the data it stores next to the original .dill
    3. Exporting used symbols directly - rather than the tree-shaken .dill, just emit the tree-shaken list of constants. This may be simpler to do, but made us realize a fourth option:
    4. Improve current const-finder - update the current algorithm that identifies symbols to ignore declarations and only include actually used symbols. Two possible implementations of this:
      a. We could try to distinguish between "use" and "declaration". This would be the most robust approach and work out of the box with the old and new google material symbols
      b. We could have an allowlist of libraries whose constants can be ignored. Then include all libraries that currently just declare constants for the purpose of providing an API, but not the uses from anywhere else in the program.
  13. guidezpl commented on Sep 12, 2022

    @guidezpl
    Member

    Even though Material Symbols is opt-in, I think this bug is still important because I suspect many apps would consider Material Symbols unusable on Web at ~5 MB minimum cost. Also, stripping out the majority of the existing 1.6MB cost of loading icons is maybe the lowest hanging fruit of all the potential binary size / cold page load optimizations that we could do.

    Agreed. As I noted in a separate issue, MaterialIcons-Regular.otf, is now 1.6MB and 410KB compressed,
    CupertinoIcons.ttf, is 283KB and 110KB compressed. This change would shave 500KB off nearly every Flutter web app, and would work eqaully as well for third party icon packages.

  14. christopherfujino commented on Oct 28, 2022

    @christopherfujino
    Contributor

    Status update on this one:

    Approach 4a above did not work as in the compiled dill use and declaration both appear as ConstantInstanceReference.

    However, by using 4b, and ignoring static references within the Icon class for the initial counter app, I was able to tree-shake 8586 out of 9900 (86.7%).

    This app actually used 6 icons, so for mobile builds 9894 out of 9900 are tree shaken (99.9%).

    So in summary, with the web dill file, by ignoring the static constant references inside the Icon class and then retaining the rest of the constant references, we will be able to tree-shake some of the icons, although there will still be some retained icons not used in the final build that may appear in the code (many of them in the getters of the PlatformAdaptiveIcons class: https://raw.githubusercontent.com/flutter/flutter/master/packages/flutter/lib/src/material/icons.dart) but are not actually reachable from main().

    I am going to move ahead with this approach.

  15. mkustermann commented on Nov 1, 2022

    @mkustermann
    Member

    /cc @rakudrama @mraleph (remember there was a discussion about this recently at summit)

  16. christopherfujino commented on Nov 9, 2022

    @christopherfujino
    Contributor

    The engine side PR is ready for review: flutter-team-archive/engine#37257. This will require a follow-up framework PR to enable in the tool, and then once it rolls to g3 will need a build rule follow-up.

  17. irajeshh commented on Dec 26, 2022

    @irajeshh

    For those who are looking for a quick fix can try this approach.

    Step 1: Release an apk file with tree shake by using flutter build apk --release --tree-shake-icons
    Step 2: Go to /build/app/intermediates/assets/release/mergeReleaseAssets/flutter_assets/fonts/MaterialIcons-Regular.otf
    Step 3: Make sure it's size is in KBs
    Step 4: Copy that file and keep it on your desktop
    Step 5: Build your web app and replace the large file web/assets/fonts/MaterialIcons-Regular.otf

    _This droped my icon size from 1.6MB to 2KB
    I used only 10 icons in the whole project

    Tips: For a quick action, try to automate this process using makefile

    Hope this helps someone.

  18. FlorianFlatscher commented on Feb 12, 2023

    @FlorianFlatscher

    Any news on this?

  19. kevmoo commented on Feb 12, 2023

    @kevmoo
    Contributor

    @FlorianFlatscher – this should "just work" at master of flutter/flutter

  20. irajeshh commented on Feb 15, 2023

    @irajeshh

    @kevmoo I'm using this @ stabel channel

  21. kevmoo commented on Feb 16, 2023

    @kevmoo
    Contributor

    @kevmoo I'm using this @ stable channel

    This feature is not yet at stable. You can try it out at master/dev

  22. github-actions commented on Mar 3, 2023

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  23. locked as resolved and limited conversation to collaborators on Mar 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

P2Important issues not at the top of the work listc: new featureNothing broken; request for a new capabilitydependency: dartDart team may need to help usengineflutter/engine related. See also e: labels.platform-webWeb applications specificallytoolAffects the "flutter" command-line tool. See also t: labels.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions