Repository navigation
Support --tree-shake-icons for the web #57181
Description
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:
- 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.
- 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
- 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.
- 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
mkustermann commentedon May 15, 2020
/cc @alexmarkov @sigmundch @johnniwinther
ciriousjoker commentedon May 26, 2021
Any progress on this? Manually filtering and bundling specific icon fonts quickly becomes tedious.
guidezpl commentedon Jun 20, 2022
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.
christopherfujino commentedon Jul 19, 2022
Adding dependecy:dart as it sounds like the fix will involve new features in dart2js
kevmoo commentedon Jul 20, 2022
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.
guidezpl commentedon Jul 21, 2022
Material Symbols will be in a new, opt-in package (rather than in the framework) for this and other reasons.
2 remaining items
jacobsimionato commentedon Sep 9, 2022
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.
christopherfujino commentedon Sep 10, 2022
Notes from sync meeting:
Options:
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.
guidezpl commentedon Sep 12, 2022
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.
christopherfujino commentedon Oct 28, 2022
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
Iconclass 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
Iconclass 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 thePlatformAdaptiveIconsclass: 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.
mkustermann commentedon Nov 1, 2022
/cc @rakudrama @mraleph (remember there was a discussion about this recently at summit)
christopherfujino commentedon Nov 9, 2022
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.
irajeshh commentedon Dec 26, 2022
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-iconsStep 2: Go to
/build/app/intermediates/assets/release/mergeReleaseAssets/flutter_assets/fonts/MaterialIcons-Regular.otfStep 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.
FlorianFlatscher commentedon Feb 12, 2023
Any news on this?
kevmoo commentedon Feb 12, 2023
@FlorianFlatscher – this should "just work" at master of flutter/flutter
irajeshh commentedon Feb 15, 2023
@kevmoo I'm using this @ stabel channel
kevmoo commentedon Feb 16, 2023
This feature is not yet at stable. You can try it out at master/dev
github-actions commentedon Mar 3, 2023
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 -vand a minimal reproduction of the issue.