Importing from shared folder from react native

All we need is an easy explanation of the problem, so here it is.

I’m in the process of creating a monorepo to hold both my React web app and my React Native app as they share a lot of common code.

The setup i’m trying to get is:

Project  
|  
+-- web  
+-- native  
----|------ file.js (should be able to import from 'shared/file2.js')  
+-- shared  
----|------ file2.js  
----|------ package.json (with name="shared")  
+-- package.json

From folowing this post: https://blog.callstack.io/a-cure-for-relative-requires-in-react-native-2b263cecf0f6#.4g1o5inru I added a package.json file to the shared folder with:

{ "name": "shared" }

and am starting my native app from the package.json in the root folder like so:

"start-native": "./native/node_modules/react-native/packager/packager.sh"

But for some reason i’m getting the following error:
enter image description here

Any idea what i’m doing wrong or how I can achieve importing files in my RN app from a shared folder that is upstream?

EDIT:
A few details I forgot to mention.
The line giving me the error is (fake file names…):

// in native/file.js  
import { aFunctionName } from 'shared/file2'

Also tried adding a name in the package.json (name=proj-root) in the root level and importing like:

import { aFunctionName } from 'proj-root/shared/file2'

Thanks!
Uri

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

To share code between web and native you should change how you are structuring your folders.

First start with a new project react-native init myProject this will create the default structure for RN apps.

myProject  
|  
+-- android
+-- ios
+-- index.android.js
+-- index.ios.js
...

Now create specific folders for web and shared code.

myProject  
|  
+-- android
+-- ios
+-- index.android.js
+-- index.ios.js
+-- web
+-- shared
----|------ index.js 
...

shared/index.js

function hi() {
    return 'hi';
}

module.exports = {
    hi: hi
};

index.ios.js

import { hi } from './shared/'; 

Method 2

I ended up changing the folder structure as stated in @diegopartes answer.

In addition, I wanted to achieve the effect of being able to import from the shared folder using absolute paths from both my web and mobile directories.

For this I did the following:

Web
I moved my webpack.config.js to the root folder of the app. Inside webpack.config.js I have the following configuration the allows me to import files using absolute paths:

const path                = require('path');
const sharedPath          = path.join(__dirname, 'shared');

const config = {
...
resolve: {
    root: [sharedPath],
  },
...
}

now my shared folder acts as a root folder. Meaning, if I have

- shared  
-- reducers  
-- actions  
--- todos.js

I can do an import { addTodo } from 'actions/todos'

Mobile

Here I went by this post which basically says:

Whichever folder you want to be able to import as root from, add a package.json file with { "name": "FOLDER_NAME" }. So for to achieve the same import as in the web app:

- shared  
    -- reducers  
    -- actions  
    --- todos.js
    --- package.json

Where the package.json contents is:

{
  "name": "actions"
}

Now I can do the same import as I did in the web app from my mobile app files.

EDIT

Regarding node_modules, I use the same package.json for both web and mobile. In my webpack.config I have an array of all React Native packages an these are excluded from my vendor bundle file.

Method 3

Did you consider to hoist node_modules?

Moreover you can use lerna to achieve what you want instead of self-written solution.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply