Repository navigation
[record_use] Migrate IconTreeShaker to package:record_use - #190225
Conversation
3806d21 to
afc7956
Compare
4864af0 to
047150c
Compare
88b4347 to
842b07d
Compare
71eca96 to
51cfbb8
Compare
51cfbb8 to
6e50967
Compare
There was a problem hiding this comment.
Code Review
This pull request migrates the icon tree-shaking mechanism from using ConstFinder to using the RecordUse metadata. It annotates IconData with @RecordUse(), updates KernelSnapshot to always generate recorded uses in AOT mode, and refactors IconTreeShaker to parse recorded uses JSON files instead of analyzing the kernel file. Review feedback suggests optimizing the empty-file check by using file.lengthSync() > 0 instead of reading the file, and strictly matching the IconData class name and library URI to prevent false positives during definition checks.
… in IconTreeShaker
Tree shaking is a compile-time concept. Deferred loading is a bundling + runtime concept. (A flutter app may use deferred loading of some UI screens. If only those UI screens need a certain font, then it would be sufficient to load the font at the time when the deferred code for those UI screens is loaded - and once the deferred UI screens actually render they are guaranteed the font and it's icons are available) A higher level tangential question: I can see that this PR changes the bespoke
(That would remove more of the bespoke logic in the flutter build system internals - e.g. invoking the C++ binary that does the font tree shaking) |
Yes
Indeed
Yes, I'd love to build them on top of data assets. I explored how we can do that in: It should just be a package, and should work also outside Flutter 👌 |
So we can combine two recordings. Use case dart2wasm + dart2js compilation fallbacks in Flutter. Conditional imports can make it so that they are not necessarily a super set of each other, they might be disjoint. So picking one to default to does not give the right semantics. Context: * flutter/flutter#190225 (comment)
| var hasNonConstant = false; | ||
|
|
||
| for (final MapEntry<DefinitionWithInstances, List<InstanceReference>> entry | ||
| in recordings.instances.entries) { |
There was a problem hiding this comment.
Nit: consider using object destructuring here
for (final MapEntry(:key, :value) in recordings.instances.entries) {| str.startsWith('package:flutter/src/widgets/icon_data.dart::IconData.'); | ||
| } | ||
|
|
||
| ({Constant? codePoint, Constant? fontFamily, Constant? fontPackage})? _extractIconDataConstants( |
There was a problem hiding this comment.
We should define a typedef for this record type. It's pretty verbose :)
| ({Constant? codePoint, Constant? fontFamily, Constant? fontPackage})? _extractIconDataConstants( | ||
| InstanceReference reference, | ||
| ) { | ||
| if (reference is InstanceConstantReference) { |
There was a problem hiding this comment.
Another opportunity for object destructuring:
if (reference case InstanceConstantReference(
instanceConstant: InstanceConstant(:final fields),
)) {
return (
codePoint: fields[_codePointFieldName],
fontFamily: fields[_fontFamilyFieldName],
fontPackage: fields[_fontPackageFieldName],
);
}| 'pubspec.yaml, or you are missing "uses-material-design: true".', | ||
| } else if (reference is InstanceCreationReference) { | ||
| final List<MaybeConstant> positional = reference.positionalArguments; | ||
| final Map<String, MaybeConstant> named = reference.namedArguments; |
There was a problem hiding this comment.
Same here:
else if (reference case InstanceCreationReference(
:final positionalArguments,
:final namedArguments,
)) {
// Use `positionalArguments` and `namedArguments` directly here
}or
else if (reference case InstanceCreationReference(
positionalArguments: final positional,
namedArguments: final named,
)) {
// Use `positional` and `named` directly here
}| /// are combined in the returned [Recordings]. | ||
| Recordings merge(Recordings other) { | ||
| final newCalls = <DefinitionWithStaticCalls, List<CallReference>>{}; | ||
| for (final MapEntry<DefinitionWithStaticCalls, List<CallReference>> entry in calls.entries) { |
There was a problem hiding this comment.
Prefer using object destructuring for MapEntrys, here and elsewhere.
| contains('Expected to find fontFamily for constant IconData with codepoint: 4660'), | ||
| ); | ||
| } | ||
| if (target.length == 2 && target[0] == 'web' && target[1] == '--wasm') { |
There was a problem hiding this comment.
if (target case ['web', '--wasm'])
|
@dcharkes fyi this increased the web side 100K in the following benchmark: https://flutter-flutter-perf.luci.app/e/?begin=1785858784&end=1786384856&keys=Xdd3fcae2aac0e95f0a61f49a23781826&num_commits=50&request_type=1&xbaroffset=2809046 I'll let you decide if that is a fair tradeoff =) |
Thanks for letting me know. I'll investigate. (Note that the web icon tree shaking was broken before and sometimes omitted icons, so I'll need to see if this is a regression, or bug fix.) |
…12420) Manual roll requested by [email protected] flutter/flutter@b766512...27b0988 2026-08-05 [email protected] reland(tool): remove redundant --enable-experiment=record-use flag (flutter/flutter#190591) 2026-08-05 [email protected] Windows: Propagate enabled accessibility state (flutter/flutter#190507) 2026-08-05 [email protected] Roll Fuchsia Test Scripts from ltbuIH9Z3T_yOuigu... to vcANVO8VIDQHasH1X... (flutter/flutter#190589) 2026-08-05 [email protected] Document frozen embedder API structs (flutter/flutter#186842) 2026-08-05 [email protected] Document super call order for State.didChangeDependencies (flutter/flutter#185945) 2026-08-05 [email protected] Move examples of `flutter/widgets` widgets out from `flutter/material` (flutter/flutter#189532) 2026-08-05 [email protected] [web] Use thread local strike caches in skwasm (flutter/flutter#190048) 2026-08-05 [email protected] doc: fix typo in see also section for PrimaryScrollController.maybeOf (flutter/flutter#190386) 2026-08-05 [email protected] Migrate the shell unit tests from legacy Dart native functions to FFI (flutter/flutter#190473) 2026-08-05 [email protected] render proxy box now defaults baseline calculation to null (flutter/flutter#190269) 2026-08-05 [email protected] Update Widgets Localizations from Translation Console (flutter/flutter#190503) 2026-08-04 [email protected] Revert: fix(tool): remove redundant --enable-experiment=record-use flag (flutter/flutter#190583) 2026-08-04 [email protected] Roll Fuchsia Test Scripts from 1frGe_KltAJKkeyPg... to ltbuIH9Z3T_yOuigu... (flutter/flutter#190561) 2026-08-04 [email protected] iOS,macOS: add tsan and ubsan support for Swift (flutter/flutter#190497) 2026-08-04 [email protected] fix: update on_message_ to nullptr after window destroy so that dart gets destroy message (flutter/flutter#185807) 2026-08-04 [email protected] [flutter_tools] Gracefully handle locked Windows files during clean (flutter/flutter#190095) 2026-08-04 [email protected] iOS,macOS: make Logger thread-safe, conform to Sendable (flutter/flutter#190488) 2026-08-04 [email protected] iOS: Eliminate use of IOSContextNoop in platform view tests (reland) (flutter/flutter#190509) 2026-08-04 [email protected] fix(tool): remove redundant --enable-experiment=record-use flag (flutter/flutter#190475) 2026-08-04 [email protected] android_hardware_smoke_test: Detect blank image failures or EGL initialization warnings and retry (flutter/flutter#190110) 2026-08-04 [email protected] Bumps text gamma on windows to match skia. (flutter/flutter#190477) 2026-08-04 [email protected] Roll Skia from 48b58ee222f1 to a8583a0a2c11 (2 revisions) (flutter/flutter#190537) 2026-08-04 [email protected] [tool][web] Intercept dart2wasm errors & append JS migration footers (flutter/flutter#190476) 2026-08-04 [email protected] [record_use] Migrate IconTreeShaker to `package:record_use` (flutter/flutter#190225) 2026-08-04 [email protected] Handle unexpected exceptions during Azure metadata detection (flutter/flutter#189457) 2026-08-04 [email protected] Fix merge conflict from flutter/flutter#190369 (flutter/flutter#190544) 2026-08-04 [email protected] Prepare device support symbols (flutter/flutter#190369) 2026-08-04 [email protected] Roll Packages from ac87e65 to 3498b9d (1 revision) (flutter/flutter#190532) 2026-08-04 [email protected] Roll Skia from a08d918ebd6a to 48b58ee222f1 (11 revisions) (flutter/flutter#190527) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
|
@gaaclarke This is a funny one: The Cupertino icons were retaining 7 icons in the previous implementation, and 0 icons in the new implementation. Now with 0 icons retained, The Flutter icon tree shaker does not know if some asset is an icon font or a normal font (that should be retained). So it decided to retain the full font. 🙈 😄 So, I think we have to specify if something is an icon font or not. |
Migrates
IconTreeShakerfromconst_findertopackage:record_use.Using the Dart compiler feature record use gives us the ability to record all constants reliably:
Should fix:
Interesting implementation details:
Artifact.constFinderfor g3 compatibility. (We can clean this up after we migrate g3.)Interesting roll details:
Testing: