expo icon indicating copy to clipboard operation
expo copied to clipboard

Fonts don't load reliably with expo-fonts + @expo-google-fonts

Open nabn opened this issue 2 years ago • 9 comments

Minimal reproducible example

https://github.com/nabn/expo-font-config-plugin-issue

Summary

Loading google fonts using expo-font config plugin + @expo-google-fonts doesn't seem to work. Dynamic loading using useFonts intermittently works.

Steps to reproduce

The with-router-tailwind template is used here, but problem exists in the blank templte too.

  • create repo: bun create-expo-app -e with-router-tailwind
  • add dev client: bunx expo install expo-dev-client
  • add font lib & a google font: bunx expo install expo-font @expo-google-fonts/dm-serif-display
  • configure the config plugin
 plugins: [
  [
    "expo-font",
    {
      "fonts": [
            "node_modules/@expo-google-fonts/dm-serif-display/DMSerifDisplay_400Regular.ttf",
            "node_modules/@expo-google-fonts/dm-serif-display/DMSerifDisplay_400Regular_Italic.ttf"
      ]
    }
  ] 
 ] 
  • use in app:
            <Text
              style={{
                fontFamily: "DMSerifDisplay_400Regular",
                fontSize: 30,
              }}
            >
              DM Serif Display
            </Text>
            <Text
              style={{
                fontFamily: "DMSerifDisplay_400Regular_Italic",
                fontSize: 30,
              }}
            >
              DM Serif Display Italic
            </Text>
  • build and run: bunx expo run:ios

Expected Fonts are applied to text Actual Fonts are not applied.

https://github.com/expo/expo/assets/1693287/9e25acb8-82b7-44c6-b5e0-bf7d04b8f4eb

Environment


  expo-env-info 1.2.0 environment info:
    System:
      OS: macOS 14.2.1
      Shell: 5.9 - /bin/zsh
    Binaries:
      Node: 18.19.0 - ~/.local/share/mise/installs/node/18/bin/node
      Yarn: 1.22.21 - ~/.bun/bin/yarn
      npm: 10.2.3 - ~/.local/share/mise/installs/node/18/bin/npm
      Watchman: 2023.12.04.00 - /opt/homebrew/bin/watchman
    Managers:
      CocoaPods: 1.14.3 - /opt/homebrew/bin/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 23.2, iOS 17.2, macOS 14.2, tvOS 17.2, visionOS 1.0, watchOS 10.2
    IDEs:
      Android Studio: 2023.1 AI-231.9392.1.2311.11255304
      Xcode: 15.2/15C500b - /usr/bin/xcodebuild
    npmPackages:
      expo: ^50.0.1 => 50.0.2 
      expo-router: ~3.4.1 => 3.4.3 
      react: 18.2.0 => 18.2.0 
      react-dom: 18.2.0 => 18.2.0 
      react-native: 0.73.2 => 0.73.2 
      react-native-web: ~0.19.6 => 0.19.10 
    Expo Workflow: managed

nabn avatar Jan 20 '24 02:01 nabn

Currently, we are unable to make the new embedded font option (via the expo-font plugin) work at all. Following the instructions for using a font from @expo-google-fonts results in none of them being available within the app when using Expo Go. Errors like the following are thrown:

fontFamily "Montserrat_400Regular" is not a system font and has not been loaded through expo-font.

It works fine using the existing async loading via useFonts.

carbonatedcoder avatar Jan 23 '24 20:01 carbonatedcoder

Thank you for filing this issue! This comment acknowledges we believe this may be a bug and there’s enough information to investigate it. However, we can’t promise any sort of timeline for resolution. We prioritize issues based on severity, breadth of impact, and alignment with our roadmap. If you’d like to help move it more quickly, you can continue to investigate it more deeply and/or you can open a pull request that fixes the cause.

expo-bot avatar Jan 26 '24 22:01 expo-bot

@amandeepmittal - it looks like we might need to improve documentation on how to use the expo-font config plugin with google fonts.

I suspect what is happening in this case is that the font name is not actually the same name as the file. note this caveat:

Create a new native build, and you can now use the font in your project with the fontFamily style prop. On Android, the font family name will be the name of the font file without the extension. On iOS, the font family name will be read from the font file itself. We recommend naming the font file the same as the font family so the family name is consistent on both platforms. For example, if you have a font family named "Inter-Black" and name the file Inter-Black.otf, then the font family name will be Inter-Black on both Android and iOS.

(source)

brentvatne avatar Jan 26 '24 22:01 brentvatne

Wouldn't the font not load at all if the name wasn't right? In the recording, dynamically loading the font is working.

nabn avatar Jan 26 '24 22:01 nabn

I'm seeing the same issue on iOS, but on Android it does work.

In the local android folder (after removing and executing npm run android) I can see the ttf files in /app/src/main/assets/fonts, and when I run the app I see them rendered correctly.

In the local ios folder I cannot find the fonts, so they do not appear to have been copied to the native project. I also don't find any reference to them in the ios/Info.plist file (again I deleted the folder and ran npm run ios to rebuild the native app locally).

steveliles avatar Feb 05 '24 15:02 steveliles

OK, I've got a step further ...

The example path in the docs is node_modules/@expo-google-fonts/inter/Inter_100Thin.ttf which works for the Android build but not for iOS.

I modified the path to be ./node_modules/@expo-google-fonts/inter/Inter_100Thin.ttf (note the "./" at the front!) and now I can see the fonts in the Resources in xcode and referenced in Info.plist. Unfortunately I still can't get the fonts to render 😅

steveliles avatar Feb 05 '24 15:02 steveliles

OK, finally I have it working on both iOS and Android.

For me the keys to making it work were:

  1. Make sure the path starts with "./", for example "./node_modules/@expo-google-fonts/inter/Inter_400Regular.ttf"
  2. On Android, the font name is the same as the file name (ie., "Inter_400Regular")
  3. On iOS, the font name is name-style (ie., "Inter-Regular").

If you want to confirm what fonts are available in your build you can add the following objectiveC code to your AppDelegate.mm file before the return statement in didFinishLaunchingWithOptions:

// Get the sorted array of font family names
  NSArray *familyNames = [[UIFont familyNames] sortedArrayUsingSelector:@selector(compare:)];
  // Iterate over each family name
  for (NSString *family in familyNames) {
      // Get font names for the current family
      NSArray *fontNames = [UIFont fontNamesForFamilyName:family];
      // Print out the family and font names
      NSLog(@"Family: %@ Font names: %@", family, fontNames);
  }

... which prints e.g.:

Family: Inter Font names: (
"Inter-Regular",
"Inter-SemiBold"
)

Now I just need to make it work on web and I'll be golden 😄

steveliles avatar Feb 05 '24 16:02 steveliles

Final note, I think:

On web I've gone back to the "dynamic" loading approach, since there's no native app to embed the font in anyways. There the font name is the same as Android, so I'm just switching on the platform at the point where I set up my theme:

  fonts: {
    body: Platform.OS === "ios" ? "Inter-Regular" : "Inter_400Regular",
    heading: Platform.OS === "ios" ? "Syne-Regular" : "Syne_400Regular"
  }

steveliles avatar Feb 05 '24 16:02 steveliles

We figured that the font on iOS won't work the same way as on Android (by calling the font file name) if the font has multiple weights. In that case, we suggest using Platform such as:

<Text
  style={{
    fontFamily: Platform.select({
      android: 'Inter_100Thin',
      ios: 'Inter-Thin',
    })
  }}>
  Inter Bold
</Text>

Similar to what @steveliles suggested.

Also, updating our documentation for now until we improve the way of handling fonts on iOS: https://github.com/expo/expo/pull/27023/files

amandeepmittal avatar Feb 09 '24 18:02 amandeepmittal

This still seems to be a problem, I can't use a font in the project via app.json following @steveliles' steps. The problem happens with fonts downloaded in the assets folder or with expo-google-fonts. I'm using Expo Go on an Android and I get the error reported by @carbonatedcoder

I cleared the Expo Go cache and it still doesn't work

Amystherdam avatar Jun 28 '24 09:06 Amystherdam

@Amystherdam, using the config plugin method using app config file doesn't work with Expo Go. You'll have to create a development build. We're in the process of updating the Fonts guide in the documentation to add more clarification about it. For a preview of the updated docs, see this: http://docs.expo.dev-pr-29903.s3-website-us-east-1.amazonaws.com/develop/user-interface/fonts/#with-expo-font-config-plugin

amandeepmittal avatar Jun 28 '24 11:06 amandeepmittal

@Amystherdam, using the config plugin method using app config file doesn't work with Expo Go. You'll have to create a development build. We're in the process of updating the Fonts guide in the documentation to add more clarification about it. For a preview of the updated docs, see this: http://docs.expo.dev-pr-29903.s3-website-us-east-1.amazonaws.com/develop/user-interface/fonts/#with-expo-font-config-plugin

Link is broken

jeremykanso avatar Jul 02 '24 13:07 jeremykanso

@jeremykanso, we published it a few days back: https://docs.expo.dev/develop/user-interface/fonts/#with-expo-font-config-plugin

amandeepmittal avatar Jul 02 '24 13:07 amandeepmittal