Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android: latest release broke support custom react-native Root #804

Closed
vladp opened this issue Oct 16, 2019 · 18 comments · Fixed by #824 or #1057
Closed

Android: latest release broke support custom react-native Root #804

vladp opened this issue Oct 16, 2019 · 18 comments · Fixed by #824 or #1057
Labels

Comments

@vladp
Copy link

vladp commented Oct 16, 2019

Environment

System:
OS: Windows 10
CPU: (8) x64 Intel(R) Core(TM) i
Memory: 15.44 GB
Binaries:
Node: 12.10.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.19.1 - C:\Users\v\AppData\Roaming\npm\yarn.CMD
npm: 6.12.0 - C:\Program Files\nodejs\npm.CMD
npmPackages:
react: 16.9.0 => 16.9.0
react-native: ^0.61 => 0.61.2

Description

my directory structure is
andrapp\ <-- has android ./app , gradlew and so on
rn.common\ <-- has package.json index.android.js and ./node_modules

in react-native 60.6 I was able to specify the React native root (in app/build.gradle)


project.ext.react = [

        entryFile: "index.android.js",
        // whether to bundle JS and assets in debug mode
        bundleInDebug: false,
        // whether to bundle JS and assets in release mode
        bundleInRelease: true,
        bundleCommand: "ram-bundle",
        enableHermes: false,  // clean and rebuild if changing
        **root:** "${myRnAppRootDir_abs}"
]

And cli was able to correctly invoke
npx.cmd --quiet react-native config
from within rn.common directory

However since this change
5724d29#diff-375026a0607eb034a6fc70cca7d74689

native_modules.gradle
Now invokes npx in 'default' directly, not in React's project root. Which causes
npx.cmd --quiet react-native config
to complain with

error Unrecognized command "config".
info Run "react-native --help" to see a list of all available commands.

Which, then, causes JSON parsing error in native_modules.js

Here is code change in native_modules.js that causes the error on Android

// old code, that was working
cmdProcess = Runtime.getRuntime().exec(command, null, root)

// new code that does not work
cmdProcess = Runtime.getRuntime().exec(command)

From the design/documentation perspective, it seems that the whole infrastructure for getReactNativeProjectRoot() have been removed, and no alternative/migration documentation has been suggested.

Note also, that react-native 0.61 project template, continues to assert that configuring custom root (where package.json) resides, by specifying root in project.ext.react (in app/build.gradle) -- is still a valid and supported option

https://github.com/facebook/react-native/blob/master/template/android/app/build.gradle

@thymikee
Copy link
Member

cc @grabbou

@thymikee
Copy link
Member

AFAICT the change was intentional, to fix a lot of other custom structure issues. Now, if the RN app is nested in a directory, we expect users to call CLI from that nested directory, and we don't care whether the node_modules/react-native are hoisted or not. Please share your repo structure and the way you use it, so we can advise.

@vladp
Copy link
Author

vladp commented Oct 16, 2019

Sure. appreciate in advance your guidance.

I am showing quite a bit of complexity below (essentially most of our front-end project tree).
You will see there android app (under a),
web applications (aa1a) and (ua1c) that are built in React Native Web.

Then you will see
rn.common
which is where our shared React-Native code is.
It is shared by Android app (that has just 1 activity with React native), and by all of the web apps.

There is a lot of co-dependency across all of that stuff and reliance on the specific directory structure we have now.
Which is also why configuring React native root when building android app was essential for us.



FRONTEND-OF-MYAPP
|-- a  (* this is where android app code resides. Android app has just 1 activity that uses RN, RN's js code is rn.common *)
|   `-- u1b
|       |-- LICENSE.md
|       |-- README.md
|       |-- app
|       |   |-- BUCK
|       |   |-- build.gradle
|       |   |-- build_defs.bzl
|       |   |-- config
|       |   |   |-- gradle_cfg
|       |   |   |   |-- build.gradle
|       |   |   |   |-- jacoco.gradle
|       |   |   |   |-- quality.gradle
|       |   |   |   `-- versioning.gradle
|       |   |   |-- signing
|       |   |   |   |-- readme.md
|       |   |   |   |-- release.keystore
|       |   |   |   `-- signing.properties
|       |   |   `-- static_analysis
|       |   |       |-- checkstyle
|       |   |       |   |-- checkstyle_rules.xml
|       |   |       |   `-- checkstyle_suppression_filter.xml
|       |   |       |-- findbugs
|       |   |       |   `-- findbugs-exclusions.xml
|       |   |       `-- pmd
|       |   |           `-- pmd_rules.xml
|       |   |-- proguard-rules.pro
|       |   `-- src
|       |       |-- main
|       |       |   |-- AndroidManifest.xml
|       |       |   |-- assets
|       |       |   |   |-- fonts
|       |       |   |   |-- project.properties
|       |       |   |-- java
|       |       |   |   `-- com
|       |       |   `-- res
|       |       |       |-- drawable
|       |       |       |-- drawable-v24
|       |       |       |-- layout
|       |       |       |-- menu
|       |       |       |-- values
|       |       |       |-- values-w600dp
|       |       |       |-- values-w820dp
|       |       |       `-- xml
|       |       |-- qa
|       |       |   `-- res
|       |       |       |-- mipmap-hdpi
|       |       |-- release
|       |       |   `-- java
|       |       |       `-- com
|       |       |-- testHelpers
|       |       |   |-- java
|       |       |   |   `-- com
|       |       |   `-- resources
|       |       |-- unitTests
|       |       |   `-- java
|       |       |       `-- com
|       |       |-- unitTestsDebug
|       |       |   `-- java
|       |       |       `-- com
|       |       |-- unitTestsQa
|       |       |   `-- java
|       |       |       `-- com
|       |       `-- unitTestsRelease
|       |           `-- java
|       |               `-- com
|       |-- art
|       |-- build.gradle
|       |-- config
|       |   `-- ide
|       |-- gradle
|       |   `-- wrapper
|       |       `-- gradle-wrapper.properties
|       |-- gradle.properties
|       `-- settings.gradle
|-- rn.common (* contains code used by Android's RN activity, and by many screens in my WebApps that use React Native Web, see symlinks to rn.common in aa1a and ua1c *)
|   |-- index.android.js
|   |-- package.json
|   |-- react-native.config.js
|   |-- src
|   |   |-- js.app
|   |   |   |-- img
|   |   |   |   |-- ic_local_library_black_48dp.png
|   |   |   |   `-- ic_menu_black_48dp.png
|   |   |   |-- mdk
|   |   |   |-- mybusiness.components
|   |   |   |   |-- nonui
|   |   |   |   `-- rnui
|   |   |   `-- mybusiness.main
|   |-- u1b__rn.code-workspace
`-- rnweb
    |-- aa1a
    |   |-- app.src
    |   |   |-- components
    |   |   |-- containers
    |   |   |-- reducers
    |   |   |-- store
    |   |   `-- styles
    |   |-- csr-cra
    |   |   |-- README.md
    |   |   |-- aa1a-csr-cra.code-workspace
    |   |   |-- config-overrides.js
    |   |   |-- package.json
    |   |   |-- public
    |   |   |-- src
    |   |   |   |-- App.css
    |   |   |   |-- App.js
    |   |   |   |-- App.test.js
    |   |   |   |-- app.src -> ../../app.src/
    |   |   |   |-- index.css
    |   |   |   |-- index.js
    |   |   |   |-- js.app -> ../../../../rn.common/src/js.app/
    |   |   |   |-- logo.svg
    |   |   |   |-- registerServiceWorker.js
    |   |   |   |-- serviceWorker.js
    |   |   |   `-- wc.src -> ../../../web.common/wc.src/
    |   |-- replace_file_link_with_dir_link.cmd
    |-- ua1c
    |   |-- app.src
    |   |   `-- readme.txt
    |   |-- create_sym_links.sh
    |   |-- csr-cra
    |   |   |-- config-overrides.js
    |   |   |-- dev-launch-win.cmd
    |   |   |-- dev_build_and_deploy.cmd
    |   |   |-- dev_build_and_deploy.sh
    |   |   |-- ide-set.sh
    |   |   |-- package.json
    |   |   |-- public
    |   |   |-- src
    |   |   |   |-- App.css
    |   |   |   |-- App.js
    |   |   |   |-- App.test.js
    |   |   |   |-- Landing.js
    |   |   |   |-- app.src -> ../../app.src/
    |   |   |   |-- index.css
    |   |   |   |-- index.js
    |   |   |   |-- js.app -> ../../../../rn.common/src/js.app/
    |   |   |   |-- logo.svg
    |   |   |   |-- registerServiceWorker.js
    |   |   |   |-- serviceWorker.js
    |   |   |   `-- wc.src -> ../../../web.common/wc.src/
    |   |   `-- ua1c-csr-csra.code-workspace
    `-- web.common
        `-- wc.src
            |-- domain
            |   `-- components
            |       |-- ecommerce
            |       `-- venuesignup
            |-- nonui
            |   `-- readme.txt
            `-- ui
                `-- readme.txt



@grabbou
Copy link
Member

grabbou commented Oct 17, 2019

Thanks for reporting this over.

The problem here is that you don't have package.json anywhere in the Android app or at the root of your project.

The CLI automatically resolves the "root" of your project by looking for the closest package.json in the directory structure. The "root" option you're referring to in the Gradle configuration is something different and that's what React Native uses for bundling resources.

I am surprised that this setup is working for you. Autolinking is looking for dependencies to link from a "package.json" and there's clearly no "package.json" with modules to link in your setup.

As a result of such directory structure, the two following problems will happen:

  • CLI will be unable to resolve a "package.json" going up the directory tree, starting from "u1b/android", where it's being called while you run your app.

  • As a result, CLI will not be able to find "react-native" dependency using "require.resolve" mechanism either. "require.resolve" goes up the directory structure as well (which is why we have ended up using the same heuristics - staying compliant with what Node is already doing). I believe "react-native" resides in "../../rn.common/node_modules", starting from "a/u1b", so it's not going to be available.

The solution requires doing few tweaks to the directory structure you have set up.

Yarn workspaces

The most elegant way would be to set up a Yarn workspaces project for this. In order to get this working, you would need to make sure that each project has a valid package.json inside, even if it's empty.

Your a/u1b should have a package.json and define a dependency on react-native, because it's depending on the React Native and actually, building it during runtime using the CLI and Gradle. You wouldn't need to this if you were just consuming a precompiled "RN.Common" archive, not having any build step at all.

You also need to explicitly list down all React Native packages that you want to link to your Android/iOS app in such package.json as well. CLI looks for dependencies to link in the closest package.json, when you build your project.

When running yarn in such a project, all "node_modules" from each application would be hoisted to the root of the project. In your case, that's "FRONTEND-OF-MY-APP/node_modules". Thanks to that, you would end up with just a single copy of "react-native" at the root, despite all your packages requiring a dependency on it.

It will also automatically support setting cross-links between your projects. Just set your packages to depend on each other and Yarn will take care of it.

For example, our CLI uses this and packages are automatically symlinked when needed. It is also the setup that we recommend for "monorepositories" and library developers. We are most likely to keep supporting it in the foreseeable future.

@grabbou
Copy link
Member

grabbou commented Oct 17, 2019

One additional note regarding my previous comment:

I believe you have designed this folder structure to re-use code between mobile and web, hence "rn.common" folder with "common" code.

However, taking a closer look at its contents, it's not "common". It contains "index.android.js" (entry point for an Android mobile app) and many other things. So at the end of the day, it combines two things: React Native code for Android mobile application and some React / JavaScript code that you may share on the Web.

In my opinion, the React Native code responsible for Android / iOS mobile application should reside under "a/u1b" where the complementary native code is located. That way, you can write some mobile-specific code as well without polluting the common folder.

By creating a package.json in that folder, this will be both possible and compatible with what CLI expects.

@vladp
Copy link
Author

vladp commented Oct 17, 2019

@grabbou thank you for the follow ups.
Let me ask this, -- is it possible, via configuration, to disable autolinking performed by the CLI?

Our Android app is a 'hybrid' (there is only one activity using RN), and we already specify the packages that must be 'loaded' by the RN Android runtime (there is only 1, vector-icons).
The rest of the packages in rn.common/package.json do not need to be loaded by RN Android runtime, and are just bundled in.
Plus, we are very happpy to continue to specify manually all the packages we want loaded, as we do today. So, essentially, autolinking feature is not essentiall at all for us.


Given that you spend effort offering explanation on why we should restructure our repo (thank you for that), let me offer some replies (although I am not sure they are particuallary convicing, I hope it gives bit more background/picture to others as well).

Overall, once in a while we think of moving our 'common/reusable' code into some form of custom node modules, then setting up custom NPM-like repo internally and pulling it from there. Or learning other tooling options around lerna/etc.
At this stage our resources/delivery priorities simply cannot afford the complexity+time involved.


The CLI automatically resolves the "root" of your project by looking for the closest package.json

It appears, that the change was made, exactly in this feature.
Now there is no way to tell CLI were my root project is (root meaning code+node_modules).

Perhaps, you were thinking to model it after how webpack looks up node_modules.
I think this is a familiar model for js/webpack devs, so it can be a reasonable idea.

But in many cases, RN is just small piece of the overall edge-device/front-end code and the overall structure is dictated by other 'opinioned/less opinioned' toolchains.

So overall, I would still advocate that autolinking or any other RN build toolchain feature allows for flexibility of defining where files can reside, and were roots of RN can reside.

In my opinion, the React Native code responsible for Android / iOS mobile application should reside under "a/u1b" where the complementary native code is located.

Well that's was not the intent. We are not that RN-centric.
We did not want to merge front-end apps under one root, just because they happen to rely on RN in a couple of screens.

We would put 2nd android app under a, but not under a/u1b
ios apps would go under i, (eg i/a2a i/a1b and so on ... )
windows apps under w,
framebuffer front ends for microntrollers, under b
Some do not rely on RN at all.

So a/u1b means 'AndroidApp-endusers-Domain1B'
i/a1b -- means IosApp-administrators-Domain1B
And so on.

As a philosophy, in a way, we structure our monorepo on combination of 'BusinessFunction+BusinessDomain', rather than on 'ProgrammingLanguage+ProgrammingLibrary+BussinessFunction'

We also have operations domains (devops, and so on, they are structured same way, but start with devops as this a operations domain).

WRT " However, taking a closer look at its contents, it's not "common". It contains "index.android.js" (entry point for an Android mobile app) and many other things. So at the end of the day, it combines two things: React Native code for Android mobile application and some React / JavaScript code that you may share on the Web.
"

That's true, I tried my best to move android.index.js (and 2 other files) out of rn.common into its own.
However Metro bundler insists that I have index.android.js and the files it referrers to underneath its dir (and not above or in siblings dir).
Metro, allowed that in previous versions, but they removed that capabilty too.
I entered an issue for it a couple of months ago, unresolved sofar
facebook/metro#444 (comment)

But even if metro would have fixed the above issue, moving index.android.js out of rn.common would not have helped the new CLI to find rn.common.


Not sure if this useful, but here is (sanitizied) output of
npx.cmd --quiet react-native config

When it is executed from rn.common (this is what CLI was receiveing, when it was respecting my root setting, with the old code
cmdProcess = Runtime.getRuntime().exec(command, null, root) ):

{
  "root": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common",
  "reactNativePath": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native",
  "dependencies": {
    "react-native-vector-icons": {
      "root": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons",
      "name": "react-native-vector-icons",
      "platforms": {
        "ios": {
          "sourceDir": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons",
          "folder": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons",
          "pbxprojPath": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\RNVectorIcons.xcodeproj\\project.pbxproj",
          "podfile": null,
          "podspecPath": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\RNVectorIcons.podspec",
          "projectPath": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\RNVectorIcons.xcodeproj",
          "projectName": "RNVectorIcons.xcodeproj",
          "libraryFolder": "Libraries",
          "sharedLibraries": [],
          "plist": [],
          "scriptPhases": []
        },
        "android": {
          "sourceDir": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\android",
          "folder": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons",
          "packageImportPath": "import com.oblador.vectoricons.VectorIconsPackage;",
          "packageInstance": "new VectorIconsPackage()"
        }
      },
      "assets": [
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\AntDesign.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\Entypo.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\EvilIcons.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\Feather.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\FontAwesome.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\FontAwesome5_Brands.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\FontAwesome5_Regular.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\FontAwesome5_Solid.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\Fontisto.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\Foundation.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\Ionicons.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\MaterialCommunityIcons.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\MaterialIcons.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\Octicons.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\SimpleLineIcons.ttf",
        "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\node_modules\\react-native-vector-icons\\Fonts\\Zocial.ttf"
      ],
      "hooks": {},
      "params": []
    }
  },
  "commands": [
    {
      "name": "log-ios",
      "description": "starts iOS device syslog tail"
    },
    {
      "name": "run-ios",
      "description": "builds your app and starts it on iOS simulator",
      "examples": [
        {
          "desc": "Run on a different simulator, e.g. iPhone 5",
          "cmd": "react-native run-ios --simulator \"iPhone 5\""
        },
        {
          "desc": "Pass a non-standard location of iOS directory",
          "cmd": "react-native run-ios --project-path \"./app/ios\""
        },
        {
          "desc": "Run on a connected device, e.g. Max's iPhone",
          "cmd": "react-native run-ios --device \"Max's iPhone\""
        },
        {
          "desc": "Run on the AppleTV simulator",
          "cmd": "react-native run-ios --simulator \"Apple TV\"  --scheme \"helloworld-tvOS\""
        }
      ],
      "options": [
        {
          "name": "--simulator [string]",
          "description": "Explicitly set simulator to use. Optionally include iOS version betweenparenthesis at the end to match an exact version: \"iPhone 6 (10.0)\"",
          "default": "iPhone X"
        },
        {
          "name": "--configuration [string]",
          "description": "Explicitly set the scheme configuration to use",
          "default": "Debug"
        },
        {
          "name": "--scheme [string]",
          "description": "Explicitly set Xcode scheme to use"
        },
        {
          "name": "--project-path [string]",
          "description": "Path relative to project root where the Xcode project (.xcodeproj) lives.",
          "default": "ios"
        },
        {
          "name": "--device [string]",
          "description": "Explicitly set device to use by name.  The value is not required if you have a single device connected."
        },
        {
          "name": "--udid [string]",
          "description": "Explicitly set device to use by udid"
        },
        {
          "name": "--no-packager",
          "description": "Do not launch packager while building"
        },
        {
          "name": "--verbose",
          "description": "Do not use xcpretty even if installed"
        },
        {
          "name": "--port [number]",
          "default": 8081
        },
        {
          "name": "--terminal [string]",
          "description": "Launches the Metro Bundler in a new window using the specified terminal path."
        }
      ]
    },
    {
      "name": "log-android",
      "description": "starts logkitty"
    },
    {
      "name": "run-android",
      "description": "builds your app and starts it on a connected Android emulator or device",
      "options": [
        {
          "name": "--root [string]",
          "description": "Override the root directory for the android build (which contains the android directory)",
          "default": ""
        },
        {
          "name": "--variant [string]",
          "description": "Specify your app's build variant",
          "default": "debug"
        },
        {
          "name": "--appFolder [string]",
          "description": "Specify a different application folder name for the android source. If not, we assume is \"app\"",
          "default": "app"
        },
        {
          "name": "--appId [string]",
          "description": "Specify an applicationId to launch after build.",
          "default": ""
        },
        {
          "name": "--appIdSuffix [string]",
          "description": "Specify an applicationIdSuffix to launch after build.",
          "default": ""
        },
        {
          "name": "--main-activity [string]",
          "description": "Name of the activity to start",
          "default": "MainActivity"
        },
        {
          "name": "--deviceId [string]",
          "description": "builds your app and starts it on a specific device/simulator with the given device id (listed by running \"adb devices\" on the command line)."
        },
        {
          "name": "--no-packager",
          "description": "Do not launch packager while building"
        },
        {
          "name": "--port [number]",
          "default": 8081
        },
        {
          "name": "--terminal [string]",
          "description": "Launches the Metro Bundler in a new window using the specified terminal path."
        },
        {
          "name": "--tasks [list]",
          "description": "Run custom Gradle tasks. By default it's \"installDebug\""
        },
        {
          "name": "--no-jetifier",
          "description": "Do not run \"jetifier\" – the AndroidX transition tool. By default it runs before Gradle to ease working with libraries that don't support AndroidX yet. See more at: https://www.npmjs.com/package/jetifier.",
          "default": false
        }
      ]
    }
  ],
  "assets": [
    "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\src\\js.app\\img\\ic_local_library_black_48dp.png",
    "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\src\\js.app\\img\\ic_menu_black_48dp.png"
  ],
  "platforms": {
    "ios": {},
    "android": {}
  },
  "haste": {
    "providesModuleNodeModules": [
      "react-native"
    ],
    "platforms": [
      "ios",
      "android"
    ]
  },
  "project": {
    "ios": null,
    "android": {
      "sourceDir": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\a\\u1b\\app\\src",
      "isFlat": false,
      "folder": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common",
      "stringsPath": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\a\\u1b\\app\\src\\src\\main\\res\\values\\strings.xml",
      "manifestPath": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\a\\u1b\\app\\src\\debugAndQa\\AndroidManifest.xml",
      "buildGradlePath": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\a\\u1b\\app\\src\\build.gradle",
      "settingsGradlePath": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\rn.common\\android\\settings.gradle",
      "assetsPath": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\a\\u1b\\app\\src\\src\\main\\assets",
      "mainFilePath": "C:\\Users\\v\\home\\devel\\myrepo\\FRONTEND\\a\\u1b\\app\\src\\src\\main\\java\\com\\u1b\\MainApplication.java",
      "packageName": "com.u1b"
    }
  }
}

@vladp
Copy link
Author

vladp commented Oct 29, 2019

just wanted to check with @grabbou or @thymikee if they could think of a way forward/workaround, without requiring us to restructure our source repo.

@thymikee
Copy link
Member

@vladp I wonder if the change we cook here would help in your case? #824

@vladp
Copy link
Author

vladp commented Oct 30, 2019

@thymikee
I think if you will find a way to pass value of

app/build.android
project.ext.react.root

into line 155 of the npx command in

https://github.com/react-native-community/cli/blob/master/packages/platform-android/native_modules.gradle


   def cmdProcess
    def npx = Os.isFamily(Os.FAMILY_WINDOWS) ? "npx.cmd" : "npx"
    def command = "${npx} --quiet react-native config"   //<--- line 155
    def reactNativeConfigOutput = ""

then it will work.

@thymikee
Copy link
Member

Looking at you project structure, this patch should work in your case.

With the changes done there we'd run npx react-native config directly from within the rn.common/ directory, which holds node_modules with CLI and react-native. Even if you started to hoist the dependencies to the parent directory, it would still work because of Node resolution algorithm used by npx.

Am I missing something? Feel free to replace your native_modules.gradle with the one that's there.

@vladp
Copy link
Author

vladp commented Nov 1, 2019

@thymikee I just tested your update on top of 0.61, and it works for us!.
Thank you for this.

It seems that what you have done, is leveraged the fact that everybody in their
app/build.gradle
already had to specify where RN gradle is (and therefore where node_modules for RN is)
Then you assume that that's the directory with RN's node_modules, is the root of the RN project,
and that's where you now run npx react-native config

That works well, it makes sense, it allows us the flexibility to keep RN common code, in whatever directory structure we want, and, as 'icing on the cake' eliminates the need to re-specify the location of that directory like 3 additional times.

@thymikee
Copy link
Member

Reopening because of #852. We need to find better solution

@thymikee thymikee reopened this Nov 15, 2019
@josephmbeveridge
Copy link

josephmbeveridge commented Dec 4, 2019

@grabbou I have a monorepo structure set up almost identical to the one you suggested earlier, but the RN CLI doesn't work properly in root. I don't want a react-native package in root, and would like to instead force each sub-folder to specify the RN version in their package.json. However, after doing this the CLI can't find run-android as a command for some reason when running from root.

I checked and I'm sure that react-native, along with all the other packages I need, are correctly hoisted up to root. The react-native command even runs, but it doesn't think that run-android is a valid sub-command. I'm currently running react-native run-android --root "./projectName". Is there any more configuration that is needed? To note, this works perfectly fine if I leave react-native in the root package.json.

Looking through the global .bin for react-native it appears to kick it to my node_modules/@react-native-community/cli package after going through the react-native one. There is also node_modules/@react-native-community/cli-platform-android which appears to have the commands I am missing, but I'm not sure how the main cli links to it.

Structure just to be clear:

package.json
 -> project1
      package.json
      -> android
      -> ios
 -> project2
      package.json
      -> android
      -> ios

where the sub-projects have essentially this as their package.json

{
  ...
  "dependencies": {
    "react-native": "0.61.5"
    ...
  }
  ...
}

and root has ideally nothing in its dependencies (or very little).

Also please feel free to send me to another issue if this isn't a good place to ask.

@lylest
Copy link

lylest commented Apr 8, 2020

why did you closed this issue

@thymikee
Copy link
Member

thymikee commented Apr 8, 2020

@lylest because we believe it was fixed by #1057 available in latest CLI version, which lets you get rid of root from Gradle config.

@vladp
Copy link
Author

vladp commented Apr 11, 2020

@thymikee
Please re-open this issue.
The problem I reported is not resolved.

I am getting
'[node, -e, console.log(require('react-native/cli').bin);]' in directory 'C:\Users\v\home\devel\myrepo\FRONTEND\a\u1b' command failed.

React native 0.62.
using most recent CLI release 4.7.0

when executing the build from android studio
or when running gradlew task
In the u1b , the edirectory where I have my android project (see my directory structure fully described October 16, 2019 comment)

FRONTEND-OF-MYAPP
|-- a  (* this is where android app code resides. Android app has just 1 activity that uses RN, RN's js code is rn.common *)
|   `-- u1b


The problem still seems to be same (using 4.7.0 release of cli. Tried both on Windows and Linux).
The cli is trying to execute java script commands in my Android app directory (u1b), and not in the correct directory which is rn.common

My settings.gradle is the same as when reported the issue 6 months ago

rootProject.name = 'u1b'
def myRnAppRootDir_abs="${rootDir}/../../rn.common"
def myRnAppRootDir_rel="../../rn.common"
apply from: file("${myRnAppRootDir_abs}/node_modules/@react-native-community/cli-platform-android/native_modules.gradle")
applyNativeModulesSettingsGradle(settings,myRnAppRootDir_rel)
...

Same build.gradle:

plugins {
    id 'com.android.application'
    id("com.github.triplet.play") version "2.6.1"
}


import com.android.build.OutputFile


def myRnAppRootDir_abs="${rootDir}/../../rn.common"
def myRnAppRootDir_rel="../../rn.common"

def myMinSDKVer=21

apply from: 'config/gradle_cfg/quality.gradle'

project.ext.react = [

        entryFile: "index.android.js",
        bundleInDebug: false,
        bundleInRelease: true,
        bundleCommand: "ram-bundle",
        enableHermes: false,  // clean and rebuild if changing
        root: "${myRnAppRootDir_abs}"
]


apply from: "${myRnAppRootDir_abs}/node_modules/react-native/react.gradle"
apply from: "${myRnAppRootDir_abs}/node_modules/react-native-vector-icons/fonts.gradle"

...

apply from: file("${myRnAppRootDir_abs}/node_modules/@react-native-community/cli-platform-android/native_modules.gradle");
applyNativeModulesAppBuildGradle(project,"${myRnAppRootDir_rel}")


NODE_MODULES environment variable is not set

v12.16.1

The problem, clearly the same as before

When settings.gradle invokes
applyNativeModulesSettingsGradle(settings)
CLI's node_modules/@react-native-community/cli-platform-android/native_modules.gradle
fails to figure out where my JS directory is (rn.common) -- because that capability was removed with CLI release in rn 0.61.

To confirm that this is same problem, I modified native_modules.gradle
and applied the same solution as @thymikee created before
(getting the JS directory from the path of nativ_modules.gradle)

// find current directory and set is as the one to use for subsequent autolinking machinery
def jsAppDir = buildscript.sourceFile.toString().split("node_modules/@react-native-community/cli-platform-android/native_modules.gradle")[0]
def projectRoot =  (jsAppDir != null)? new File(jsAppDir) : rootProject.projectDir;
def autoModules = new ReactNativeModules(logger,projectRoot)

That allowed to build to pass the above mentioned error... But without the above change to CLI code, I simply do not know how to get this to even start the build.

@lylest

This comment has been minimized.

@urtheone
Copy link

still happen in 0.71.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
6 participants