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

feat: support autolinking in monorepos #768

Merged
merged 44 commits into from
Oct 11, 2019
Merged

feat: support autolinking in monorepos #768

merged 44 commits into from
Oct 11, 2019

Conversation

grabbou
Copy link
Member

@grabbou grabbou commented Oct 3, 2019

Fixes #537
Fixes #717
Fixes #657 (path to .bin no longer hardcoded)
Fixes #633

The problem:

There are various issues complaining about weak or broken support for mono repositories, in regards to auto-linking. The workarounds are temporary and error-prone, being executed on top of a confusing resolution system.

Surprisingly, we already have quite a good support for mono-repo in the CLI. For example, we check for a package in node_modules up the directory tree. We also do that for resolving the configuration file.

In this PR, I am reworking some of the fundamental assumptions about the paths within auto-linking in order to make it support various project structures without any extra work.

Automatic mono repository support for automatic linking 😂

Summary:

Please look at the structure that I am working on. I believe this is the most common mono repo:

- /node_modules
   - /react-native
   - /react-native-firebase
- /packages
   - /mobile
      - /node_modules
         - /react-native-webview
      - /ios

This structure is based on the @brunolemos repository that he provided for reproduction purposes.

Please keep in mind the following two design decisions:

My main assumption is that all configuration relative to the project you are working on (metro configuration, CLI configuration) should be placed inside packages/mobile. I think scoping is better and is going to support multiple apps that co-exist within a single codebase.

Dependencies can live at different levels in the project hierarchy (hence I had to remove hardcoded root, which wouldn't make this work). This is important when there are multiple React Native apps living next to each other when a package cannot be hoisted.

Test:

When running pod install on iOS and Android, both react-native-webview and react-native-firebase are linked properly with their relative paths.

Status:

  • iOS
  • Android

Let me know if this structure is similar to what you are running and what you'd expect.

Changes

  • feat: deprecate root in auto-linking and introduce automatic detection of the project location
  • refactor: refactor PackageManager to not rely on a setProjectRoot being called in different places
  • refactor: limit dependency on an implicit process.cwd() being set by few functions
  • feat: introduce detachedFunction (internally) that runs without configuration (useful for init and other commands that don't need project context)

@tbergquist-godaddy
Copy link

I remember looking into brunolemos repository, but if I understand correctly, this setup works because of the react-native.config.js in the root pointing to the android project path?

And this would only work with one react-native app in your monorepo right? What if I want to have more react-native apps in the same monreopo?

@grabbou
Copy link
Member Author

grabbou commented Oct 4, 2019

Speaking to @thymikee, we have decided to pursue using yarn and npx again and checking which versions are supported. Using them lets us make even fewer assumptions about the paths, which is making it better for monorepo.

Will resume later.

Copy link
Member

@thymikee thymikee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks too simple to be true :D so far I didn't find anything suspicious, but we need to test it thoroughly

packages/platform-ios/native_modules.rb Show resolved Hide resolved
packages/platform-ios/native_modules.rb Show resolved Hide resolved
We do not need root anymore. However, we still accept one argument (config) for testing purposes. Without this check, users that pass custom root would accidentially break their projects as CLI would take it as a config value.
@grabbou grabbou changed the title WIP: Support autolinking in monorepo Support autolinking in monorepo Oct 8, 2019
@grabbou
Copy link
Member Author

grabbou commented Oct 8, 2019

Added Android support. Feedback is welcome :)

@Titozzz
Copy link
Contributor

Titozzz commented Oct 10, 2019

Great job :)

docs/autolinking.md Show resolved Hide resolved
@@ -57,10 +63,10 @@ def use_native_modules!(root = "..", config = nil)
end

podspec_dir_path = Pathname.new(File.dirname(podspec_path))
project_root = Pathname.new(config_root)

relative_path = podspec_dir_path.relative_path_from project_root
Copy link
Member

@thymikee thymikee Oct 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we don't have custom root, I think instead of using project_root we need to use cwd, because that's we look for – a relative path from cwd (ios dir) to our native module (in node_modules or custom path). This fixes the Slider repo example for me:

Suggested change
relative_path = podspec_dir_path.relative_path_from project_root
relative_path = podspec_dir_path.relative_path_from Dir.pwd

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

projet_root is project_root = Pathname.new(config["project"]["ios"]["sourceDir"]) few lines earlier - so that's exactly the location of ios folder.

PWD might be not a good idea, see: #657 when running from root folder with --ios-directory flag

@Salakar
Copy link
Member

Salakar commented Oct 10, 2019

It might be good to test this on the React Native Firebase monorepo test project also (https://github.com/invertase/react-native-firebase/tree/master/tests), though I have no availability until probably end of next week 😫

@grabbou
Copy link
Member Author

grabbou commented Oct 11, 2019

Will test React Native Slider and React Native Firebase before we ship it, just to be sure.

@grabbou
Copy link
Member Author

grabbou commented Oct 11, 2019

React Native Slider isn't properly configured right now and this PR leveraged its issues. Running react-native config reveals that project.ios.sourceDir points to ios instead of example/ios.

The following configuration makes everything run smoothly:

const root = __dirname;

module.exports = {
  project: {
    android: {
      sourceDir: './example/android',
    },
    ios: {
      project: './example/ios/example.xcodeproj',
    },
  },
  dependencies: {
    'react-native-slider': {
      root,
    },
  },
};

Note that in the future, once we add support to runAndroid and runIOS to use config (right now, they don't), it will make it easier.

For example, no --root flag will be needed to runAndroid to point it to the correct directory.

@grabbou
Copy link
Member Author

grabbou commented Oct 11, 2019

Note: I wouldn't recommend doing React Native Slider setup in the future. Ideally, every project goes React Native Firebase way, having a separate package.json and independent package for an example project.

In that scenario, no custom configuration at all is needed. I still feel like custom root is a hack :(

@thymikee
Copy link
Member

thymikee commented Oct 11, 2019

Doesn't this configuration leak to the users if config is published?

I think it's about time to end this hack (because it clearly was one, I forgot how bad :D). The now seemingly correct approach there would be to include a real package.json with "react-native": "*" and "@react-native-community/slider": ".." and setup workspaces for less stuff to download

@grabbou
Copy link
Member Author

grabbou commented Oct 11, 2019

@thymikee project doesn't leak outside. dependency would be read, but that would be on purpose :)

I actually just wrote this down and I am totally on board with your idea - I believe this is the best way to set it up and doesn't include this hack.

@thymikee thymikee changed the title Support autolinking in monorepo feat: support autolinking in monorepos Oct 11, 2019
@grabbou
Copy link
Member Author

grabbou commented Oct 11, 2019

@thymikee we should have a generator for initing such a structure like React Native Firebase to work on. Once it's supported here by default, we can make it official and the only use-case supported.

@thymikee
Copy link
Member

@grabbou sounds like something that Bob could provide

@grabbou
Copy link
Member Author

grabbou commented Oct 11, 2019

React Native Firebase works w/o issues with this PR @Salakar. Great project set up by the way!

@Salakar
Copy link
Member

Salakar commented Oct 11, 2019

React Native Firebase works w/o issues with this PR @Salakar. Great project set up by the way!

Thanks for checking!

@vomchik
Copy link

vomchik commented Jan 31, 2020

@grabbou Hi. Could you help me? Should both dependencies be added to package.json?
Currently, I'm using Lerna and run this command npx lerna booststap --hoist so all my deps hoist to root node_modules folder, but pod install can't find any react-native deps.
Maybe you have a repo with some examples.
Thanks.

@vongohren
Copy link

Yeah some examples of this would be nice, because Im still battling to no-hoist or not, to make sure that all is packaged right. Im following a couple of leads: https://engineering.brigad.co/react-native-monorepos-code-sharing-f6c08172b417

But keep getting missing in the project on some files and even getting past that I get firebase issues: invertase/react-native-firebase#2122

So as the commentes in the medium says, is it still too early to do react native monorepo?

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