2 years ago
#67891
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