loading...
Cover image for Tutorial: How to share code between iOS, Android & Web using React Native, react-native-web and monorepo

Tutorial: How to share code between iOS, Android & Web using React Native, react-native-web and monorepo

brunolemos profile image Bruno Lemos Updated on ・9 min read

Let's make our react-native app work in the browser, the right way.

This tutorial was made for react-native <= 0.61. If you are using a newer version, I recommend that you fork this repository instead: brunolemos/react-native-web-monorepo, I am keeping it updated 🙌


Why am I writing this?

Hi 👋 I'm Bruno Lemos. I recently launched a project called DevHub - TweetDeck for GitHub and one of the things that caught people's attention was the fact that it is an app made by a single developer and available on 6 platforms: Web (react-native-web), iOS (react native), Android (react native), macOS, Windows and Linux (electron, for now), with almost 100% code sharing between them. It even shares some code with the server! This is something that would require a team of 3+ until a couple years ago.

Since then, I've received dozens of tweets and private messages asking how to achieve the same and in this tutorial I'll walk you through it.

What's react-native-web?

If you are not familiar with react-native-web, it's a lib by Necolas (ex Twitter engineer) to make your React Native code render in the browser. Roughly speaking, you will write <View /> and it will render <div />, making sure all styles render the exact same thing. It does more than that, but let's keep it simple.

The new Twitter was created using this technology and it's awesome.

If you already know react-native, you don't need to learn any new syntax. It's the same API.


Summary

  • Starting a new React Native project
  • Turning our folder structure into a monorepo
  • Making react-native work in a monorepo
  • Sharing code between our monorepo packages
  • Creating a new web project using create-react-app and react-native-web
  • Making CRA work inside our monorepo with code sharing
  • ???
  • Profit

Step-by-step tutorial

Starting a new React Native project

  • $ react-native init myprojectname
  • $ cd myprojectname
  • $ git init && git add . -A && git commit -m "Initial commit"

Note: It's much easier to create a cross platform app from scratch than trying to port an existing mobile-only (or even harder: web-only) project, since they may be using lot's of platform specific dependencies.

EDIT: If you use expo, it seems they will soon have built in support for web!

Turning our folder structure into a monorepo

Monorepo means having multiple packages in a single repository so you can easily share code between them.  It's a bit less trivial than it sounds because both react-native and create-react-app require some work to support monorepo projects. But hey, at least it's possible!

We'll use a feature called Yarn Workspaces for that.
Requirements: Node.js, Yarn and React Native

  • Make sure you are at the project root folder
  • $ rm yarn.lock && rm -rf node_modules
  • $ mkdir -p packages/components/src packages/mobile packages/web
  • Move all the files (except .git) to the packages/mobile folder
  • Edit the name field on packages/mobile/package.json from packagename to mobile
  • Create this package.json at the root directory to enable Yarn Workspaces:
{
  "name": "myprojectname",
  "private": true,
  "workspaces": {
    "packages": [
      "packages/*"
    ],
    "nohoist": []
  }
  "dependencies": {
    "react-native": "0.61.3"
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Create a .gitignore at the root directory:
.DS_Store
.vscode
node_modules/
yarn-error.log
Enter fullscreen mode Exit fullscreen mode
  • $ yarn

Making react-native work in a monorepo

  • Check where react-native got installed. If it was at /node_modules/react-native, all right. If it was at /packages/mobile/node_modules/react-native, something is wrong. Make sure you have the latest versions of node and yarn. Also make sure to use the exact same version of dependencies between the monorepo packages, e.g. "react": "16.11.0" on both mobile and components, not a different version between them.

  • Open your favorite editor and use the Search & Replace feature to replace all occurrences of node_modules/react-native/ with ../../node_modules/react-native/.

  • For react-native <= 0.59, open packages/mobile/package.json. Your start script currently ends in /cli.js start. Append this to the end: --projectRoot ../../.

  • Open packages./mobile/metro.config.js and set the projectRoot field on it as well so it looks like this:

const path = require('path')

module.exports = {
  projectRoot: path.resolve(__dirname, '../../'),
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: false,
      },
    }),
  },
}
Enter fullscreen mode Exit fullscreen mode
  • [Workaround] You currently need to add the react-native dependency to the root package.json to be able to bundle the JS:
  "dependencies": {
    "react-native": "0.61.3"
  },
Enter fullscreen mode Exit fullscreen mode

iOS changes

  • $ open packages/mobile/ios/myprojectname.xcodeproj/
  • Open AppDelegate.m, find jsBundleURLForBundleRoot:@"index" and replace index with packages/mobile/index
  • Still inside Xcode, click on your project name on the left, and then go to Build Phases > Bundle React Native code and Images. Replace its content with this:
export NODE_BINARY=node
export EXTRA_PACKAGER_ARGS="--entry-file packages/mobile/index.js"
../../../node_modules/react-native/scripts/react-native-xcode.sh
Enter fullscreen mode Exit fullscreen mode
  • $ yarn workspace mobile start

You can now run the iOS app! 💙 Choose one iPhone emulator and press the "Run" triangle button inside Xcode.

image

Android changes

  • $ studio packages/mobile/android/
  • Open packages/mobile/android/app/build.gradle. Search for the text project.ext.react = [...]. Edit it so it looks like this:
project.ext.react = [
    entryFile: "packages/mobile/index.js",
    root: "../../../../"
]
Enter fullscreen mode Exit fullscreen mode
  • Android Studio will show a Sync Now popup. Click on it.
  • Open packages/mobile/android/app/src/main/java/com/myprojectname/MainApplication.java. Search for the getJSMainModuleName method. Replace index with packages/mobile/index, so it looks like this:
@Override
protected String getJSMainModuleName() {
  return "packages/mobile/index";
}
Enter fullscreen mode Exit fullscreen mode

If you get the Cannot get property 'packageName' on null object error, try disabling auto linking

You can now run the Android app! 💙 Press the "Run" green triangle button inside Android Studio and choose the emulator or device.

image

Sharing code between our monorepo packages

We've created lots of folders in our monorepo, but only used mobile so far. Let's prepare our codebase for code sharing and then move some files to the components package, so it can be reused by mobile, web and any other platform we decide to support in the future (e.g.: desktop, server, etc.).

  • Create the file packages/components/package.json with the following contents:
{
  "name": "components",
  "version": "0.0.1",
  "private": true
}
Enter fullscreen mode Exit fullscreen mode
  • [optional] If you decide to support more platforms in the future, you'll do the same thing for them: Create a packages/core/package.json, packages/desktop/package.json, packages/server/package.json, etc. The name field must be unique for each one.

  • Open packages/mobile/package.json. Add all the monorepo packages that you are using as dependencies. In this tutorial, mobile is only using the components package:

"dependencies": {
  "components": "0.0.1",
  ...
}
Enter fullscreen mode Exit fullscreen mode
  • Stop the react-native packager if it's running
  • $ yarn
  • $ mv packages/mobile/App.js packages/components/src/
  • Open packages/mobile/index.js. Replace import App from './App' with import App from 'components/src/App'. This is the magic working right here. One package now have access to the others!
  • Edit packages/components/src/App.js, replace Welcome to React Native! with Welcome to React Native monorepo! so we know we are rendering the correct file.
  • $ yarn workspace mobile start

Yay! You can now refresh the running iOS/Android apps and see our screen that's coming from our shared components package. 🎉

  • $ git add . -A && git commit -m "Monorepo"

Web project

Note: You can reuse up to 100% of the code, but that doesn't mean you should. It's recommended to have some differences between platforms to make them feel more natural to the user. To do that, you can create platform-specific files ending with .web.js, .ios.js, .android.js or .native.js. See example.

Creating a new web project using CRA and react-native-web

  • $ cd packages/
  • $ npx create-react-app web
  • $ cd ./web (stay inside this folder for the next steps)
  • $ rm src/* (or manually delete all files inside packages/web/src)
  • Make sure the dependencies inside package.json are the exact same between all monorepo packages. For example, update the "react" version to "16.9.0" (or any other version) on both web and mobile packages.
  • $ yarn add react-native-web react-art
  • $ yarn add --dev babel-plugin-react-native-web
  • Create the file packages/web/src/index.js with the following contents:
import { AppRegistry } from 'react-native'

import App from 'components/src/App'

AppRegistry.registerComponent('myprojectname', () => App)
AppRegistry.runApplication('myprojectname', {
  rootTag: document.getElementById('root'),
})
Enter fullscreen mode Exit fullscreen mode

Note: when we import from react-native inside a create-react-app project, its webpack config automatically alias it to react-native-web for us.

  • Create the file packages/web/public/index.css with the following contents:
html,
body,
#root,
#root > div {
  width: 100%;
  height: 100%;
}

body {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
Enter fullscreen mode Exit fullscreen mode
  • Edit packages/web/public/index.html to include our CSS before closing the head tag:
...
<title>React App</title>
<link rel="stylesheet" href="%PUBLIC_URL%/index.css" />
</head>
Enter fullscreen mode Exit fullscreen mode

Making CRA work inside our monorepo with code sharing

CRA doesn't build files outside the src folder by default. We need to make it do it, so it can understand the code from our monorepo packages, which contains JSX and other non-pure-JS code.

  • Stay inside packages/web/ for the next steps
  • Create a .env file (packages/web/.env) with the following content:
SKIP_PREFLIGHT_CHECK=true
Enter fullscreen mode Exit fullscreen mode
  • $ yarn add --dev react-app-rewired
  • Replace the scripts inside packages/web/package.json with this:
"scripts": {
  "start": "react-app-rewired start",
  "build": "react-app-rewired build",
  "test": "react-app-rewired test",
  "eject": "react-app-rewired eject"
},
Enter fullscreen mode Exit fullscreen mode
  • Create the packages/web/config-overrides.js file with the following contents:  
const fs = require('fs')
const path = require('path')
const webpack = require('webpack')

const appDirectory = fs.realpathSync(process.cwd())
const resolveApp = relativePath => path.resolve(appDirectory, relativePath)

// our packages that will now be included in the CRA build step
const appIncludes = [
  resolveApp('src'),
  resolveApp('../components/src'),
]

module.exports = function override(config, env) {
  // allow importing from outside of src folder
  config.resolve.plugins = config.resolve.plugins.filter(
    plugin => plugin.constructor.name !== 'ModuleScopePlugin'
  )
  config.module.rules[0].include = appIncludes
  config.module.rules[1] = null
  config.module.rules[2].oneOf[1].include = appIncludes
  config.module.rules[2].oneOf[1].options.plugins = [
    require.resolve('babel-plugin-react-native-web'),
  ].concat(config.module.rules[2].oneOf[1].options.plugins)
  config.module.rules = config.module.rules.filter(Boolean)
  config.plugins.push(
    new webpack.DefinePlugin({ __DEV__: env !== 'production' })
  )

  return config
}
Enter fullscreen mode Exit fullscreen mode

The code above overrides some create-react-app's webpack config so it includes our monorepo packages in CRA's build step

  • $ git add . -A && git commit -m "Web project"

That's it! You can now run yarn start inside packages/web (or yarn workspace web start at the root directory) to start the web project, sharing code with our react-native mobile project! 🎉

image

Some gotchas

  • react-native-web supports most of the react-native API, but a few pieces are missing like Alert, Modal, RefreshControl and WebView;
  • If you come across a dependency that doesn't work well with the monorepo structure, you can add it to the nohoist list;

Some tips

  • Navigation may be a bit of a challenge; you can use something like react-navigation which recently added web support or you can try using two different navigators between and mobile, in case you want the best of both worlds by compromising some code sharing;
  • If you plan sharing code with the server, I recommend creating a core package that only contain logic and helper functions (no UI-related code);
  • For Next.js, you can check their official example with react-native-web
  • For native windows, you can try react-native-windows;
  • For native macOS, you can the new Apple Project Catalyst, but support for it is not 100% there yet (see my tweet);
  • To install new dependencies, use the command yarn workspace components add xxx from the root directory. To run a script from a package, run yarn workspace web start, for example; To run a script from all packages, run yarn workspaces run scriptname;

Thanks for reading! 💙

If you like react, consider following me here on Dev.to and on Twitter.


Links

Discussion

pic
Editor guide
Collapse
bantinggamer profile image
bantingGamer

HELP! something changed and i cannot replicate this tutorial anymore. i cannot get past the first time you are testing android studio. I remember something like --version react-native@next that is now missing from this tutorial. and now i cannot replicate it at all some one please help.

this is now the 7th time im following the instructions and i get this error first time i try test in the android simulator after trying to create monorepo

Unable to resolve module `./packages/mobile/index

Collapse
brunolemos profile image
Bruno Lemos Author

Hi, I updated the tutorial with the latest changes from react-native@0.59, search for projectRoot to see the updated step involving the file metro.config.js.

Collapse
bantinggamer profile image
bantingGamer

thank you so much for the new changes in the tutorial. i made the changes to the metro.config.js just like you suggested and i can now run it on android. i will continue with the rest of the tutorial in the morning.

Collapse
bantinggamer profile image
bantingGamer

Hey Bruno how are you?

Im still running into a issue. Soon as i complete the web section of the tutorial. my mono repo breaks for mobile. it installs all the modules in packages/mobile/node-modules instead of root/node_modules.

Thus when I run packages/mobile/yarn start i get the following error
"Error: Cannot find module 'E:\2019_PROJECTS\moco-messenger-project\code\repo\test\node_modules\react-native\local-cli\cli.js'"

I dont understand how the web project is affecting the mobile project. Please assist.

kind regards

Thread Thread
brunolemos profile image
Bruno Lemos Author

Make sure you have the correct content inside the root package.json and you used yarn at the root directory to install the dependencies, not inside each package neither npm instead of yarn.

Compare your code with the repository to see if anything is different: github.com/brunolemos/react-native...

Thread Thread
bantinggamer profile image
bantingGamer

hey bruno,

I just did like you said, I even upgraded react-native to v0.59.0 stable. yet still when i run yarn in the root it still installs packages/mobile/node-modules and not in root/node_modules.

how can i compare an entire project with difference in vs code? are you sure there isnt a step missing? I have tried 3 times now following your exact instructions.

Thread Thread
brunolemos profile image
Bruno Lemos Author

Do you have the latest version of nodejs and yarn? How is your root package.json?

Thread Thread
bantinggamer profile image
bantingGamer

I just checked on my computer, im running yarn 1.130 and node v10.0.0 i believe those are the latest versions.

my root package.json file looks exactly like yours.

{
"name": "myprojectname",
"version": "0.0.1",
"private": true,
"workspaces": {
"packages": [
"packages/*"
]
}
}

like i said im extremely confused becasue i dont understand why the monorepo breaks when i add the web

Thread Thread
bantinggamer profile image
bantingGamer

i just downloaded your project at
github.com/brunolemos/react-native... and when i run yarn in the root it is also installing the packages in the wrong places.

Thread Thread
rynatk profile image
Ryan Atkinson

Hey everyone, I downloaded the project, followed the updated tutorial and ran into the same exact issue. I got /mobile running again by updating the relative filepath in its package.json to the react-native-cli:

"scripts": {
    "start": "node ./node_modules/react-native/local-cli/cli.js start",
    "test": "jest"
  },

good luck!

Thread Thread
brunolemos profile image
Bruno Lemos Author

Hey, you both were right! React Native started getting installed inside packages/mobile/node_modules, which is wrong. Changing the path is not the right solution though.

I investigated and you need to make sure all your dependencies have the exact same version between the monorepo packages. For example, change your "react" dependency inside the mobile and web's package.json to the exact same version (e.g. 16.8.4).

This will make react-native get installed in the root node_modules again and also prevent multiple instances of react being installed in the same project, which would cause all kinds of bugs.

Updated the tutorial and also the repository: github.com/brunolemos/react-native...

Collapse
vntravelbag profile image
Vietnam Travel Bag

Hi Bruno,

How to use 3rd lib, I want to add react-native-element package.
It's work well on mobile, but when I run web app, it's error below:

Support for the experimental syntax 'classProperties' isn't currently enabled (41:23):

  39 | 
  40 | export default class SwipeRating extends Component {
> 41 |   static defaultProps = {
     |                       ^
  42 |     type: 'star',
  43 |     ratingImage: require('./images/star.png'),
  44 |     ratingColor: '#f1c40f',

Add @babel/plugin-proposal-class-properties (https://git.io/vb4SL) to the 'plugins' section of your Babel config to enable transformation.

Here's what I added to config-override.js on packages/web

const appIncludes = [
  ...
  resolveApp('../../node_modules/react-native-elements'),
  resolveApp('../../node_modules/react-native-vector-icons'),
]

module.exports = function override(config, env) { 
  ...
  config.module.rules[2].oneOf[1].options.plugins = [
    require.resolve('babel-plugin-react-native-web'),
    require.resolve('@babel/plugin-proposal-class-properties'),
  ].concat(config.module.rules[2].oneOf[1].options.plugins)
  ...
}

In future, I will add react-navigation and some other packages.
Please help, many thanks!

Collapse
brunolemos profile image
Bruno Lemos Author

Did you make it work?

I haven't tried your code but yes, changing config-override.js correctly should be enough.

Collapse
nishcooly profile image
Nishant Koli

Was anyone able to add react-navigation to the project? I got react-native-elements working by following the above comment.

Here's a working example for React-Navigation with web :
github.com/react-native-elements/r...

Thank for documenting all this work thoroughly.
As a React-Native noob, this guide was very easy to follow along ! Cheers!

Thread Thread
nishcooly profile image
Nishant Koli

I got react-navigation's drawer working on the web.

The following is my config-override.js

const fs = require('fs')
const path = require('path')
const webpack = require('webpack')

const appDirectory = fs.realpathSync(process.cwd())
const resolveApp = relativePath => path.resolve(appDirectory, relativePath)

// our packages that will now be included in the CRA build step
const appIncludes = [
  resolveApp('src'),
  resolveApp('../components/src'),
  resolveApp('../../node_modules/@react-navigation'),
  resolveApp('../../node_modules/react-navigation'),
  resolveApp('../../node_modules/react-native-uncompiled'),
  resolveApp('../../node_modules/react-native-elements'),
  resolveApp('../../node_modules/react-native-gesture-handler'),
  resolveApp('../../node_modules/react-native-ratings'),
  resolveApp('../../node_modules/react-native-screens'),
  resolveApp('../../node_modules/react-native-tab-view'),
  resolveApp('../../node_modules/react-native-vector-icons'),
  resolveApp('../components/libraries/MSALAuthLogin'),
  resolveApp('../../node_modules/react-native-vector-icons'),

]

module.exports = function override(config, env) {
  // allow importing from outside of src folder
  config.resolve.plugins = config.resolve.plugins.filter(
    plugin => plugin.constructor.name !== 'ModuleScopePlugin'
  )
  config.module.rules[0].include = appIncludes
  config.module.rules[1] = null
  config.module.rules[2].oneOf[1].include = appIncludes
  config.module.rules[2].oneOf[1].options.plugins = [
    require.resolve('babel-plugin-react-native-web'),
    require.resolve('@babel/plugin-proposal-class-properties'),
  ].concat(config.module.rules[2].oneOf[1].options.plugins)
  config.module.rules = config.module.rules.filter(Boolean)
  config.plugins.push(
    new webpack.DefinePlugin({ __DEV__: env !== 'production' })
  )

  return config
}

Thread Thread
devozs profile image
Oz Shemesh

thanks for the input
i am facing similar issue while using GoogleSigninButton from react-native-google-signin.

i tried adding require.resolve('@babel/plugin-proposal-class-properties') as you suggested below.

also tried to update babel.config.js with the following, didnt worked as well...
module.exports = {
plugins: [
[
'@babel/plugin-proposal-decorators',
{
legacy: true,
},
],
[
'@babel/plugin-proposal-class-properties',
{
loose: true,
},
],
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-transform-regenerator',
[
'@babel/plugin-transform-runtime',
{
helpers: false,
regenerator: true,
},
],
],
presets: ['@babel/preset-flow', 'module:metro-react-native-babel-preset'],
}

also tried with loose: true
require.resolve('@babel/plugin-proposal-class-properties', {
loose: true,
}),

any suggestion please?

thanks for you time.

Thread Thread
nishcooly profile image
Nishant Koli

Hi Oz, were you able to make it run? Did you try with a compatible release (any before 0.60)?

Thread Thread
devozs profile image
Oz Shemesh

Hi Nishant,

Unfortunately I was not able to solve it.
I am not sure about earlier versions but I went over many possible suggestions, none of them worked...
Any additional idea that I can try?

Thanks for the reply

Thread Thread
raajnadar profile image
Rajendran Nadar

Use this config to fix the issue

config.module.rules.push(
    {
        test: /\.js$/,
        use: {
            loader: 'babel-loader',
            options: {
                // Disable reading babel configuration
                babelrc: false,
                configFile: false,

                // The configration for compilation
                presets: [
                    '@babel/preset-env',
                    '@babel/preset-react',
                    '@babel/preset-flow'
                ],
                plugins: [
                    '@babel/plugin-proposal-class-properties',
                    '@babel/plugin-proposal-object-rest-spread'                  
               ]
            }
        }
    }
)

Add the above code before the return config line

Thread Thread
devozs profile image
Oz Shemesh

Thanks Rajendran

i tried adding the above as part of config-overrides.js
it didn't helped.

BTW, i`ve executed 'sudo yarn add @react-native-community/google-signin'

Under the folder 'react-native-web-monorepo/packages/components'
Is that the right location?

Thanks, Oz

Thread Thread
devozs profile image
Oz Shemesh

An update...
i had to add two more dev dependencies under the web module.
sudo yarn add --dev babel-loader
sudo yarn add --dev @babel/preset-flow

now i am getting different error:
/react-native-web-monorepo/node_modules/@react-native-community/google-signin/src/GoogleSigninButton.js
Attempted import error: 'requireNativeComponent' is not exported from 'react-native'.

Collapse
karvulf profile image
karvulf

With the react-native-version 0.60.4, I have some problems with libhermes.
When starting the android-app, it crashes and I always get the message: E/SoLoader: couldn't find DSO to load: libhermes.so. Any suggestions what to do?

Edit: Fixed my problem. You have to enable hermes, so that it looks like this in your build.gradle in app:
project.ext.react = [
entryFile: "packages/mobile/index.js",
root: "../../../../",
enableHermes: true, // clean and rebuild if changing
]

Collapse
rafaelje profile image
Rafael Jesus Hernández Vasquez

This works for me thanks!

Collapse
proof666 profile image
Sergey Pushkin

You can run debug session from vscode with React Native Tools extension. But with monorepo its little hacky... btw, read-native run-its --project-path "./packages/mobile/ios" also work

I setup only iOS project with macos: you need to specify "runArguments": ["--project-path", "./packages/mobile/ios"] in debug task in launch.json and symlink with command:

ln -s /Users/proof666/Desktop/Projects/ShopList_new/PaperList/packages/mobile/ios  /Users/proof666/Desktop/Projects/ShopList_new/PaperList/ios

~if somebody already setup android debug, please ping me~
Update:
in vscode task for android add

...
"runArguments": ["--root", "./packages/mobile"] 
Collapse
brunolemos profile image
Bruno Lemos Author

Thanks for sharing!

Collapse
ziaulrehman40 profile image
Zia Ul Rehman

Hi Bruno, thanks for the awesome detailed tutorial with all the updates. And i can see you are very active in comments also which is awesome!

Its really nice to see react's progress towards PWA and cross platform portability.

I am following this tutorial to convert our old add(on Rn 0.59) over to react-native web. I followed this tutorial and setup everything up.
Than i copied the dependencies from our mobile repo's package json to packages/components/package.json. And all other code respectively in src. Idea was to get everything running on ios in this monorepo setup and than go from there to fix whatever needs to be fixed for web.

But i am getting some errors like first i got:

bundling failed: Error: Unable to resolve module path from /Users/..../projec/node_modules/react-native-dotenv/index.js: Module path does not exist in the Haste module map

Fixed it by adding path explicitly in dev-dependencies. Than started getting error:

bundling failed: Error: While trying to resolve module fs from file /Users/..../projec/node_modules/babel-plugin-dotenv/index.js, the package /Users/..../projec/node_modules/fs/package.json was successfully found. However, this package itself specifies a main module field that could not be resolved (/Users/..../projec/node_modules/fs/index.js. Indeed, none of these files exist

I am not very experienced in react and react-native, i am mainly on Ruby on Rails, so maybe this is something basic which i am getting wrong.
I found: stackoverflow.com/a/39046690/4738391 which suggests omething wrong with node environment or something. But i am a bit confused, i mean i can add these dependencies etc but it should work out of the box for mobile, as it was working fine in previous repo.

Any help will be greatly appreciated. Thanks.

Collapse
ziaulrehman40 profile image
Zia Ul Rehman

After cache clean and everything, second error changed to:
error: bundling failed: Error: While trying to resolve module fs from file /Users/..../projec/node_modules/babel-plugin-dotenv/index.js, the package /Users/..../projec/node_modules/fs/package.json was successfully found. However, this package itself specifies a main module field that could not be resolved (/Users/..../projec/node_modules/fs/index.js. Indeed, none of these files exist

Collapse
cjam profile image
Colter McQuay

I was running into the same issue and I think I figured out the cause of the problem. I unfortunately don't know how to fix it. It seems to be related to react-native-cli not being able to locate the metro and babel configs because it's being run from the root of the repository.

Since they aren't found, when the bundler comes across react-native-dotenv within a source file it will actually import the source file rather than using the replacement provided by the babel plugin.

Collapse
ziaulrehman40 profile image
Zia Ul Rehman

This was a stupid error, i had forgot to add 'module:react-native-dotenv' in my babel config presets. Adding it solved the problem and i got my mobile app compiled. There were some imports fixes etc in scode needed to be done to run app successfully. But that is done.

But now next errors(on web), i posted this SO question: stackoverflow.com/questions/571953...

If i can get any help, would be great.

Collapse
brunolemos profile image
Bruno Lemos Author

Please remove all node_modules folders and .lock files from your project, clear all caches (xcode, —reset-cache, etc), and try following the steps again. Maybe you missed something.

You shouldn’t remove the dependencies from mobile. Check this repo source code and commit diffs: github.com/brunolemos/react-native...

After running yarn to install dependencies, check the contents of packages/mobile/node_modules, and let me know which folders it has. It shouldn’t have any, all should be in the root node_modules.

If nothing works, maybe they released a new version of the cli that broke something, in that case you can use a previous version or investigate the change.

Collapse
ziaulrehman40 profile image
Zia Ul Rehman

I think i was not clear in my comment, actually it did work with barebone setup as described in this post. It was working perfectly, than i started exporting my mobile code, that's when it exploded.

I wanted to just have mobile app running as it is in this architecture. Than move un-convertable code to mobile and write replacement code for only those in web. But my mobile app is not running with these errors.

I did all the cache clear and everything but same issue. mobile repo's node_modules folder have 2 folder, .bin and metro-react-native-babel-preset.

I am pretty sure it is some of my mobile dependency. I don't know if i should share the package json etc and everything here. It will just get annoyingly long here.

Let me know if i should share that here, or i can reach you through some other medium.

I do understand this blog post is like THE go to blog right now for new projects which want to take this route. but porting old projects is a lot more messy. If i do succeed in porting my app on this architecture and support web, i will leave pointers and can also write an extension of this blog post.

Collapse
shubhamsinha profile image
Shubham Sinha
scripts: {
  "start": "node ../../node_modules/react-native/local-cli/cli.js start --projectRoot ../../"
}

throws error error: unknown option `--projectRoot'

On modifying --projectRoot to --projectRoots I get following error

Loading dependency graph...jest-haste-map: Watchman crawl failed. Retrying once with node crawler.

Collapse
brunolemos profile image
Bruno Lemos Author

You mean when trying to use jest? If not please check the repository to see what you made differently.

Collapse
shubhamsinha profile image
Shubham Sinha

Sorry, I modified my comment. I am getting an error with --projectRoot. I was trying on my own repo. I'll be cloning your repo and then let you know if the problem persists.

Thread Thread
brunolemos profile image
Bruno Lemos Author

I'm using the unreleased react-native 0.59 in this tutorial, some dependencies got a major bump so maybe there are some differences if you are using an older version.

Collapse
asmakhalfallah2018 profile image
AsmaGithub

did you find an alternative for --projectRoot please ?

Collapse
zhigang1992 profile image
Zhigang Fang

Really great stuff, we learn a lot!

Here is what we wrote on somewhat the same topic.

reily.app/posts/2019-02-25/firebas...

It was too much trouble to set up both Android, iOS and their native dependencies in the mono repo structure.

So we decided to just nohoist everything. T_T

Collapse
brunolemos profile image
Bruno Lemos Author

Nice, thanks for the mention in the article!

Were you able to share code between web and mobile using nohoist? I've had problems with this approach in the past but I don't remember exactly why. It has some downsides but it's definitely much simpler to setup. Everything working well for you this way?

Collapse
zhigang1992 profile image
Zhigang Fang

No, sry for taking so long to reply.

Our yarn workspace is just set up to include app / backend / website

And they do not share components.

The problem is that metro does not support symbol links. Which is what yarn workspace uses.

github.com/facebook/metro/issues/1

Collapse
mschipperheyn profile image
Marc Schipperheyn

Having some troubles getting react-native-web hoisted and getting everything to run. It insists on staying inside the web/node_modules together with fbjs and react. I do have some nohoist packages that are linked in the mobile project. I verified all the version numbers. They seem to be aligned

Tried various cleaning actions. I'm getting errors from hoisted elements not being able to find react-native-web shouldn't metro-react-native-babel-preset be implemented as a preset in the web project? This seems to be indicated in react-native-web examples

Collapse
brunolemos profile image
Bruno Lemos Author

You need to use the exact same version of react between all package.json that have it.

Collapse
mschipperheyn profile image
Marc Schipperheyn

Number of issues here:
Changing jsBundleURLForBundleRoot:@"index" to jsBundleURLForBundleRoot:@"packages/mobile/index" leads to resolution errors
Leaving it as it is, leads to @babel/runtime/helpers/interopRequireDefault does not exist in the Haste module map. It looks like the packages/mobile/index reference is the way to go but that the react-native command uses packages/mobile as the ref location instead of the project root. From the root I tried two commands (RN 0.59):

mobile: start => ../../node_modules/.bin/react-native start --reset-cache
root: start => cd ./packages/mobile && yarn start
root: start => yarn workspace mobile start

In both cases, I get "Unable to resolve module ./packages/mobile/index from /Users/me/projects/rnw/packages/mobile/.
[...]
`Indeed, none of these files exist:

  • /Users/me/projects/rnw/packages/mobile/packages/mobile/index

Notice the duplicate packages/mobile reference

Collapse
mschipperheyn profile image
Marc Schipperheyn

Ok, I identified the problem. The packages/mobile/metro.config.js is not processed. The projectRoot remains packages/mobile instead of ``

Collapse
xoagop profile image
Anna Fröblom

Hi,

I'm facing the same problem. Did you manage to solve why the metro.config.js wasn't processed?

Thread Thread
brunolemos profile image
Bruno Lemos Author

Current solution is to set --projectRoot ../../ at the package.json start script instead of metro.config.js, like it used to be before. Not sure if it's a bug or not.

Collapse
horsepowerbank profile image
Horsepowerbank.com

Hey, thanks for your awesome tutorial. Just a quick question, how can we host the web version of the app? Cause it seem like it share the file inside the packages/component/src folder. I using Docker, is it mean that we need to add all files into the server?

Collapse
brunolemos profile image
Bruno Lemos Author

The web package has a build command, and the result goes to the packages/web/dist folder. You should deploy only the dist folder.

Collapse
horsepowerbank profile image
Horsepowerbank.com

I see.. thanks bro.. thats help a lot

Collapse
meprakashravi profile image
Prakash Ravichandran

Hi Bruno,

Great tutorial. Thanks for sharing.

Is it possible to maintain the each platform code in 3 different repo. Already I am having iOS and Android project. Now i would like to add some modules in react_native and integrate in iOS and Android. The thing is when the iOS and Android are inside the react-native root repo that is working fine. Linking also happening. But when I separate the iOS folder and when try to install the Pod i am getting issue as "cannot find module react_native/cli" in use_native_modules.

Kindly help me.

Collapse
pra3t0r5 profile image
Pra3t0r5

Hi man, absolutely amazing tutorial, my dev team managed to get it up an running in no time.
However, we are facing two problems, one is related to babel plugins, no matter what i did, i could not add the @babel/plugin-transform-react-jsx, therefore the web package crashes:

../commons/pages/tabs/tabs.page.js
SyntaxError: /home/praetors/Projects/node/proyectoSembrar/packages/commons/pages/tabs/tabs.page.js: Support for the experimental syntax 'jsx' isn't currently enabled (16:9):

  14 | const dummyTab = () => {
  15 |     return (
> 16 |         <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
     |         ^
  17 |             <Text>Test</Text>
  18 |         </View>
  19 |     );

Add @babel/plugin-transform-react-jsx (https://git.io/vb4yd) to the 'plugins' section of your Babel config to enable transformation.
Enter fullscreen mode Exit fullscreen mode

The other problem comes with react-native-vector-icons: ^7.0.0, we added the:

apply from: "../../../../node_modules/react-native-vector-icons/fonts.gradle"
Enter fullscreen mode Exit fullscreen mode

but we could not get them to render in android, instead it shows the crossed box, here is how we implemented it:

import Icon from 'react-native-vector-icons/Ionicons';

export default function Tabs() {
    return (
        <Tab.Navigator
           //...
            screenOptions={({ route }) => ({
                tabBarIcon: ({
                    focused, color, size
                }) => {
                    let iconName;
                    switch (route.name) {
                        case 'Inicio':
                            iconName = focused ? 'ios-home' : 'ios-home-outline';
                            break;
                    //...
                    }
                    return <Icon name={iconName} size={size} color={color} />;
                }
            })}>
            <Tab.Screen name="Inicio" component={Home} />
             //...
        </Tab.Navigator>
    )
}
Enter fullscreen mode Exit fullscreen mode
Collapse
andreimelo profile image
Andrei Melo

try this, please see the following :
step

  1. npm install @babel/plugin-transform-react-jsx or yarn add @babel/plugin-transform-react-jsx

  2. go to config-overrides.js : Then add the package installed to plugins...
    please see below,

const fs = require('fs');
const path = require('path');
const webpack = require('webpack');

const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);

// our packages that will now be included in the CRA build step
const appIncludes = [
resolveApp('src'),
resolveApp('../common/src'),
resolveApp('../../node_modules/@react-navigation'),
resolveApp('../../node_modules/react-navigation'),
resolveApp('../../node_modules/react-native-gesture-handler'),
resolveApp('../../node_modules/react-native-screens'),
];

module.exports = function override(config, env){
config.module.rules.push({
test : /.(js|mjs|tsx|ts)$/,
exclude : /@babel(?:\/|\{1,2})runtime/,
use : {
loader : 'babel-loader',
options : {
babelrc : false,
configFile : false,
compact : false,
// The configration for compilation
presets : [
[
'module:metro-react-native-babel-preset',
], // Add this line,
[
require.resolve('babel-preset-react-app/dependencies'),
{ helpers: true },
],
],
cacheDirectory : true,
plugins : [
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-transform-flow-strip-types',
'@babel/plugin-transform-react-jsx'
[
'module-resolver',
{
alias : {
'^react-native$' : 'react-native-web',
},
},
],
],
},
},
});
return config;
};

thanks

Collapse
andreimelo profile image
Andrei Melo

paste it to *config-overrides.js

Collapse
mjstelly profile image
Michael Stelly

I recently worked on a project which used monorepo. It was my first introduction to it. I must say, I was not impressed. But hear me out. I've worked in the mobile app industry for over 10 years. I've seen architectures come and go.

Conceptually, I understand the use case for implementing such a design. In practice, I found it unintuitive, incredibly confusing, and slowed my project onboarding process to a crawl. I had six weeks to perform the job for which I was hired. The first week was spent wrapping my head around how to simply walk through the workflows. That cost the client a lot of money and reduced my available billable time by 20%. Imagine what would happen if the client had to onboard a less-experienced dev.

To be fair, there are a lot of unknowns here. It was my first hands-on with the design. Maybe the client's architect built it incorrectly? Would my experience have improved had the repo been better documented, i.e. had any doc at all? I don't really know.

I'm off that project and on my way to others. I will withhold judgment for now because this project could've been a fluke. I just wanted to interject my experience. For any non-trivial project, it's important for readers to remember that the business drives technology decisions. If a monorepo design pattern solves the particular business requirement, then I hope this tutorial helps you jumpstart your project.

Collapse
vegtelenseg profile image
BrandNew

Hello,

Thank you so much for the article.

I have pulled down your repo, installed the deps and ran it. Metro bundler runs well but I do not see anything on the emulators.

Is there a step that I am missing?

Thanks

Siya

Collapse
brunolemos profile image
Bruno Lemos Author

To run the mobile apps you can open Xcode/Android Studio and press the Run button.

Collapse
vegtelenseg profile image
BrandNew

Yeah, I realised that is how you were running it. I am a fan of the terminal, so I prefer that way. But for some reason I thought that running the bundler would mount the project into the emulator. Thank you so much for the article, I found it very helpful.

How did you configure auto reloading?

Thanks

Collapse
jasonivers profile image
Jason

When I use "yarn start", my web app works pretty much exactly the way it should. If I use "yarn build", and then "serve -s build", however, it gives me an error for createBrowserApp:

AppNavigator.ts:99 Uncaught TypeError: Object(...) is not a function

AppNavigator.ts:99 is:

const LoginNavigator = Platform.OS === 'web' ? createBrowserApp(loginStackNavigator) : createAppContainer(loginStackNavigator)

react-navigation, @react-navigation, react-native-gesture-handler, react-native-reanimated, react-native-screens, react-navigation-stack, and @react-navigation/web are all in my main project's package.json, and "brought over" via

resolveApp('../../node_modules/react-navigation'),

I can't figure out why it works via "yarn start", but not on "yarn build". I've spent a while searching, and I can't seem to find an answer. Anyone have any ideas?

Collapse
ericlifs profile image
Eric Lifs

Thanks Bruno for this awesome post!! It was the only way I was able to make react-native work within a monorepo structure.

Currently I am working on a web + ios + tvos app and I was wondering how should I configure the tvos app since it react-native relies on npm:react-native-tvos@0.62.2-0. Following your tutorial I have:

1) Added 'react-native' and 'react-native/**' into tv package.json noHoist in order to get the react-native stored within the tv package and not use the ios hoisted one.

2) Use your metro.config.js configuration but also added the extraNodeModules in order to override the react-native alias to use the tv package one:

resolver: {
    extraNodeModules: {
      'react-native': path.resolve(__dirname, 'node_modules/react-native'),
    },
  }

3) Change the AppDelegate.m file with your configuration
4) Within the Bundle React Native code and Images section I have added the EXTRA_PACKAGER_ARGS but kept the react-native path as it is in order to use the tv package one:

export NODE_BINARY=node
export EXTRA_PACKAGER_ARGS="--entry-file packages/tv/index.js"
../node_modules/react-native/scripts/react-native-xcode.sh

Is this okay? Am I missing something else?

Thank you very much, your post is awesome <3!

Collapse
js08 profile image
js

Hi,

I downloaded the repo, I am able to run the web app, but I have issue with ios
Can you tell me why I am getting the below issue, I am trying to do pod install inside my ios folder

aal003110384:ios reerer89989823$ pod install

[!] Invalid Podfile file: cannot load such file -- /Users/reerer89989823/Desktop/codebase/Shipment/react-native-web-monorepo-master/packages/mobile/node_modules/@react-native-community/cli-platform-ios/native_modules.

# from /Users/reerer89989823/Desktop/codebase/Shipment/react-native-web-monorepo-master/packages/mobile/ios/Podfile:2
# -------------------------------------------
# platform :ios, '9.0'

require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
#

# -------------------------------------------

Collapse
5ervant profile image
Mark Anthony B. Dungo

Sir, will createBrowserApp(switchNavigator, { history: 'browser' }) work when I host a React Native Web app on GitHub Pages to have such these URLs:

  • username.github.io/Home
  • username.github.io/Links
  • username.github.io/Settings

Is it possible on GitHub Pages with React Native Web?

Collapse
secretmapper profile image
Secretmapper

Hello Bruno, awesome tutorial as I mentioned!

I have another question though, and it's related to builds. I've set the build phase as Release (so I can run it without a server) but I get an error in Xcode:

File /Users/--/Library/Developer/Xcode/DerivedData/project-name/Build/Products/Release-iphoneos/project-name.app/main.jsbundle does not exist. This must be a bug with'

Is there anything special I need to set here to get Xcode to build it?

Collapse
brunolemos profile image
Bruno Lemos Author

No, this error is unrelated to this tutorial. Try cleaning the caches, e.g. Product > Clean and yarn start --reset-cache.

Collapse
secretmapper profile image
Secretmapper

Thank you cheers! I had thought it was something related to the workspace edits. Turns out there's an issue in react-native about github.com/facebook/react-native/i....

Thread Thread
gabrielbull profile image
Gabriel Bull

So how did you fix it? I have the same issue. The GitHub issue link you provided is not working for me :-/

Collapse
devozs profile image
Oz Shemesh

Thanks a lot for this great tutorial.

i`ve probably missing it in the comments but i am not sure what pakage.json i should use for adding additional dependencies.
should i only update the root /package.json
or individually also

  • packages/components/package.json
  • packages/mobile/package.json
  • packages/web/package.json

in addition, only yarn should be used?

Thanks again.

Collapse
brunolemos profile image
Bruno Lemos Author

Yes only yarn because npm doesn’t have the “workspaces” feature.

You’ll add the dependencies in the package that’s using them. Most of it will probably be in the components. Don’t add at the root unless it’s things like lint etc.

Collapse
5ervant profile image
Mark Anthony B. Dungo

Hello Bruno,

1.) Now that Expo for Web was released, what would you recommend?
To setup a monorepo for Mobile and Web packages or to use Expo for Web?
There's also a React Native Web CLI called create-react-native-web-app.

2.) And also could you give some guide how to setup Next.js as a package of this monorepo? Upon running yarn create next-app --example with-react-native-web next, here's the response:

PS C:\Users\USERNAME\Documents\Node.js Projects\Samples\myprojectname\packages> yarn create next-app --example with-react-native-web next
yarn create v1.16.0
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Installed "create-next-app@0.5.9" with binaries:
      - create-next-app
- Downloading files for with-react-native-web example[before-after-hook]: "Hook()" repurposing warning, use "Hook.Collection()". Read more: https://git.io/upgrade-before-after-hook-to-1.4
DEPRECATED (@octokit/rest): `repos.getContent()` is deprecated, use `repos.getContents()`
> Success! Downloaded with-react-native-web files for next

  Installing npm modules:
    react
    react-dom
    next

> Error! Failed to install react, react-dom, next, try again.
undefined
(node:12428) UnhandledPromiseRejectionWarning: Error: yarn installation failed
    at C:\Users\USERNAME\AppData\Local\Yarn\Data\global\node_modules\create-next-app\lib\utils\install.js:39:23
    at processTicksAndRejections (internal/process/task_queues.js:82:5)
(node:12428) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:12428) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are
not handled will terminate the Node.js process with a non-zero exit code.
Done in 17.47s.

Thanks for any response!

Collapse
brunolemos profile image
Bruno Lemos Author

Expo has it's own set of limitations, e.g. I've been using hooks in production since november 2018 and it only arrived in expo may 2019. If you are ok using expo go for it! They seem to be doing great progress.

About next, I don't know what the issue is, try creating the project separately and copy pasting the folder into the monorepo. Otherwise open an issue with them about monorepo support.

Collapse
efabrica profile image
Hugo Leonardo Gomes de Sousa

Olá bruno, baixei a versão mais recente do monorepo, mas está dando esse erro,
sabe dizer porque? e como resolver?

Loading dependency graph, done.
[1] error: bundling failed: Error: Unable to resolve module ../../../commons/reducers/ from E:\sistemasagv\appwmsmobile\app-rf\packages\components\src\screen-mobile\Reducer\index.js: The module ../../../commons/reducers/ could not be found from E:\sistemasagv\a
ppwmsmobile\app-rf\packages\components\src\screen-mobile\Reducer\index.js
. Indeed, none of these files exist:
[1] * E:\sistemasagv\appwmsmobile\app-rf\packages\components\commons\reducers(.native||.android.js|.native.js|.js|.android.json|.native.json|.json|.android.ts|.native.ts|.ts|.android.tsx|.native.tsx|.tsx)
[1] * E:\sistemasagv\appwmsmobile\app-rf\packages\components\commons\reducers\index(.native||.android.js|.native.js|.js|.android.json|.native.json|.json|.android.ts|.native.ts|.ts|.android.tsx|.native.tsx|.tsx)
[1] at ModuleResolver.resolveDependency (E:\sistemasagv\appwmsmobile\app-rf\node_modules\metro\src\node-haste\DependencyGraph\ModuleResolution.js:163:15)
[1] at ResolutionRequest.resolveDependency (E:\sistemasagv\appwmsmobile\app-rf\node_modules\metro\src\node-haste\DependencyGraph\ResolutionRequest.js:52:18)
[1] at DependencyGraph.resolveDependency (E:\sistemasagv\appwmsmobile\app-rf\node_modules\metro\src\node-haste\DependencyGraph.js:283:16)
[1] at Object.resolve (E:\sistemasagv\appwmsmobile\app-rf\node_modules\metro\src\lib\transformHelpers.js:261:42)
[1] at dependencies.map.result (E:\sistemasagv\appwmsmobile\app-rf\node_modules\metro\src\DeltaBundler\traverseDependencies.js:399:31)
[1] at Array.map ()
[1] at resolveDependencies (E:\sistemasagv\appwmsmobile\app-rf\node_modules\metro\src\DeltaBundler\traverseDependencies.js:396:18)
[1] at E:\sistemasagv\appwmsmobile\app-rf\node_modules\metro\src\DeltaBundler\traverseDependencies.js:269:33
[1] at Generator.next ()
at asyncGeneratorStep (E:\sistemasagv\appwmsmobile\app-rf\node_modules\metro\src\DeltaBundler\traverseDependencies.js:87:24)


Collapse
ziaulrehman40 profile image
Zia Ul Rehman

I want to discuss something we are facing after getting a great kickstart from this post. That is responsiveness problem.

We have made significant progress in our journey of converting existing RN apps to RNW. In-fact i am now writing a series of articles on my experience, first one was written last weekend and i plan on writing next this weekend. Here is the first part:
medium.com/@ziaulrehman/part-1-con...

For my use case, i am using a similar approach to this library: github.com/calinortan/react-getscreen it basically adds event handlers which trigger a state change hence re-render whenever screen size crosses one of pre-defined(configurable) widths.
This allows us to add conditional styles etc on some elements, or even hide/show some elements conditionally. This along with Platform.OS === 'web' is basically all we are doing for now. It doesn't look very clean but it works and gives us responsive design.

What techniques have you used(if any) for this? What worked best? And what would you suggest. Thanks.

Collapse
brunolemos profile image
Bruno Lemos Author

I have a custom hook that checks the app dimensions and returns if it’s small/medium/large: github.com/devhubapp/devhub/blob/m...

Besides that, make sure to always use flexbox and percentages where makes sense, not fixed widths in pixels.

Collapse
ziaulrehman40 profile image
Zia Ul Rehman

Yeah similar approach with HOC for class components. I actually just released a small RN component for this(actually my first npm package). npmjs.com/package/react-native-get...

Collapse
arunmenon1975 profile image
Arun Menon

Thanks for the post! I have been able to get it going without any problems using the outlined steps.

I am facing problems however when i try to install 3rd party dependencies after getting the initial setup going. It will be great if the post could be updated with steps on how to install dependencies post setup.

For example i wanted to add react-native-gesture-handler and a few other native libraries but somehow i keep getting some issue or the other. I tried yarn workspace components add react-native-gesture-handler and it installs but i am unable to use it since i get IDE errors about some constants not being found. Similar issues with other libraries as well. Auto-linking somehow doesn't seem to reflect.

Should jettifier be installed and added in the post-install of package.json(and if so which package.json - root or the ones inside the packages) if running commands like yarn workspace mobile start? Basically some tips on how to add 3rd party libraries for both mobile and web will really help. Thanks again for the post - its my first attempt at a monorepo and this post really helped iron out all my initial doubts but i am also obviously making some newbie/rookie mistakes so there are some stumbling blocks to really get started with it.

Collapse
arunmenon1975 profile image
Arun Menon

Ok. so with a few more attempts i got it going for a critical dependency in my packages. I am using the versatile Navigation router (github.com/grahammendick/navigation) for all the routing requirements in all my packages, across all the router's supported platforms (which is basically everything web, mobile, native etc).

After following all the steps in the post i initially installed the router into my equivalent of the components package. I got it to work for the web but, for the react-native implementation, the navigation router has native code for Android and IoS and somehow it wasn't getting auto-linked. The solution was to simply install it to my equivalent of the mobile package and everything seems good! im still not sure of the jettifer post-install step but it should not be an issue i think.

Collapse
thienthaitechnology profile image
Thien Thai Technology Co.,Ltd

root package.json should add "," to end of "workspaces":{...}
like this:
{
"name": "myprojectname",
"private": true,
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": []
},
"dependencies": {
"react-native": "0.61.3"
}
}

Collapse
sasarivera profile image
sasarivera

Hi.

If I understand correctly, the React native and react dependencies should be installed in the root node_modules to avoid having multiples version of the packages in the app.

Does this apply to every dependencies the packages share? (ex. react-native-elements)

Thanks for the guide!

Collapse
brunolemos profile image
Bruno Lemos Author

Yes, all dependencies should be installed at the root node_modules, this way it's less likely you'll face problems. Please note that this doesn't mean putting it in the root package.json -- you put the dependencies at all the packages/xxx/package.json that use this dependency.

Collapse
jcarraway profile image
Rett Carraway

Is the --projectRoot flag a metro config option? trying to set this up with the 0.59.0 release and running into haste map resolution issues for @babel/runtime

Collapse
brunolemos profile image
Bruno Lemos Author

Please refresh the page, I've updated the tutorial a few minutes ago with the new step related to projectRoot. You don't set --projectRoot anymore, you add it to metro.config.js.

Collapse
jcarraway profile image
Rett Carraway

ha - thank you. i had just made and tested the same update and got it working. cheers!

Collapse
koredefashokun profile image
Oluwakorede Fashokun

Thanks, Bruno! I really needed this. Can this be applied to Lerna instead of Yarn Workspaces?

Collapse
brunolemos profile image
Bruno Lemos Author

I've never used Lerna because Yarn Workspaces does all I need, so I don't know the answer. But let us know! 🙌

Collapse
msand profile image
Mikael Sand

Nice article, I have a bit similar example for code sharing between react-native and next.js with react-native-web here: infinidraw.live/

Source: github.com/msand/InfiniDraw
Expo version: github.com/msand/InfiniDrawExpo

But, it's not really clean architecturally, it's a single project rather than separate folders & package.json for web and native, causing some tradeoffs. Been thinking should slit it up a bit similar to this.

Collapse
bantinggamer profile image
bantingGamer

when you say, "You can now run the Android app! 💙" what does that mean? what steps do i take to run the app?

Collapse
brunolemos profile image
Bruno Lemos Author

There is a "Run" green button inside Android Studio that will open the app inside an emulator.

Collapse
bantinggamer profile image
bantingGamer

Thank you so much. I just wanted to make sure that im not missing anything because I couldn't get "react-native run-android" to work.

Thread Thread
scesbron profile image
Sebastien Cesbron

You have several options to make react-native commands work.

  • in the node_modules directory of your package make a symlink to the node_modules/react-native directory from the root of the project because react-native-cli need to find cli.js in node_modules/react-native.
  • prefix your command with yarn or npm : yarn react-native run-android
  • in your package.json file add a script "run-android": "react-native run-android" and then use yarn run-android
Thread Thread
aminlatifi profile image
Amin Latifi

I used second option. However, I am using third party libraries and it cannot resolve these dependencies!

Could not resolve project :react-native-navigation.
Required by:
project :app
> Unable to find a matching configuration of project :react-native-navigation: None of the consumable configurations have attributes.
Could not resolve project :react-native-vector-icons.
Required by:
project :app
> Unable to find a matching configuration of project :react-native-vector-icons: None of the consumable configurations have attributes.

Thread Thread
aminlatifi profile image
Amin Latifi

Solved,
I changed projectDir attribute of library in android/settings.gradle