Font and asset preload and cache best practices

Hey all,

I’m wondering what the best practice is for preloading and caching app assets? I’ve read the docs on Offline Support,Preloading & Caching Assets and https://docs.expo.io/versions/latest/sdk/app-loading.html, and I’m using the suggested approaches. However, I find that my app has quite a long startup time in spite of having fairly few assets (<1 mb, 16 files)

My asset folder structure is as follows:

assets
  background
    1 .png file
  icons
    10 .png files
  pushbutton.png
  splash.png

In my app.json, I bundle all of these with "assetBundlePatterns": ["assets/**"]

My AppLoading looks like this:

<AppLoading
  startAsync={this.loadAndCacheAssets}
  onFinish={this.setReady}
  onError={this.handleLoadingError}
/>

and my loadAndCacheAssets function:

export const loadAndCacheAssets = async () => {
  // const imageAssets = cacheImages([
  //   'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png',
  //   require('./assets/images/circle.jpg'),
  // ]);

  const fontAssets = cacheFonts([
    FontAwesome.font,
    Foundation.font,
    Ionicons.font,
    SimpleLineIcons.font,
    Octicons.font,
    Entypo.font,
    EvilIcons.font,
    MaterialIcons.font,
    MaterialCommunityIcons.font,
  ]);

  await Promise.all([
    // ...imageAssets,
    ...fontAssets,
  ]);
};

const cacheImages = images => {
  return images.map(image => {
    if (typeof image === 'string') {
      return Image.prefetch(image);
    } else {
      return Asset.fromModule(image).downloadAsync();
    }
  });
};

const cacheFonts = fonts => {
  return fonts.map(font => Font.loadAsync(font));
};

I intentionally included the outcommented code for caching images, seeing as all images should be bundled with the app due to the app.json, right? Or did I misunderstand something?

Also, I’m not sure wether it’s a terrible idea to download the full font libs - does someone know how big these are, and if there’s some way to only download the icons I need?

In any case, I could understand why the above two issues could make the first app startup slow if my bundling isn’t set up right - but it continues to take around 7-10 seconds for a cold start?

Any advice would be much appreciated.

This all looks in tippity top shape. Some performance time comes from having to boot-up the js VM. I I’m not sure what yo app looks like or how big it is so all I can do is guess…
React Native docs recommend you inline bundle: Performance Overview · React Native
Before doing that I would recommend removing references to code you aren’t using (again not sure what’s going on under the hood :} )

We are also actively working on making startup faster in general - cuz waiting is a pain. I believe this would mean reworking the ios kernel in some way. @ben would know more about this. :blue_heart::blue_heart::blue_heart::blue_heart:

Hey Evan,

First, congratulations on your forums.expo.io cake day! :smile:

Thanks for getting back to me. It’s nice to know that I’ve done it correctly, but it’s a bit disappointing that there isn’t anything I can do to optimize the startup. A cold start of up towards 10 seconds is unacceptable for a modern app, and would mean that Expo isn’t viable for consumer-facing product yet. The only solution to circumvent this AFAIK is to build the first screens (login, feed/whatever else the user might land on) natively and start the JS part of the app in the background, which would be super cumbersome.

I’m not using any major modules, it’s a pretty standard setup: react navigation, redux(persist, thunk), lodash, validator, moment and some light UI helper libraries with no assets, such as keyboard-spacer, lightbox, react-native-animatable and such (no NativeBase or other heavy UI libs), so dynamic/delayed bundling/loading shouldn’t be a factor.

I’d love some insight into what you are working on in order to have a better outlook of what to expect in the future?

@jhalborg have you published this project yet? If so, can you share the URL with me? If not, can you share the source with me?

@jhalborg if you are having a 10 second startup that is an isolated issue. I took the time to measure some Expo app startups.

I have a few live apps that I haven’t really optimized (because I’m lazy), here are their cold startup times:
Sunset Cyberspace (big 3D video game): 4630ms
Pillar Valley (medium 3D video game): 4380ms
Nitro Roll (big 3D video game): 4560ms


Here are some other pure Expo apps:
Urban Dictionary: 3200ms
Hashtagger: 1900ms
Lexi: 5000ms
Nodevember: 3000ms
Spark Fiction: 3500ms
Mats in Mind: 2710ms
Hangman: 2520ms
My Games: 4430ms
My Magic Lives: 3112ms


Times are measured when the app icon is first touched on an old iPhone 7+

I’ve tried measuring the startup times more closely, and to be fair it’s closer to 5 seconds than 10 - perhaps it’s just that it feels like 10, seeing as pure native apps have closer to 1 or 0 seconds startup time. :smile:

Do you know how Hangman or Hashtagger reach the sub 2 seconds startup times? That I can live with, but 5 is still too high I think.

I’ve sent you both a link in a PM for my app slug on test env

EDIT: Just to be sure, it’s not necessary to further specify which icons of each font to grab in the cacheFonts method?

Friendly ping @bacon :slight_smile:

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.