2 years ago

#67891

test-img

Kruspe

Use custom fonts within expo/Node.js-monorepo with UI Kitten

I am using this monorepo as a base template. I installed UI Kitten based on the instructions in the UI Kitten documentation

cd ./packages/expo
yarn add @ui-kitten/components @eva-design/eva react-native-svg

I also installed the following packages, according to the expo documentation:

yarn add expo-font expo-app-loading

I then copied a ttf-file to packages/expo/assets and created a custom mapping file, packages/app/mapping.json:

{
    "components": {
    },
    "strict": {
        "text-font-family": "my-font-regular",
    }
}

After that I modified packages/expo/App.tsx:

import { ApplicationProvider, Layout, Text } from '@ui-kitten/components';
...
export default function App() {
  const loadFonts = async () => {
    await Font.loadAsync({
      'my-font-regular': require('./assets/Amatic_Regular.ttf')
    })
  }
  const [fontLoaded, setFontLoaded] = useState(false);
  if (!fontLoaded) {
    console.log("FONT NOT LOADED")
    return (
      <AppLoading
        startAsync={loadFonts}
        onFinish={() => { console.log("DONE LOADING");setFontLoaded(true)}}
        onError={(err) => console.error(err)}
      />
    )
  }
  console.log("FONT IS LOADED, RETURN APP")
  return (
    <ApplicationProvider {...eva} theme={eva.light}>
        <Layout style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Text>Test</Text>
        </Layout>
    </ApplicationProvider>
  )
}

In order to make this work, I'll have to modify my packages/expo/metro.config.js, according to the UI Kitten documentation:

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

const config = getDefaultConfig(__dirname)

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

config.watchFolders = [workspaceRoot]
config.resolver.nodeModulesPath = [
  path.resolve(projectRoot, 'node_modules'),
  path.resolve(workspaceRoot, 'node_modules')
]

const MetroConfig = require('@ui-kitten/metro-config');

const evaConfig = {
  evaPackage: '@eva-design/eva',
  customMappingPath: path.resolve(workspaceRoot, 'packages/app/mapping.json'),
};

module.exports = MetroConfig.create(evaConfig, config);

If I now try to start the project, using:

cd packages/expo
yarn start:expo

and try to run it on an Android device, it will fail:

ENOENT: no such file or directory, open 'node_modules/@eva-design/eva/generated.json'
Error: ENOENT: no such file or directory, open 'node_modules/@eva-design/eva/generated.json'
    at Object.openSync (node:fs:585:3)
    at Object.writeFileSync (node:fs:2153:35)
    at Function.BootstrapService.processMappingIfNeeded (C:\Users\Me\git\expo-next-monorepo-example\src\metro-config\services\bootstrap.service.ts:136:10)
    at Function.BootstrapService.run (C:\Users\Me\git\expo-next-monorepo-example\src\metro-config\services\bootstrap.service.ts:67:24)
    at Object.handleMetroEvent [as update] (C:\Users\Me\git\expo-next-monorepo-example\src\metro-config\index.ts:55:24)
    at C:\Users\Me\git\expo-next-monorepo-example\node_modules\metro\src\index.js:153:27
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (C:\Users\Me\git\expo-next-monorepo-example\node_modules\metro\src\index.js:68:24)
    at _next (C:\Users\Me\git\expo-next-monorepo-example\node_modules\metro\src\index.js:90:9)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

However, if I go to the base directory (cd ../../), I can enter the following command:

npx ui-kitten bootstrap @eva-design/eva .\packages\app\mapping.json

If I try to enter this command within the expo-directory, like:

npx ui-kitten bootstrap @eva-design/eva ..\app\mapping.json

it fails:

node:internal/crypto/hash:105
    throw new ERR_INVALID_ARG_TYPE(
    ^

TypeError [ERR_INVALID_ARG_TYPE]: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received null
    at new NodeError (node:internal/errors:371:5)
    at Hash.update (node:internal/crypto/hash:105:11)
    at Function.BootstrapService.createChecksum (C:\Users\Me\git\expo-next-monorepo-example\node_modules\@ui-kitten\metro-config\services\bootstrap.service.js:132:10)
    at Function.BootstrapService.processMappingIfNeeded (C:\Users\Me\git\expo-next-monorepo-example\node_modules\@ui-kitten\metro-config\services\bootstrap.service.js:99:41)
    at Function.BootstrapService.run (C:\Users\Me\git\expo-next-monorepo-example\node_modules\@ui-kitten\metro-config\services\bootstrap.service.js:58:26)
    at Command.<anonymous> (C:\Users\Me\git\expo-next-monorepo-example\node_modules\@ui-kitten\metro-config\cli\bootstrap.js:23:80)
    at Command.listener (C:\Users\Me\git\expo-next-monorepo-example\node_modules\commander\index.js:315:8)
    at Command.emit (node:events:390:28)
    at Command.parseArgs (C:\Users\Me\git\expo-next-monorepo-example\node_modules\commander\index.js:651:12)
    at Command.parse (C:\Users\Me\git\expo-next-monorepo-example\node_modules\commander\index.js:474:21) {
  code: 'ERR_INVALID_ARG_TYPE'

So, if the command has been run from the base directory, the app will start. It will output:

 LOG  FONT NOT LOADED
 LOG  DONE LOADING
 LOG  FONT IS LOADED, RETURN APP

and then crash, saying:

 ERROR  fontFamily "my-font-regular" is not a system font and has not been loaded through Font.loadAsync.

- If you intended to use a system font, make sure you typed the name correctly and that it is supported by your device operating system.

- If this is a custom font, be sure to load it with Font.loadAsync.
    [...]

Noticeable: After I make a change to the code, the app doesn't reload, but instead crash:

Error: ENOENT: no such file or directory, open 'node_modules/@eva-design/eva/generated.json'

It won't start until I run said command from the base directory again.

I have tested this workflow with a "normal" expo project and it works. The issue is somewhere in this monorepo-setup.

node.js

react-native

expo

metro-bundler

react-native-ui-kitten

0 Answers

Your Answer

Accepted video resources