Many projects do not use a specific tool to manage multiple packages from the same repository, and this is not necessarily a problem. However, one of the trickiest issues in medium to large react-native projects is importing files outside of the root directory with Metro Bundler.
In fact, even in the React Native official documentation, you will not find a solution for this.
Consider the following project structure:
root
node_modules
src
-- components
-- views
-- theme
-- …others
web
-- node_modules
-- index.js
-- …others
native
-- node_modules
-- android
-- ios
-- index.js
-- App.jsx
-- metro.config.js
-- babel.config.js
-- …others
This project uses react-native-web, so the code can be developed once and then run on web, iOS, and Android.
Let’s say you have an Example
component in src
.
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export const Example = () => {
return (
<View style={style.container}>
<Text style={style.title}>Hello from Root: /src</Text>
</View>
);
};
const style = StyleSheet.create({
container: {
alignItems: 'center',
backgroundColor: 'yellow',
height: 200,
justifyContent: 'center',
width: 200,
},
title: {
fontSize: 18,
},
});
To import the Example
component from src
in your native App.js
, you would do this:
import {Example} from '../src/components';
Or, you could use an alias called @components
:
import {Example} from '@components';
However, the Metro Bundler would give you the following error:
BUNDLE ./index.js
error: Error: Unable to resolve module ../src/components from /…route_to_project_directory/rn-import-files-outside-root/native/App.js:
Solution
- To solve this issue, you will need to modify the Metro configuration in your
native/metro.config.js
file:
const path = require('path');
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true,
},
}),
},
resolver: {
sourceExts: ['js', 'json', 'ts', 'tsx', 'jsx'],
},
watchFolders: [
path.resolve(__dirname, '../node_modules'),
path.resolve(__dirname, '../src'),
path.resolve(__dirname, '..'),
],
projectRoot: path.resolve(__dirname),
};
- Add the
babel-plugin-module-resolver
to your development dependencies. Navigate to your React Native project directory and run:
yarn add -D babel-plugin-module-resolver
- Then, modify your
native/babel.config.js
file as follows:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module-resolver',
{
root: ['../src'],
alias: {
'@components': '../src/components',
'react-native': './node_modules/react-native',
react: './node_modules/react',
},
},
],
],
};
Note: the exact contents of this file will depend on the specific configuration of your project.
To see the changes, stop the Metro Bundler in your terminal and start it again with the reset cache flag:
npx react-native start --reset-cache
This should allow you to import files from outside the root directory in your React Native project.
Here are some additional resources that may be helpful:
- Configuring Metro (official documentation): https://facebook.github.io/metro/docs/configuration/
- Example repository: https://github.com/developerdanx/rn-import-files-outside-root
Top comments (1)
Worked, thank you