-
Notifications
You must be signed in to change notification settings - Fork 24.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make all React Native apps start 12% faster #49449
base: main
Are you sure you want to change the base?
Conversation
LGTM |
Iirc, there are a set of compressed assets in APKs that should be uncompressed on disk for fast app starts. The bundle is one of them. Nice find. Is there a middle ground though rather than making apks all bigger? I believe in the FB app we have the bundle compressed in the apk and then on first launch we uncompressed it on disk. That makes all subsequent launches fast. Is that a reasonable approach here? |
How would that be implemented? As in, added native code that manually uncompresses the bundle on first launch, writes the uncompressed data to disk (caches?) and then uses that for future launches? Or can you overwrite the existing compressed resource? |
Yep, exactly like that. 🙂 I'm not sure how the ota clients like expo-updates work but you'd want to do that when the updates are downloaded too |
I think such a change would require significantly more effort - and I'm honestly not sure if it's worth the effort. Download size is roughly the same with my PR, because Google Play compresses the .apk again, so the .bundle is compressed on their servers. With your change, the uncompression is just delayed after the first launch, instead of before. Not sure if that really makes sense for the added complexity? Especially if you consider that this will be native code and could throw/crash. |
Btw for everyone else; you can pull in this change in your apps already by simply setting android {
+ androidResources {
+ noCompress += ["bundle"]
+ }
} |
I loved how you gave credit for all the team, keep the good work! |
Summary:
Okay the title is a bit clickbaity, but this is actually true. (on Android)
We (Janic, Szymon, Ruby and Me) discovered something interesting. React Native uses
mmap
for mapping the JS bundle to RAM, to avoid having to load the entire thing instantly at app startup.Ruby doubted that this was true - so we investigated.
Apparently on Android, resources are compressed. And if the JS bundle is stored compressed, it has to be uncompressed before it can be loaded into RAM, hence not allowing it to be mmapp'ed! (see
_CompressedAsset::getBuffer
)So with this PR, we now add
.bundle
files tonoCompress
in the react-native gradle plugin, which disables compression for the JS bundle.In our tests, this improved TTI by 400ms!! (or 12%) 🤯🚀
NOTE: Yes, the .apk will now be bigger. But; Google Play compresses it anyways, so the download size of your .apk will likely not increase by much. It will be bigger on disk though.
Changelog:
[ANDROID] [CHANGED] Disable bundle compression to improve startup time
Test Plan:
1. Verify compression is disabled
Build two apps, one with this patch and one without. When I did this using the RN community template, the one without this patch was 47,6 MB, and the one with this patch was 48 MB in size. So the .apk got bigger, which is what we expected
2. Verify app startup is faster
Use tools like react-native-performance or custom markers to measure TTI. In our tests, we shaved off 400ms from the startup time, which was about 12%. (on a low-end Android device)