Perf/images lazy loading#71170
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
It's ready for the review. |
|
@martasudol there are more conflicts now 🙈 |
|
🚧 @mountiny has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, Desktop, and Web. Happy testing! 🧪🧪
|
| function ImageSVG({src, width = '100%', height = '100%', fill, hovered = false, pressed = false, style, pointerEvents, preserveAspectRatio}: ImageSVGProps) { | ||
| if (!src) { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
@martasudol I think we should also add a null-guard in android and ios files.
| const {asset: ExpensifyAppIcon} = useMemoizedLazyAsset(() => loadExpensifyIcon('ExpensifyAppIcon')); | ||
| const {asset: Inbox} = useMemoizedLazyAsset(() => loadExpensifyIcon('Inbox')); | ||
| const {asset: MoneySearch} = useMemoizedLazyAsset(() => loadExpensifyIcon('MoneySearch')); | ||
| const {asset: Buildings} = useMemoizedLazyAsset(() => loadExpensifyIcon('Buildings')); |
There was a problem hiding this comment.
Please update this to use useMemoizedLazyExpensifyIcons here.
| const pageTitle = shouldDisplayCardDomain ? expensifyCardTitle : (cardList?.[cardID]?.nameValuePairs?.cardTitle ?? expensifyCardTitle); | ||
| const {displayName} = useCurrentUserPersonalDetails(); | ||
| const {asset: Flag} = useMemoizedLazyAsset(() => loadExpensifyIcon('Flag')); | ||
| const {asset: MoneySearch} = useMemoizedLazyAsset(() => loadExpensifyIcon('MoneySearch')); |
There was a problem hiding this comment.
Please update this to use useMemoizedLazyExpensifyIcons here.
| const {asset: Tag} = useMemoizedLazyAsset(() => loadExpensifyIcon('Tag')); | ||
| const {asset: Users} = useMemoizedLazyAsset(() => loadExpensifyIcon('Users')); | ||
| const {asset: Workflows} = useMemoizedLazyAsset(() => loadExpensifyIcon('Workflows')); | ||
|
|
There was a problem hiding this comment.
Please update this to use useMemoizedLazyExpensifyIcons here.
| function ChangeWorkspaceMenuSectionList() { | ||
| const {translate} = useLocalize(); | ||
| const styles = useThemeStyles(); | ||
| const illustrations = useMemoizedLazyIllustrations(['FolderOpen', 'Workflows'] as const); |
There was a problem hiding this comment.
We don't need to use as const for inline literal.
This comment was marked as resolved.
This comment was marked as resolved.
|
@martasudol We have some console errors and warnings. One of them is from the Error from
|
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppandroid_native_hybrid.mp4Android: mWeb Chromeandroid_chrome.mp4iOS: HybridAppios_native_hybrid.mp4iOS: mWeb Safariios_safari.mp4MacOS: Chrome / Safariweb_chrome.mp4MacOS: Desktopdesktop_app.mp4 |
|
@mountiny I believe it's expecting a PR reviewer checklist from Gonals, as per this comment. I have tried commenting with the checklist twice. |
Thanks for noticing!
|
mountiny
left a comment
There was a problem hiding this comment.
Thank you @OlimpiaZurek @martasudol @Krishna2323
Excited to see what will be the bundle size change with all the updates we have done so far
|
🚀 Deployed to staging by https://github.com/mountiny in version: 9.2.29-0 🚀
|
|
🚀 Deployed to production by https://github.com/mountiny in version: 9.2.29-5 🚀
|


Explanation of Change
Coming from #69358.
This PR demonstrates the initial implementation, focusing on workspace-related components. It shows how illustrations can be split into chunks and lazy-loaded on demand. Later PRs will extend this approach to Expensicons, general image assets, and bank/company card logos.
Before:
After:
Fixed Issues
$ #68775
PROPOSAL: https://callstack-hq.slack.com/archives/C05LX9D6E07/p1756383462406999
Tests
Open the app, switch between offline/online statuses and check if icons are loaded correctly.
Offline tests
Same as Tests.
QA Steps
Same as Tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectioncanBeMissingparam foruseOnyxtoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Nagranie.z.ekranu.2025-09-26.o.10.44.01.mov
Android: mWeb Chrome
Nagranie.z.ekranu.2025-09-26.o.10.31.51.mov
iOS: Native
Nagranie.z.ekranu.2025-09-26.o.10.09.43.mov
iOS: mWeb Safari
Nagranie.z.ekranu.2025-09-26.o.10.15.08.mov
MacOS: Chrome / Safari
Nagranie.z.ekranu.2025-09-26.o.09.33.39.mov
MacOS: Desktop
Nagranie.z.ekranu.2025-09-26.o.10.24.25.mov