[SOLVED] Cannot load font from @expo/vector-icons


#1

I’ve spent a lot of time researching how fonts and images can be preloaded, etc… and I was able to load fonts and images from my assetts folder.

However I could not figure out what is the catch when fonts are (ou should) be taken from dependencies.

In the sources I’ve posted below, you can see 3 very similar approaches for preloading fonts.
Could someone clarify why so similar approaches deliver so different results?

import React from 'react';
import { Asset, Font, AppLoading } from 'expo';

import { MaterialIcons } from '@expo/vector-icons';

import * as sjs from './assets/js/scalajs-output-android.js';


export default class App extends React.Component {
  state = {
    fontsLoaded: false,
  };

  async componentWillMount() {

    //-- This call does not find MaterialIcons
    //-- await Font.loadAsync([MaterialIcons.font]);

    //-- This call complains that the promise is never fulfilled
    //-- await Font.loadAsync({
    //--   'MaterialIcons': MaterialIcons.font                     
    //-- });

    // This call works
    await Font.loadAsync({
      'MaterialIcons': require('./assets/fonts/MaterialIcons.ttf')
    });

    this.setState({ fontsLoaded: true });
  };

  render() {
    if (!this.state.fontsLoaded) {
      return <AppLoading />;
    }
    const component = sjs.drawerNavigation_root();
    return (React.createElement(component, {}));
  }
}

This is my packages.json:

{
  "name": "test2",
  "version": "0.1.0",
  "private": true,
  "main": "node_modules/expo/AppEntry.js",
  "expo": {
    "name": "test2",
    "slug": "test2",
    "sdkVersion": "22.0.2",
    "privacy": "public"
  },
  "scripts": {
    "start": "react-native start server --transformer scalajsTransformer.js"
  },
  "dependencies": {
    "expo": "^22.0.0",
    "@expo/vector-icons": "6.2.0",
    "react": "16.0.0-beta.5",
    "react-native": "https://github.com/expo/react-native/archive/sdk-22.0.2.tar.gz",
    "react-navigation": "^1.0.0-beta.17"
  },
  "devDependencies": {
    "babel-preset-react-native": "1.9.1",
    "react-test-renderer": "16.0.0-beta.5"
  }
}

#2

hello! I labeled the various styles above for convenience

  1. can you clarify what you mean by “This call does not find MaterialIcons”?
  2. you would have to do await Font.loadAsync(MaterialIcons.font); here instead. MaterialIcons.font is an object that looks like this: {'MaterialIcons': require('@expo/vector-icons/fonts/MaterialIcons.ttf')}
  3. this is the same as the fixed version of the 2nd option which i described above

#3

Hello @notbrent : thanks for the quick reply.

  1. cannot find font is explained here: https://github.com/frgomes/mobile.g8/issues/1

Your suggestion ( await Font.loadAsync(MaterialIcons.font); ) complains like item (1) above.

I’ve tried another flavor based on insider information you provided (thank you for that!), and it works.
Please find below the results of my tests:

    //-- This call does not find MaterialIcons
    //-- await Font.loadAsync([MaterialIcons.font]);

    //-- This call does not find MaterialIcons
    //-- await Font.loadAsync(MaterialIcons.font);

    //-- This call complains that the promise is never fulfilled
    //-- await Font.loadAsync({
    //--   'MaterialIcons': MaterialIcons.font
    //-- });

    //-- This works, but I don't like the idea of copying .ttf files into my project.
    //-- await Font.loadAsync({
    //--   'MaterialIcons': require('./assets/fonts/MaterialIcons.ttf')
    //-- });

    // This works as expected 
    await Font.loadAsync({
       'MaterialIcons': require('@expo/vector-icons/fonts/MaterialIcons.ttf')
    });

#4

ah, so the reason is that the font is named 'material' internally. usually people just use the icon set through the exposed MaterialIcons component.

you can see the name of the font here: https://github.com/expo/vector-icons/blob/master/MaterialIcons.js#L4


#5

I’ve seen a similar report somewhere else in the forum and a similar root cause for the issue: the internal name does not match the external name. I suppose a lot of people will still stumble on the same trap.


#6

right. we should probably change it to make the fontFamily name identical to the icon component name. could you submit a pull request for that? additionally, this fact should be added to the README


#7

It’s not very wise if I send a PR. Why not?
Because I’m not a JS developer and I do not have enough knowledge in regards to Expo codebase.

The effort I did is limited to make ScalaJS work well enough with Expo.
More info here: https://github.com/frgomes/mobile.g8/tree/expo-support


#8

I still have an issue with this and receiving the RSoD.

Is there anything i am missing? Here is my App.js in full;

import React from 'react'
import { Font, AppLoading } from 'expo'
import { MaterialIcons } from '@expo/vector-icons'
import HybridApp from './src/App'

export default class NativeApp extends React.Component {
  constructor() {
    super()
    this.state = {
      fontsAreLoaded: false
    }
  }
  async componentWillMount() {
    await Font.loadAsync({'MaterialIcons': require('@expo/vector-icons/fonts/MaterialIcons.ttf')})
    this.setState({ fontsAreLoaded: true })
  }
  render() {
    const { fontsAreLoaded } = this.state
    return !fontsAreLoaded ? <AppLoading /> : <HybridApp />
  }
}

#9

notice how we load the font in this: https://github.com/expo/new-project-template/blob/master/App.js#L32-L46