Cli: Simplify setup for monorepos

Created on 4 Dec 2019  路  14Comments  路  Source: react-native-community/cli

Describe the Feature

On iOS, you need to set PROJECT_ROOT in order to make CLI work in a monorepo. On Android, same set of configuration is required.

Possible Implementations

  • [ ] Get rid of PROJECT_ROOT on iOS because it's not needed anymore
  • [ ] Figure out strategy for Android.

Related Issues


related to https://github.com/react-native-community/cli/issues/865 https://github.com/react-native-community/cli/issues/656

feature request

Most helpful comment

Did anyone got build working with hermes enabled in a monorepo?

I've got hermes to work by telling react where it's files are:
hermesCommand: "/mnt/c/Users/user/WebstormProjects/project/node_modules/hermes-engine/%OS-BIN%/hermes",

This solved the initial issue of not being able to build becasue hermes executable was not found, however with this fix in place build is still failing with:

internal/modules/cjs/loader.js:638
    throw err;
    ^

Error: Cannot find module '/mnt/c/Users/user/WebstormProjects/project/packages/mobile/node_modules/react-native/scripts/compose-source-maps.js'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)
    at Function.Module._load (internal/modules/cjs/loader.js:562:25)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)

> Task :app:bundleReleaseJsAndAssets FAILED

...because it is looking for node_modules folder in wrong location; the correct location is the same as in hermesCommand, /mnt/c/Users/user/WebstormProjects/project/node_modules.

Building works with enableHermes: false, so it only fails with hermes is enabled.

Any suggestion how to get around this?

My full react config from gradle:

project.ext.react = [
  entryFile   : "index.js",
  enableHermes: true,  // clean and rebuild if changing
  hermesCommand: "/mnt/c/Users/user/WebstormProjects/project/node_modules/hermes-engine/%OS-BIN%/hermes",
  cliPath     : "../../node_modules/react-native/cli.js",
]

EDIT:
I figured out that one can also use relative path for hermesCommand, which is a bit different than cliPath. Seems like one has to point hermesCommand 2 levels higher in directory structure (when compared to cliPath):

hermesCommand: "../../../../node_modules/hermes-engine/%OS-BIN%/hermes",

EDIT2 / SOLUTION:
By digging through the source code I found that composeSourceMapsPath config key exists, so my whole react config looks like this:

project.ext.react = [
  entryFile   : "index.js",
  enableHermes: true,  // clean and rebuild if changing
  hermesCommand: "../../../../node_modules/hermes-engine/%OS-BIN%/hermes",
  composeSourceMapsPath: "../../node_modules/react-native/scripts/compose-source-maps.js",
  cliPath     : "../../node_modules/react-native/cli.js",
]

This got me pass the issue with compose-source-maps.js and I think files were successfully processed by hermes. However, there seems to still be an issue with code-push, since build fails with

Error: Cannot find module '/mnt/c/Users/user/WebstormProjects/project/packages/mobile/node_modules"/react-native-code-push/scripts/generateBundledResourcesHash.js'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)
    at Function.Module._load (internal/modules/cjs/loader.js:562:25)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)

...so this time code-push is looking node_modules in wrong location. I think this issue is out of scope here, so I guess I should check Microsoft's github regarding this.

All 14 comments

this is my error when building

Error: Cannot find module '/app/packages/app/node_modules/react-native/cli.js'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:794:15)
    at Function.Module._load (internal/modules/cjs/loader.js:687:27)
    at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)
    at internal/main/run_main_module.js:17:11 {
  code: 'MODULE_NOT_FOUND',
  requireStack: []
}

as it searches for react-native in the wron glocation

I've got this working like this

project.ext.react = [
    entryFile: "index.js",
    bundleInStaging: true,
    devDisabledInStaging: true,
    bundleInAlpha: true,
    devDisabledInAlpha: true,
    enableHermes: false,  // clean and rebuild if changing
+    root: "../../../../"
]

modifying root path on app/build.gradle

but this raised another issue

error Invalid platform "android" selected.
info Available platforms are: "native". If you are trying to bundle for an out-of-tree platform, it may not be installed.

it only shows the android command inside react-native packages inside our monorepo (like here https://github.com/entria/entria-fullstack/tree/master/packages/app), but fails on root

what is the proper solution for this?

fixed android like this

project.ext.react = [
   cliPath: "../../node_modules/react-native/cli.js",
]

ios also need this

export NODE_BINARY=node
export PROJECT_ROOT="$PROJECT_DIR/.."

../../../node_modules/react-native/scripts/react-native-xcode.sh

Yeah, in my experience, this is the major root cause for all of the monorepo issues that a lot of people are facing these days.

Any idea how we could plug into it? Setting dynamically variables?

this is a hard one, maybe a monorepo documentation guide could be good enough

fixed android like this

project.ext.react = [
   cliPath: "../../node_modules/react-native/cli.js",
]

In my case it was

project.ext.react = [
    ...
    entryFile: "index.js",
    cliPath: "../node_modules/react-native/cli.js",
]

Because project structure is:

node_modules/
- react-native/
mobile/
- node_modules/
- index.js
shared/
web/

@sibelius, following up to my discussions https://github.com/react-native-community/cli/issues/656#issuecomment-601097688, we should be able to safely remove PROJECT_ROOT.

In theory, we always want it to be ios/.. and even if it ends up being deeper in the hierarchy, CLI knows what to do.

If you look at the details of the commit that introduced this change - https://github.com/facebook/react-native/commit/9ccde378b6e6379df61f9d968be6346ca6be7ead, I believe its assumptions are no longer true and we can get rid of it.

Waiting for Janic to get back to me whether this is right and I believe we can follow up with a PR. This particular change shouldn't require anything on the CLI side.

The ideal for me is this on iOS, regardless of your step

export NODE_BINARY=node
../../../node_modules/react-native/scripts/react-native-xcode.sh

As per Janic's comment, we're good to go with the suggested changes.

I will proceed with them soon and link a PR that is landing in React Native as a result.

Just filled in React Native PR - https://github.com/facebook/react-native/pull/28354. Appreciate your review and support in additional explanations :)

Did anyone got build working with hermes enabled in a monorepo?

I've got hermes to work by telling react where it's files are:
hermesCommand: "/mnt/c/Users/user/WebstormProjects/project/node_modules/hermes-engine/%OS-BIN%/hermes",

This solved the initial issue of not being able to build becasue hermes executable was not found, however with this fix in place build is still failing with:

internal/modules/cjs/loader.js:638
    throw err;
    ^

Error: Cannot find module '/mnt/c/Users/user/WebstormProjects/project/packages/mobile/node_modules/react-native/scripts/compose-source-maps.js'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)
    at Function.Module._load (internal/modules/cjs/loader.js:562:25)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)

> Task :app:bundleReleaseJsAndAssets FAILED

...because it is looking for node_modules folder in wrong location; the correct location is the same as in hermesCommand, /mnt/c/Users/user/WebstormProjects/project/node_modules.

Building works with enableHermes: false, so it only fails with hermes is enabled.

Any suggestion how to get around this?

My full react config from gradle:

project.ext.react = [
  entryFile   : "index.js",
  enableHermes: true,  // clean and rebuild if changing
  hermesCommand: "/mnt/c/Users/user/WebstormProjects/project/node_modules/hermes-engine/%OS-BIN%/hermes",
  cliPath     : "../../node_modules/react-native/cli.js",
]

EDIT:
I figured out that one can also use relative path for hermesCommand, which is a bit different than cliPath. Seems like one has to point hermesCommand 2 levels higher in directory structure (when compared to cliPath):

hermesCommand: "../../../../node_modules/hermes-engine/%OS-BIN%/hermes",

EDIT2 / SOLUTION:
By digging through the source code I found that composeSourceMapsPath config key exists, so my whole react config looks like this:

project.ext.react = [
  entryFile   : "index.js",
  enableHermes: true,  // clean and rebuild if changing
  hermesCommand: "../../../../node_modules/hermes-engine/%OS-BIN%/hermes",
  composeSourceMapsPath: "../../node_modules/react-native/scripts/compose-source-maps.js",
  cliPath     : "../../node_modules/react-native/cli.js",
]

This got me pass the issue with compose-source-maps.js and I think files were successfully processed by hermes. However, there seems to still be an issue with code-push, since build fails with

Error: Cannot find module '/mnt/c/Users/user/WebstormProjects/project/packages/mobile/node_modules"/react-native-code-push/scripts/generateBundledResourcesHash.js'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)
    at Function.Module._load (internal/modules/cjs/loader.js:562:25)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)

...so this time code-push is looking node_modules in wrong location. I think this issue is out of scope here, so I guess I should check Microsoft's github regarding this.

Following @tad3j answer, using react-native 0.63.2 I had to change hermesCommand.

hermesCommand: "../../../../node_modules/hermes-engine/%OS-BIN%/hermes",

Changed to:

hermesCommand: "../../../../node_modules/hermes-engine/%OS-BIN%/hermesc",

I still need to pass all other configuration, composeSourceMapsPath, cliPath and hermesCommand. Not passing composeSourceMapsPath was throwing a error.

My monorepo configuration is more or less like this, trying to not use nohoist at all.

  - node_modules
     - react-native
  - packages
      - app
      - web
      - any other shared package

My final build.gradle project.ext.react is the following:

project.ext.react = [
    entryFile: "packages/app/index.js",
    enableHermes: true,  // clean and rebuild if changing,
    hermesCommand: "../../../../node_modules/hermes-engine/%OS-BIN%/hermesc",
    composeSourceMapsPath: "../../node_modules/react-native/scripts/compose-source-maps.js",
    cliPath: "../../node_modules/react-native/cli.js",
]
Was this page helpful?
0 / 5 - 0 ratings

Related issues

mauricioscotton picture mauricioscotton  路  3Comments

jchook picture jchook  路  4Comments

Jarred-Sumner picture Jarred-Sumner  路  3Comments

patrickkempff picture patrickkempff  路  4Comments

thymikee picture thymikee  路  4Comments