expo / expo

An open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.
https://docs.expo.dev
MIT License
32.92k stars 5.24k forks source link

Unable to resolve Fonts after upgrade to 33 #4626

Closed Erlix322 closed 5 years ago

Erlix322 commented 5 years ago

🐛 Bug Report

The loading of Fonts is no longer working

Environment

Windows 10

Steps to Reproduce

This is my package json dependencies "dependencies": { "@expo/samples": "2.1.1", "aws-amplify": "^1.1.28", "aws-amplify-react": "^2.3.8", "aws-amplify-react-native": "*", "axios": "^0.18.0", "buffer": "^5.2.1", "expo": "^33.0.0", "expo-font": "^5.0.1", "mobx": "^5.8.0", "mobx-react": "^5.4.3", "native-base": "^2.12.1", "react": "16.8.3", "react-native": "https://github.com/expo/react-native/archive/sdk-33.0.0.tar.gz", "react-native-elements": "^1.1.0", "react-native-markdown-renderer": "^3.2.8", "react-native-platform-touchable": "^1.1.1", "react-navigation": "^2.18.2", "react-paypal-express-checkout": "^1.0.5" }

Expected Behavior

I was expecting that Fonts are loaded from the location

Actual Behavior

but the folder exists Error: no such file or directory, scandir

p-sebastian commented 5 years ago

Its a modular import now,

expo install expo-font

then

import * as Font from 'expo-font';

juanorellana13 commented 5 years ago

Followed instructions @p-sebastian, unfortunately "no such file or directory, scandir" error persistent. Similar situation as @Erlix322, font files exist and worked with previous version of Expo-Cli.

cruzach commented 5 years ago

Hi @Erlix322 & @juanorellana13!

Can one of you provide a repro for this issue?

(Also- if you're looking for more information on the new modular imports, I'd read the SDK 33 blogpost)

juanorellana13 commented 5 years ago

Hello @cruzach, I slapped together this example application last night. Hope this helps: https://github.com/juanorellana13/hair_stylist_companion

majugurci commented 5 years ago

This is also not working for me. It worked in previous version (32.0.5).

Here is the code located in project\src\services\fontLoader.js

import * as Font from 'expo-font';

async function loadFonts() {
    await Font.loadAsync({
        Roboto: require('native-base/Fonts/Roboto.ttf'),
        Roboto_medium: require('native-base/Fonts/Roboto_medium.ttf')
    });
}

I have managed to get error message in console: ENOENT: no such file or directory, scandir 'D:\workspace\project\src\services\node_modules\native-base\Fonts'

So, it is now looking for relative paths, is it something new?

When I run it with this code it works:

import * as Font from 'expo-font';

async function loadFonts() {
    await Font.loadAsync({
        Roboto: require('../../node_modules/native-base/Fonts/Roboto.ttf'),
        Roboto_medium: require('../../node_modules/native-base/Fonts/Roboto_medium.ttf')
    });
}
cruzach commented 5 years ago

I think I'm a little confused- this works when you provide the correct path to the font. With SDK 32 you could provide:

async function loadFonts() {
    await Font.loadAsync({
        Roboto: require('native-base/Fonts/Roboto.ttf'),
        Roboto_medium: require('native-base/Fonts/Roboto_medium.ttf')
    });
}

And it would work?

juanorellana13 commented 5 years ago

@majugurci, your proposed solution worked on my example repo. I guess it is looking for relative paths now. I will need to update my own notes of this. Strange that this happened. I remember creating some test applications to mess around using the previous version of Expo and this never happened until the upgrade to 33. Once again thank you. So does that mean we need to use relative paths for additional Fonts moving forward?

load = async () => {
        await Font.loadAsync({
            Roboto: require('../../node_modules/native-base/Fonts/Roboto.ttf'),
            Roboto_medium: require('../../node_modules/native-base/Fonts/Roboto_medium.ttf'),
            ...Ionicons.font
        });
        this.setState({ ready: true });
    };
JoaoBGusmao commented 5 years ago

same here, bug I receive Asset failed MD5 integrity check. I found out that this happens when I try to load assets from outside my app folder. In my case, I have an external package with my fonts, and that's what causes the error

majugurci commented 5 years ago

@cruzach Yes, that is correct.

I thought this is how require works, if you do not specify relative path then it is looking in pre-configured directories and one of them is node_modules. Is it not so?

Also, I have seen this in native-base example app and used it for some time. Here is the link: https://github.com/GeekyAnts/NativeBase-KitchenSink/blob/CRNA/src/boot/setup.js

Erlix322 commented 5 years ago

Thanks @majugurci ! According to your tip with relative paths I did the following now.

I put all needed Fonts into a folder where the components is and imported them using es6 imports. I might migrate to the new imports for the fonts later and check if it works.

Code

import Roboto from './fonts/Roboto.ttf';
import {Font} from 'expo'
import Roboto_medium from './fonts/Roboto_medium.ttf';

export default class MyComponent extends Component {
     async componentWillMount() {
          await Font.loadAsync({
            Roboto,
            Roboto_medium
          }); 

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

Folder Structure

components
    --fonts
        --Roboto.ttf
   MyComponent.js
chrisdrackett commented 5 years ago

just ran into this as well. I've tried using the format suggested above, but without luck. For what it is worth this works correctly when the target is web (using the web beta) but does not work in native anymore.

brentvatne commented 5 years ago

@chrisdrackett - can you provide a runnable reproducible example?

chrisdrackett commented 5 years ago

@brentvatne sure, here you go:

https://github.com/chrisdrackett/expo-font-example

for me if I try and run this on iOS (yarn iOS) I get the following:

Unable to resolve "../media/font.woff" from "src/components/FontLoader.tsx"

however if I run yarn web everything is happy.

This code is taken from a project that ran for me on an older version of expo.

brentvatne commented 5 years ago

woff is not an extension supported by the packager by default. you can add it by creating metro.config.js in the root of your project and doing this:

const defaultAssetExts = require("metro-config/src/defaults/defaults").assetExts;

module.exports = {
  resolver: {
    assetExts: [
      ...defaultAssetExts,
      "woff"
    ]
  }
};

now it should load. i simplified the source code you posted and it ran fine with the following code:

import React from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';
import * as Font from 'expo-font';

const FontLoader = ({ children }) => {
  const [fontsLoaded, setFontsLoaded] = React.useState(false);

  React.useEffect(() => {
    async function loadFonts() {
      await Font.loadAsync({
        lolFont: require('./font.woff'),
      });

      setFontsLoaded(true);
    }

    loadFonts();
  }, []);

  if (!fontsLoaded) {
    return null;
  }

  return children;
};

export default function App() {
  let [count, setCount] = React.useState(0);

  return (
    <FontLoader>
      <View style={styles.container}>
        <Text style={{ fontFamily: 'lolFont' }}>
          Open up App.js to start working on your app!
        </Text>
      </View>
    </FontLoader>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
brentvatne commented 5 years ago

for your reference, here are the extensions that metro supports by default: https://github.com/facebook/metro/blob/50267d895cdd2c5102907a4fc18430d689399112/packages/metro-config/src/defaults/defaults.js#L14-L49

the reason it would work on web is that the packager used in that context is webpack and there are some different behaviors

chrisdrackett commented 5 years ago

ah, good catch. I don't remember making the move from .ttf to .woff, but we probably did it as part of the move to a universal app.

brentvatne commented 5 years ago

closing this because there isn't a reproducible example. if you have a problem loading fonts in sdk33, please create a new issue and follow the issue template along with providing a reproducible example :)

seromenho commented 5 years ago

@chrisdrackett woff format worked for you?

chrisdrackett commented 5 years ago

@seromenho for now (in development) I've gone back to .ttf but due to licensing I may just need a different way of loading fonts between web and native

RyanTG commented 5 years ago

@p-sebastian Can you clarify how to use this? import * as Font from 'expo-font';

Also, your reply makes it seems like this breakage is by design, as part of the switch to modular imports. Yet modular imports are not required in Expo 33. So, it seems like this issue shouldn’t be happening.

Some replies say that the relative paths to the fonts are wrong. I wasn’t able to fix my issue by linking directly to the fonts within node_modules, so I want to try and use the modular import method. But I’m not clear on how.

For example, if a screen uses FontAwesome, how do I import it? import FontAwesome as FontAwesome from 'expo-font'?

chrisdrackett commented 5 years ago

@RyanTG after you load the font using Font from expo (https://docs.expo.io/versions/latest/sdk/font/) you then use the font by name within the styles of a component. something like:

<Text style={{ fontFamily: "FontAwesome" }}>Text here</Text>
RyanTG commented 5 years ago

@chrisdrackett Thanks for the help. What if a screen uses two different fonts?

import * as FontAwesome from 'expo-font'
import * as MaterialIcons from 'expo-font'

That seems wrong, but I can't figure out the correct syntax.

I actually think I'm hitting a secondary issue right now (so, not appropriate for this issue), but I'll share the error anyway: Unable to resolve "react-native-vector-icons/FontAwesome" from "node_modules/react-native-elements/src/social/SocialIcon.js". Not seeing anything on the RNE forums about this. But it seems related to all the font paths suddenly breaking.

chrisdrackett commented 5 years ago

you only use import * as Font from 'expo-font'; during setup. In your component files you don't need to import anything at all. I don't have one on hand, but there should be expo examples that describe how to use Font

RyanTG commented 5 years ago

Ah great, thank you. In my project's current release we do use Font in one screen, so I'll model things after that. Overall, this still seems like a step backward in terms of clear, concise code.

brentvatne commented 5 years ago

@RyanTG - i'm not sure you're understanding this correctly. nothing changed except that if you previously used import { Font } from 'expo'; you now write import * as Font from 'expo-font';. that's it.

RyanTG commented 5 years ago

@brentvatne hmm ok. What I experienced was that after upgrading from 32 to 33, the paths to the expo vector icons are wrong. Previously import { MaterialCommunityIcons } from '@expo/vector-icons' worked fine, and now it seems to think that import is for a (relative) path within ./app and not within ./node_modules. There are quite a few other people experiencing this, as well.

ENOENT: no such file or directory, scandir '/home/ryantg/Documents/project/pbm-react/app/screens/node_modules/@expo/vector-icons/fonts'                                         
Failed building JavaScript bundle.

Perhaps I just need to start fresh with the upgrade process. Newest cli, cache cleared, etc.

brentvatne commented 5 years ago

does this happen if you create a new project? if not, do you have some custom babel config that might be causing this?

RyanTG commented 5 years ago

I don't have a custom babel config. I'll try a new project. Thanks for your time - Expo rules.

brentvatne commented 5 years ago

@RyanTG - you should delete .babelrc in your project and replace it with babel.config.js like this: https://github.com/expo/expo/blob/master/templates/expo-template-blank/babel.config.js

also you can change https://github.com/bpoore/pbm-react/blob/master/index.js to just:

import App from './app/index'
p-sebastian commented 5 years ago

@RyanTG I am using the latest Expo-33 with the typescript template. And normal destructured import didn't work for me on this version, this is why I used it like this, although it is much better this way.

first install the new module

expo install expo-font

then just import it like below

Location of fonts

./assets/fonts/*.ttf

Main Component

./src/App.tsx


import React, { useState } from 'react';
import * as Font from 'expo-font'; // this is how you import it
import { AppLoading } from 'expo';
import AppContainer from './app.routes';

export default function App() { const [isReady, setReady] = useState (false);

if (!isReady) { // this is what makes sure the fonts are ready before loading the app return ( <AppLoading startAsync={_loadAssets} // this loads the fonts onFinish={() => setReady (true)} onError={e => console.error (e)} /> ); } return (

); } // font loading function const _loadAssets = async () => { await Font.loadAsync ({ 'dank-mono': require ('../assets/fonts/DankMono-Regular.ttf'), 'dank-mono-italic': require ('../assets/fonts/DankMono-Italic.ttf'), 'fira-code-bold': require ('../assets/fonts/FiraCode-Bold.ttf') }); };

RyanTG commented 5 years ago

Thanks! I resolved my issue. I ended up loading the fonts within my index.js, as you described above, and I commented out every import { MaterialCommunityIcons } from '@expo/vector-icons' etc on each screen. This finally allowed the bundler to not fail. And that point the fonts weren't found (e.g. ReferenceError: Can't find variable: FontAwesome), and I needed to add back those imports.

And at that point I was able to figure out the exact line that had been causing the bundler to fail (because that error code was not really descriptive, and it looked to me like the vector icon paths for wrong throughout the project):

    async componentDidMount(){
        this.props.getCurrentLocation()

        await Font.loadAsync({'MaterialIcons': require('@expo/vector-icons/fonts/MaterialIcons.ttf')})
        await Font.loadAsync({'Material Icons': require('@expo/vector-icons/fonts/MaterialIcons.ttf')})
        this.setState({ materialIconsLoaded: true })
    }

which is a weird bit of code, wherein I had to explicitly get some fonts to load (and even more strangely, I had to call the font Material Icons for android, but MaterialIcons on ios - very strange, but two other devs on this project verified this weirdness). Removing the font stuff in that block resolved the issue.

thanks again.

harrisonlo commented 4 years ago

Are variable fonts supported? (i.e. font.var.ttf)

E-Viskhan commented 3 months ago

Woff/Woff2 formats are not working in Android, and, of course, there are not working in React Native. Use otf/ttf formats fonts and the name of file and Postscript Name of fonts should be same and use only letters, "_" symbol or maybe numbers(do not know exactly)!!!