Create-react-native-app: Importing files outside main directory

Created on 1 Jun 2017  路  20Comments  路  Source: expo/create-react-native-app

Where I have a directory for mobile and a directory for web which I'd like to share some common code (utils, etc). Currently, if I import a file outside the root directory of my generated app (outside where App.js is located), I get an error with no file found.

Is this by design? Will this be supported in the future and is this an Expo limitation or RN?

Thanks

Most helpful comment

@pankaj-arunsingh I can鈥檛 find the original issue where I finally found this but basically add only the external module path you want to import. In my case my module had a dependency on React and React-Native so those are added as extraNodeModules. Hope this helps.

Inside rn-cli.config.js:

var path = require("path");
const metroBundler = require('metro-bundler');

var config = {
  extraNodeModules: {
    "react-native": path.resolve(__dirname, "node_modules/react-native"),
    "react": path.resolve(__dirname, "node_modules/react"),
  },
  getProjectRoots() {
    return [
      // Keep your project directory.
      path.resolve(__dirname),
      path.resolve(__dirname, "../native"), // path to the external module
    ];
  }
}
module.exports = config;

All 20 comments

this is a behavior of the react-native packager: https://github.com/facebook/react-native/issues/12241

@brentvatne thanks for the reply. Will this solution work with Expo?
https://github.com/facebook/react-native/issues/12241#issuecomment-300879473

why not try it and find out? :P

yes

@brentvatne
The solution @mmahalwy mentioned, i.e. creating rn-cli.config.js in the root of my project and using it to add the parent directory as a project root, doesn't work for me with Expo 18.

Wondering if I'm doing something wrong or whether this doesn't work anymore.

Can confirm that this solution does not work. There is currently no way of importing a file from outside the app directory. Using symlinks doesn't work either.

One suggestion and workaround I will add is that you could bundle the common files into a npm package and publish it on the npm registry, then you can add it as a dependency to your projects.

Metro Bundler, which is used by React Native as the packager (the React Native equivalent to Webpack) doesn't support symlinks. As for rn-cli.config.js, it does still work but it's just hard to configure -- we use it on our internal "monorepo" in order to load local versions of our npm packages at Expo. Make sure in app.json, under "expo", you have:

"packagerOpts": {
    "projectRoots": "",
    "assetExts": ["ttf"],
    "config": "rn-cli.config.js"
 },

An example of a rn-cli.config.js:

const path = require('path');

module.exports = {
  getProjectRoots() {
    return [path.join(__dirname, '..', 'other-dir'), __dirname];
  }
};

There really needs to be some better documentation on this :( If someone gets it working, can you write it up?

@brentvatne I can't seem to get the packager to accept the other root directories. How do you import them? Do you need to reference the path or just call the component itself?

1 - import 'component' from '../other-dir/component'
2 - import 'component' from 'component'

I'm trying to get a monorepo working similar to yours but I just can't seem to crack this.

My project directory

- apps
-- native (CRNA root)
--- app.json
--- index.js
--- package.json
- components
-- component-1
--- index.js
--- package.json
-- component-2
--- index.js
--- package.json
lerna.json
package.json

app.json

{
  "expo": {
    "sdkVersion": "19.0.0"
  },
  "packagerOpts": {
    "projectRoots": "",
    "config": "rn-cli.config.js"
 }
}

rn-cli.config.js

const path = require('path');

module.exports = {
  getProjectRoots() {
    return [
      path.join(__dirname, '..', '..', 'components'),
      __dirname
    ];
  }
};

Nevermind! I'm an idiot! I misunderstood "under expo" in the app.json - It's all working now.

app.json

{
  "expo": {
    "sdkVersion": "19.0.0",
    "packagerOpts": {
      "projectRoots": "",
      "config": "rn-cli.config.js"
    }
  }
}

@robdonn @brentvatne did this work for you when the module used react and react-native as peer dependencies? After updating to the latest everything (my project had a very old crna-scripts), rn-cli.config.js was being accepted with that config but no matter what I tried, it kept on failing to recognise the linked module.

There's nothing fancy going on with the library (https://github.com/viewsdx/keyboard-avoiding-and-dismissing-view), just one file that exports a component and imports react and some stuff from react-native. Both, react and react-native are marked as peerDependencies and in the latest yarn (1.1.0) they don't get installed at all.

Using the config above it picks up the module alright but it fails to load react with Module does not exist in the module map:

screen shot 2017-09-25 at 20 40 25

If react is a dev dependency (with the same dependencies that my app is using), it goes even crazier because of duplicate module definitions:
screen shot 2017-09-25 at 20 43 07

It doesn't matter if my module comes before or after __dirname in getProjectRoots or if I reset the cache in between. The moment the module is linked it goes boom. :(

It is important to say that it works fine if my linked module doesn't use react, react-native or any other dependency that the project I'm linking from uses.

I wonder if anyone ran into this and got around it somehow?

Do you reckon I should be posting this at facebook/metro-bundler/issues/1 instead?

@dariocravero did you ever find a solution to this problem? This is exactly what I'm up against right now.

This is crazy. Please post a solution to this problem if anyone finds it.

@pankaj-arunsingh I can鈥檛 find the original issue where I finally found this but basically add only the external module path you want to import. In my case my module had a dependency on React and React-Native so those are added as extraNodeModules. Hope this helps.

Inside rn-cli.config.js:

var path = require("path");
const metroBundler = require('metro-bundler');

var config = {
  extraNodeModules: {
    "react-native": path.resolve(__dirname, "node_modules/react-native"),
    "react": path.resolve(__dirname, "node_modules/react"),
  },
  getProjectRoots() {
    return [
      // Keep your project directory.
      path.resolve(__dirname),
      path.resolve(__dirname, "../native"), // path to the external module
    ];
  }
}
module.exports = config;

@pankaj-arunsingh - post to https://github.com/facebook/metro-bundler and be sure to fill out their issue template if you think this should be easier or whatever! @roblafeve's solution works

In case anyone is stuck with this and until the different issues are fixed, I made a little guide on how to use yarn workspaces with Create React App and Create React Native App (Expo) to share common code across. Hope you find it handy! https://learn.viewsdx.com/how-to-use-yarn-workspaces-with-create-react-app-and-create-react-native-app-expo-to-share-common-ea27bc4bad62~~ https://medium.com/viewsdx/how-to-use-yarn-workspaces-with-create-react-app-and-create-react-native-app-expo-to-share-common-ea27bc4bad62

@dariocravero your link didn't work ..
But i found it tru the research on medium. Here's the URL that works for me:
https://medium.com/viewsdx/how-to-use-yarn-workspaces-with-create-react-app-and-create-react-native-app-expo-to-share-common-ea27bc4bad62

Thanks @jonasdumas, we unlinked that domain from medium and I forgot to update the link here!

@dariocravero I got it working using your guide, however the nature of my project requires using a classic react-native project. After ejecting are their some steps to get things working?

Let me know thanks!

@dariocravero and anyone using his crna-make-symlinks-for-yarn-workspaces module, if you are running a classic react native project(or a ejected crna project) you can remove link('expo', root, from); from the script to prevent errors on a second call of it. I am personally running the script on every react-native start so that I don't have to worry about it. Without making that change I would get yelled at.

@roblafeve your solution is working!!!
I add "node_modules/redux" in extraNodeModules, it work very well!!!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iRoachie picture iRoachie  路  5Comments

scf4 picture scf4  路  5Comments

mwq27 picture mwq27  路  5Comments

FezVrasta picture FezVrasta  路  3Comments

andyvanosdale picture andyvanosdale  路  3Comments