expo icon indicating copy to clipboard operation
expo copied to clipboard

[SDK50] Load custom fonts with expo-font

Open TomCorvus opened this issue 1 year ago • 15 comments

Minimal reproducible example

https://github.com/TomCorvus/ExpoMonorepo

Summary

Hi,

I would like to know what is the good behavior to use expo-font since SDK50 in bare workflow? I'm using useFont hook with requires which it usually worked on SDK49 but fonts don't load anymore since SDK50 and I have this error: [Error: Module "1" is missing from the asset registry]

I tried to add the fonts in Xcode ressources but the only font I can load successfully is my custom icons font from Icomoon generator called by createIconSetFromIcoMoon from @expo/vector-icons

But I don't know if we need to use useFont AND add fonts in Xcode ressources or use one of both options. Both of these options don't work for me btw.

I don't see any issue about this, so I don't know if it is a bug or I missed something.

I'm working on a monorepo. The app entry is in another folder. The minimal reproducible example is representative of my environment

Thanks for your replies and help.

Environment

  expo-env-info 1.2.0 environment info:
    System:
      OS: macOS 14.2.1
      Shell: 5.9 - /bin/zsh
    Binaries:
      Node: 20.9.0 - /usr/local/bin/node
      Yarn: 4.0.1 - /usr/local/bin/yarn
      npm: 10.1.0 - /usr/local/bin/npm
      Watchman: 2023.07.10.00 - /usr/local/bin/watchman
    Managers:
      CocoaPods: 1.14.3 - /Users/nickname/.rbenv/shims/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 23.2, iOS 17.2, macOS 14.2, tvOS 17.2, visionOS 1.0, watchOS 10.2
      Android SDK:
        API Levels: 23, 26, 28, 29, 30, 31, 33, 34
        Build Tools: 28.0.3, 29.0.2, 29.0.3, 30.0.2, 30.0.3, 31.0.0, 33.0.0, 33.0.1, 34.0.0
        System Images: android-26 | Google APIs Intel x86 Atom, android-27 | Google APIs Intel x86 Atom, android-27 | Google Play Intel x86 Atom, android-28 | Google APIs Intel x86 Atom, android-29 | Google APIs Intel x86 Atom, android-30 | Google APIs Intel x86 Atom, android-30 | Google Play Intel x86 Atom, android-31 | Google APIs ARM 64 v8a, android-31 | Google APIs Intel x86_64 Atom, android-33 | Google APIs Intel x86_64 Atom
    IDEs:
      Android Studio: 2023.1 AI-231.9392.1.2311.11255304
      Xcode: 15.2/15C500b - /usr/bin/xcodebuild
    npmPackages:
      expo: ~50.0.3 => 50.0.3 
      react: 18.2.0 => 18.2.0 
      react-native: 0.73.2 => 0.73.2 
    Expo Workflow: bare

TomCorvus avatar Jan 24 '24 17:01 TomCorvus

I think I have this problem too...

    await Font.loadAsync({
      Inter: require('@tamagui/font-inter/otf/Inter-Medium.otf'),
      InterBold: require('@tamagui/font-inter/otf/Inter-Bold.otf'),
    });

Just does not work on SDK 50 and all of my icons from @expo/vector-icons are gone, instead, got this error: Module "26" is missing from the asset registry

Platform: Web

likeSo avatar Jan 25 '24 10:01 likeSo

I have the same problem, since switching to SDK 50, the icons from react-native-paper no longer work. The checkboxes don't even appear anymore. Also I added expo-font in the configuration file and it doesn't work either :/

[ "expo-font", { "fonts": [ "./assets/fonts/Poppins.ttf", "./assets/fonts/PoppinsBold.ttf" ] } ],

Eliost avatar Jan 26 '24 11:01 Eliost

I think it is for both platforms (Android and iOS). I can't build Android release app because of that.

AssertionError [ERR_ASSERTION]: Assets must have hashed files. Ensure the expo-asset plugin is installed.

> Task :app:createBundleReleaseJsAndAssets FAILED
Execution failed for task ':app:createBundleReleaseJsAndAssets'.
> Process 'command 'node'' finished with non-zero exit value 1

EDIT: on Web/iOS/Android, when I see the @likeSo reply.

TomCorvus avatar Jan 26 '24 13:01 TomCorvus

I am facing the same issue and getting Unable to resolve "missing-asset-registry-path" from "src/assets/fonts/Aeonik/Aeonik-Bold.ttf" Screenshot 2024-01-26 at 10 51 42 AM

Ankur-Magan avatar Jan 26 '24 15:01 Ankur-Magan

I'm having the same issue here: cannot load any custom font.

I tried using directly expo/vector-icons, I tried loading custom font with expo-font (tried both approaches seen here: https://docs.expo.dev/develop/user-interface/fonts/#use-a-custom-font).

Nothing worked, nothing is rendered on screen and I have the following error : Module "XX" is missing from the asset registry

I also had the same issue when I was on expo 49.

expo-env-info 1.2.0 environment info: System: OS: Linux 6.5 Ubuntu 22.04.3 LTS 22.04.3 LTS (Jammy Jellyfish) Shell: 5.1.16 - /bin/bash Binaries: Node: 14.21.3 - ~/.nvm/versions/node/v14.21.3/bin/node Yarn: 1.22.19 - /usr/bin/yarn npm: 6.14.18 - ~/.nvm/versions/node/v14.21.3/bin/npm npmPackages: expo: ^50.0.2 => 50.0.2 react: 18.2.0 => 18.2.0 react-native: 0.73.2 => 0.73.2 npmGlobalPackages: eas-cli: 7.0.0 Expo Workflow: managed

myagoo avatar Jan 26 '24 17:01 myagoo

The cumbersome "workaround" I found is to use react-native-svg to recreate the icon components I want to use with the help of https://reactsvgicons.com/

myagoo avatar Jan 26 '24 17:01 myagoo

I think I get the same issue, after I upgraded to expo SDK 50 I get this error:

[Error: Module "1" is missing from the asset registry]

If I delete all fonts from the useFont hook (including expo vector Icons) it works, but then no symbols will be displayed. The module which is missing, changed in my case after I removed one of the fonts I used.

Before i upgraded to SDK 50 it worked in my case.

Error: image

ALBUS12345 avatar Jan 26 '24 19:01 ALBUS12345

can someone please share a minimal reproducible example without using a monorepo?

brentvatne avatar Jan 26 '24 22:01 brentvatne

While trying to create a minimal example, I created another expo app with fresh deps and custom font loading worked 😱 So I updated expo from 50.0.2 to 50.0.4 and @babel/core in my main project and it is now working

myagoo avatar Jan 27 '24 08:01 myagoo

I update Expo but I have the same error. Simulator Screenshot - iPhone 15 Pro Max - 2024-01-27 at 11 28 27

I had this issue during SDK50 beta but I thought it was a compatibility problem. @myagoo do you just call font with useFont? For now, I try with useFont like on SDK49 and I add plugins config in app.config:

	plugins: [
		[
			'expo-font',
			{
				fonts: [
					'../core/src/assets/fonts/CircularBook.ttf',
					'../core/src/assets/fonts/CircularMedium.ttf',
					'../core/src/assets/fonts/CircularBold.ttf',
					'../core/src/assets/fonts/Icons.ttf',
				],
			},
		],
		'expo-secure-store',
		'expo-tracking-transparency',
	],

But I don't know if I need to set both.

TomCorvus avatar Jan 27 '24 10:01 TomCorvus

I only tried dynamic font loading with useFont.You dont need to the app.json part if you use useFont.

For me, a lot of things were not working : expo vector icons did not show up, sound loading did not properly work, custom font loading did not work.

But everything is new resolved since I updated all my dependencies to latest

myagoo avatar Jan 27 '24 10:01 myagoo

While trying to create a minimal example, I created another expo app with fresh deps and custom font loading worked 😱 So I updated expo from 50.0.2 to 50.0.4 and @babel/core in my main project and it is now working

what version did you use for @babel/core?

Ankur-Magan avatar Jan 28 '24 05:01 Ankur-Magan

I am using expo managed workflow and noticed that font are successfully getting copied but issue happens during metro bundler

ScreenShots

Screenshot 2024-01-28 at 7 54 24 PM

Screenshot 2024-01-28 at 7 55 03 PM

Metro Config

/**
 * Metro configuration for React Native
 * https://github.com/facebook/react-native
 *
 * @format
 */

const { getDefaultConfig } = require('expo/metro-config');

// extra config is needed to enable `react-native-svg-transformer`
module.exports = (async () => {
  const {
    resolver: { sourceExts, assetExts, resolverMainFields },
  } = await getDefaultConfig(__dirname);
  return {
    transformer: {
      babelTransformerPath: require.resolve('react-native-svg-transformer'),
      assetPlugins: ['expo-asset/tools/hashAssetFiles'],
    },
    resolver: {
      assetExts: assetExts.filter((ext) => ext !== 'svg'),
      sourceExts: [...sourceExts, 'svg', 'd.ts'],
      resolverMainFields: ['sbmodern', ...resolverMainFields],
    },
  };
})();

Any suggestions would be highly appreciated, Thanks in advance

Ankur-Magan avatar Jan 29 '24 00:01 Ankur-Magan

@TomCorvus were you able to get any fix?

Ankur-Magan avatar Jan 29 '24 21:01 Ankur-Magan

@Ankur-Magan No, I tried a few things, but it doesn't work. Can you give us a minimal repro of your environment? On my side, I can't reproduce it on a simple repo.

But it is very strange, if I set Icons font on Xcode, it is working but not with letters font.

I don't have any clue to find a solution. I don't know if it causes by react-native or expo.

I find this issue on react-native project (https://github.com/facebook/react-native/issues/42693) This user seems to get the same problem without Expo but he is not really precise in his description.

I keep trying to reproduce this problem.

TomCorvus avatar Jan 29 '24 22:01 TomCorvus

I believe this problem happens only when UPGRADING the expo to SDK50. What did I do?

  • vim package.json, edit expo package from 49.0.15 to 50.0.2 or 50.0.4
  • $ bun i
  • $ bun expo install --fix
  • Remove 'expo-router/babel', from babel.config.js
  • $ bun expo start --web -c, and an error Module "22" is missing from the asset registry appears!

But for a minimal reproducible example, I cannot create an old version of the expo! SDK 49: No Error!
SDK 50: No Error!
SDK 49 -> SDK 50: Error!

My package.json:

{
  "name": "",
  "main": "expo-router/entry",
  "version": "1.0.0",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "test": "jest --watchAll"
  },
  "jest": {
    "preset": "jest-expo"
  },
  "dependencies": {
    "@expo/vector-icons": "^14.0.0",
    "@react-native-async-storage/async-storage": "1.21.0",
    "@react-navigation/native": "^6.0.2",
    "@shopify/flash-list": "1.6.3",
    "@tamagui/animations-react-native": "^1.84.1",
    "@tamagui/babel-plugin": "^1.84.1",
    "@tamagui/font-inter": "^1.84.1",
    "@tamagui/react-native-media-driver": "^1.84.1",
    "@tamagui/shorthands": "^1.84.1",
    "@tamagui/themes": "^1.84.1",
    "axios": "^1.6.5",
    "expo": "~50.0.4",
    "expo-font": "~11.10.2",
    "expo-image": "~1.10.5",
    "expo-image-picker": "~14.7.1",
    "expo-linking": "~6.2.2",
    "expo-router": "~3.4.6",
    "expo-splash-screen": "~0.26.4",
    "expo-status-bar": "~1.11.1",
    "expo-system-ui": "~2.9.3",
    "expo-web-browser": "~12.8.2",
    "i18next": "^23.7.16",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-i18next": "^14.0.0",
    "react-native": "0.73.2",
    "react-native-gesture-handler": "~2.14.0",
    "react-native-network-logger": "^1.15.0",
    "react-native-reanimated": "~3.6.2",
    "react-native-safe-area-context": "4.8.2",
    "react-native-screens": "~3.29.0",
    "react-native-web": "~0.19.6",
    "react-native-webview": "13.6.4",
    "tamagui": "^1.84.1"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@types/react": "~18.2.14",
    "jest": "^29.2.1",
    "jest-expo": "~50.0.1",
    "prettier": "^3.1.1",
    "react-test-renderer": "18.2.0",
    "typescript": "^5.1.3"
  },
  "overrides": {
    "react-refresh": "~0.14.0"
  },
  "resolutions": {
    "react-refresh": "~0.14.0"
  },
  "private": true
}

My babel.config.js:

module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      [
        "@tamagui/babel-plugin",
        {
          components: ["tamagui"],
          config: "./tamagui.config.ts",
          logTimings: true,
        },
      ],
      "react-native-reanimated/plugin"
    ],
  };
};

likeSo avatar Jan 30 '24 06:01 likeSo

+1

Kind of same. After upgrading to SDK 50, I get:

Error: Unable to resolve module missing-asset-registry-path from .../assets/fonts/MuseoSans_300.otf: missing-asset-registry-path could not be found within the project or in these directories: node_modules

1 | OTTO �0CFF ��� GPOS���+�#�GSUB���\�OS/2L� `cmap�e���4head��?��6hheay��$hmtx��h�� maxp�Pname��$u�4post��� �S"_<�����������.@s���j����@�P�,������2���@Jxljb ����� ���....

AskoK avatar Jan 30 '24 07:01 AskoK

I have the same issue, I downgraded the @react-native/assets-registry from 0.74 to 0.73 to work

gtsifrikas avatar Jan 30 '24 11:01 gtsifrikas

I am able to recreate this issue with new expo app and here is the reproducible git repo for same:

https://github.com/MaganAnkur/expo-test

Issue happens when I added svg support in the code after adding metro.config.js and I added react-native-svg-transformer, app start giving

Issue 1: Asset must have hashed files, Ensure the expo-asset plugin is installed Note: expo-asset is already installed

Issue 2: I modified the metro config a little bit and added assetPlugins: ['expo-asset/tools/hashAssetFiles'] it fixed the above issue but not it started giving: Unable to resolve module missing-asset-registry-path

cc: @brentvatne

Ankur-Magan avatar Jan 30 '24 16:01 Ankur-Magan

So far I have managed to build Android app in release and debug mode and fonts are loaded. Thanks to @Ankur-Magan, I followed steps on https://github.com/kristerkari/react-native-svg-transformer and modified my metro config by adding:

babelTransformerPath: require.resolve("react-native-svg-transformer")

and

    assetExts: assetExts.filter((ext) => ext !== "svg"),
    sourceExts: [...sourceExts, "svg"]

I also added: yarn add -D @react-native/js-polyfills metro-config @react-native/metro-babel-transformer metro-runtime @react-native/metro-config react-native-svg-transformer See: https://github.com/react-navigation/react-navigation/issues/11192#issuecomment-1916837933

After that, I had an error with ProGuard and R8. I needed to add in ProGuard rules:

-dontwarn javax.lang.model.element.Element
-dontwarn javax.lang.model.type.TypeMirror
-dontwarn javax.lang.model.type.TypeVisitor
-dontwarn javax.lang.model.util.SimpleTypeVisitor7

Despite all this, I had to add my fonts in android/app/src/main/assets/fonts (See: https://github.com/unimonkiez/react-native-asset)

Now I see my custom fonts on release or debug (emulator) mode BUT I always this error [Error: Module "1" is missing from the asset registry] according to useFont hook.

But it doesn't work on iOS.

Please don't follow these steps above to unblock your project in production mode. I have not testing if all of this is stable and it's specific to my project, but this may give you some ideas on how to resolve the issue.

TomCorvus avatar Jan 30 '24 21:01 TomCorvus

While trying to create a minimal example, I created another expo app with fresh deps and custom font loading worked 😱 So I updated expo from 50.0.2 to 50.0.4 and @babel/core in my main project and it is now working

what version did you use for @babel/core?

After investigating the package-lock.json, it seems that I was already using the latest version of @babel/core 7.23.7. So the only thing that i did to fix my issue was to upgrade expo to 50.0.4

myagoo avatar Jan 31 '24 18:01 myagoo

@TomCorvus @Ankur-Magan - the recommended approach to extend the babel transformer is this: https://docs.expo.dev/versions/latest/config/metro/#extending-the-babel-transformer

basically, create a file that exports a transform function, add your custom logic and then return a call to the expo babel transformer

does anyone want to take a stab at fixing this in the react-native-svg-transformer readme?

brentvatne avatar Jan 31 '24 23:01 brentvatne

Thanks @brentvatne for taking look into this, but seems like in v1.3.0 react-native-svg-transformer is already using @expo/metro-config/babel-transformer here : https://github.com/kristerkari/react-native-svg-transformer/blob/c2f6c81c754ab8d586b50b457f80480ead3c1806/index.js#L14C21-L14C57

but despite that I tried extracting the code and only use @expo/metro-config/babel-transformer

metro.transformer.js

const { resolveConfig, transform } = require("@svgr/core");
const resolveConfigDir = require("path-dirname");


/**
 * `metro-react-native-babel-transformer` has recently been migrated to the React Native
 * repository and published under the `@react-native/metro-babel-transformer` name.
 * The new package is default on `react-native` >= 0.73.0, so we need to conditionally load it.
 *
 * Additionally, Expo v50.0.0 has begun using @expo/metro-config/babel-transformer as its upstream transformer.
 * To avoid breaking projects, we should prioritze that package if it is available.
 */
const upstreamTransformer = require('@expo/metro-config/babel-transformer');

const defaultSVGRConfig = {
  native: true,
  plugins: ["@svgr/plugin-svgo", "@svgr/plugin-jsx"],
  svgoConfig: {
    plugins: [
      {
        name: "preset-default",
        params: {
          overrides: {
            inlineStyles: {
              onlyMatchedOnce: false
            },
            removeViewBox: false,
            removeUnknownsAndDefaults: false,
            convertColors: false
          }
        }
      }
    ]
  }
};

module.exports.transform = async ({ src, filename, options }) => {
  if (filename.endsWith(".svg")) {
    const config = await resolveConfig(resolveConfigDir(filename));
    const svgrConfig = config
      ? { ...defaultSVGRConfig, ...config }
      : defaultSVGRConfig;
    return upstreamTransformer.transform({
      src: await transform(src, svgrConfig),
      filename,
      options
    });
  }
  return upstreamTransformer.transform({ src, filename, options });
};

metro.config.js

/**
 * Metro configuration
 * https://facebook.github.io/metro/docs/configuration
 *
 * @type {import('metro-config').MetroConfig}
 */

const { getDefaultConfig } = require("expo/metro-config");

const defaultConfig = getDefaultConfig(__dirname);
const { assetExts, sourceExts } = defaultConfig.resolver;


const config = {
  ...defaultConfig,
  transformer: {
   babelTransformerPath: require.resolve("./metro.transformer.js"),
    assetPlugins: ['expo-asset/tools/hashAssetFiles']
  },
  resolver: {
    assetExts: assetExts.filter((ext) => ext !== "svg"),
    sourceExts: [...sourceExts, "svg"]
  }
};

module.exports = config

Issue still persist. Thanks in advance

Ankur-Magan avatar Feb 01 '24 01:02 Ankur-Magan

ah i see. one potential issue i see there is that it is clobbering the resolver and the transformer. make sure you keep those values around from the original config:

const config = {
  ...defaultConfig,
  transformer: {
   ...defaultConfig.transformer,
   babelTransformerPath: require.resolve("./metro.transformer.js"),
  },
  resolver: {
   ...defaultConfig.resolver,
    assetExts: assetExts.filter((ext) => ext !== "svg"),
    sourceExts: [...sourceExts, "svg"]
  }
};

notice that the react-native-svg-transformer docs correctly demonstrate this:

const { getDefaultConfig } = require("expo/metro-config");

module.exports = (() => {
  const config = getDefaultConfig(__dirname);

  const { transformer, resolver } = config;

  config.transformer = {
    ...transformer,
    babelTransformerPath: require.resolve("react-native-svg-transformer")
  };
  config.resolver = {
    ...resolver,
    assetExts: resolver.assetExts.filter((ext) => ext !== "svg"),
    sourceExts: [...resolver.sourceExts, "svg"]
  };

  return config;
})();

https://github.com/kristerkari/react-native-svg-transformer/tree/c2f6c81c754ab8d586b50b457f80480ead3c1806?tab=readme-ov-file#for-expo-sdk-v4100-or-newer

brentvatne avatar Feb 01 '24 01:02 brentvatne

Thank you so much @brentvatne for your suggestion, it fixes the issue for me, Really appreciate your time and effort

Ankur-Magan avatar Feb 01 '24 02:02 Ankur-Magan

good to hear @Ankur-Magan!

@TomCorvus - if you can create a minimal repro that doesn't use a monorepo that'd be appreciated. we currently still recommend yarn classic for monorepos (see this doc) but @byCedric has put in a bunch of work to improve out-of-the-box support in react-native for other pkg manager setups, it's just not quite there yet. you may have some success using other tools in the ecosystem to help make those monorepo tools work though.

brentvatne avatar Feb 01 '24 02:02 brentvatne

@brentvatne Not needed. My metro config was a mess. I used https://github.com/microsoft/rnx-kit since SDK49 to get symlinks available with yarn and monorepo. I followed your message, took @byCedric monorepo metro config as example and cleaned my metro config. Fonts appear now on iOS and Android. Thanks a lot for your help.

I post my Metro config if it can help someone else. Monorepo, Turbo, SVG, Lottie, Storybook and some blacklisted modules not needed for my project.

// Learn more https://docs.expo.dev/guides/monorepos
const { getDefaultConfig } = require('expo/metro-config');
const { FileStore } = require('metro-cache');
const path = require('path');

const projectRoot = __dirname;
const workspaceRoot = path.resolve(projectRoot, '../..');

const config = getDefaultConfig(projectRoot);

const blacklistedModules = ['fs', 'ejs'];

config.transformer.getTransformOptions = async () => ({
	transform: {
		experimentalImportSupport: false,
		inlineRequires: true,
	},
});

config.transformer.babelTransformerPath = require.resolve('react-native-svg-transformer');

config.watchFolders = [workspaceRoot];

config.resolver.disableHierarchicalLookup = true;

config.resolver.resolverMainFields = ['sbmodern', 'react-native', 'browser', 'main'];

config.resolver.nodeModulesPaths = [
	path.resolve(projectRoot, 'node_modules'),
	path.resolve(workspaceRoot, 'node_modules'),
];
config.resolver.resolveRequest = (context, moduleName, platform) => {
	if (blacklistedModules.includes(moduleName)) {
		return {
			filePath: path.resolve(__dirname + '/shim-module.js'),
			type: 'sourceFile',
		};
	}
	// Optionally, chain to the standard Metro resolver.
	return context.resolveRequest(context, moduleName, platform);
};
config.resolver.assetExts = [...config.resolver.assetExts.filter((ext) => ext !== 'svg'), 'lottie'];

config.resolver.sourceExts = [...config.resolver.sourceExts, 'svg'];

// Use turborepo to restore the cache when possible
config.cacheStores = [new FileStore({ root: path.join(projectRoot, 'node_modules', '.cache', 'metro') })];

module.exports = config;

TomCorvus avatar Feb 01 '24 19:02 TomCorvus

@0xPT it was related to metro config, and what exactly you are facing, for fonts if you will refer to official documentation - https://docs.expo.dev/versions/latest/sdk/font/ it should be good

Ankur-Magan avatar Feb 07 '24 20:02 Ankur-Magan

guys this is a big issue, i'm still have this issue. like your cases i did the upgrade from previous version of expo (45 in my case) to the 50, and i fixed a lot of issues in the meanwhile, but this about the Assets still here. in my case this is the first error i encontering when i launch the run:ios: node_modules/@expo-google-fonts/nunito/Nunito_500Medium.ttf: Assets must have hashed files. Ensure the expo-asset plugin is installed.

but if i commenting the part of my code about the fonts, i have the same issues but on expo-vectors.

please fix it @expo-bot

DeabitTech avatar Feb 20 '24 14:02 DeabitTech

@DeabitTech - please read the thread, you are not configuring metro config correctly. also try running npx expo-doctor@latest which will tell you the same. this page explains how to extend metro safely: https://docs.expo.dev/guides/customizing-metro/

brentvatne avatar Feb 20 '24 18:02 brentvatne