React native monorepo with PNPM
Asked Answered
A

6

6

My goal

I am trying to use React native monorepo with PNPM, because I need performance of pnpm.

Expected

I should be able to bundle React native app with pnpm android and start development server with pnpm start.

Actual results

I can bundle app, but I cant start metro server. I always get this error: enter image description here

More info

I have node v16.14.2, react native v0.69.

I know default metro bundler doesn't support symlinks (https://github.com/pnpm/pnpm/issues/1252#issuecomment-667600769), which pnpm use, so I tried to patch metro in metro.config.js: metro.config.js

This works perfectly fine with pure React native repo like here e.g: https://github.com/gjhughes/react-native-pnpm-example

My project structure looks like this:

project
└───shared
└───backend
│   │   package.json
│   
└───frontend
│   │   package.json
│   
└───mobile-app
│   │   package.json

Here is my pnpm-workspace.yaml:

pnpm-workspace.yaml

I am desperate. Is it even possible?

If you have any more questions, feel free to ask!

Abatement answered 7/10, 2022 at 20:47 Comment(0)
V
10

Use pnpm without symlinks. Create a .npmrc in the root of your monorepo with the following setting:

node-linker=hoisted

Remove node_modules and run pnpm install. Related docs: https://pnpm.io/npmrc#node-linker

Vasyuta answered 7/10, 2022 at 21:15 Comment(2)
This breaks everything, I have to then change all paths in settings.gradle and even then I can't bundle the app. The symlink problem should be resolved by @rnx-kit, which has probably problem with the pnpm workspace.Marquand
React 0.72 has support for symlinks, although you have to enable it in a config file. It will be the default in 0.73. reactnative.dev/blog/2023/06/21/…. I haven't tried it myself.Wincer
B
2

In your .npmrc you can do next:

To see if there are any problems with symlinks and make anything work you can start with

node-linker=hoisted

But this will break the point of having pnpm at all

For my case these lines did the job, and ready to be extended if necessary

public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*
public-hoist-pattern[]=*react-native*
public-hoist-pattern[]=*metro*

(note that eslint and prettier reused from defaults)

Reference further details here https://pnpm.io/npmrc#hoist-pattern

Bacteria answered 31/7, 2023 at 14:4 Comment(0)
O
2

My situation is similar to yours, I solved this problem through the expo official documentation。

https://docs.expo.dev/guides/monorepos/

to create and set the metro.config.js in mobile folder

const { getDefaultConfig } = require('expo/metro-config');
const path = require('path');

// Find the project and workspace directories
const projectRoot = __dirname;
// This can be replaced with `find-yarn-workspace-root`
const monorepoRoot = path.resolve(projectRoot, '../..');

const config = getDefaultConfig(projectRoot);

// 1. Watch all files within the monorepo
config.watchFolders = [monorepoRoot];
// 2. Let Metro know where to resolve packages and in what order
config.resolver.nodeModulesPaths = [
  path.resolve(projectRoot, 'node_modules'),
  path.resolve(monorepoRoot, 'node_modules'),
];

module.exports = config;

Odell answered 15/3, 2024 at 6:40 Comment(3)
and you can watch my github project to fork a full stack monorepo projectOdell
I forgot to add, that I do not use expoMarquand
thanks, watchFolders was the missing setting for me.Histrionic
O
1

Hi i made a boilerplate working with monorepos in case you need it

Using react-native 0.72.1 on a monorepo like turbo that enjoy it ;)

https://github.com/Morraycage/turbo-react-native-boilerplate

Outdistance answered 6/7, 2023 at 23:57 Comment(0)
M
0

If you still want to take advantage of pnpm and avoid the node-linker=hoisted option, you can take a look at this great article that explains how to make it works.

To summarize it, you need to

1- add a bunch of packages to make the react-native cli works with pnpm:

pnpm install @react-native-community/cli-platform-ios @react-native-community/cli-platform-android

2- re-install your pods

# in ios folder
bundle exec pod install

3- allow metro to understand symlink (prior to RN72, it natively can't) with @rnx-kit

pnpm install @rnx-kit/metro-config @rnx-kit/metro-resolver-symlinks

change your metro.config.js file to this:

const { makeMetroConfig } = require('@rnx-kit/metro-config')
const MetroSymlinksResolver = require('@rnx-kit/metro-resolver-symlinks')

module.exports = makeMetroConfig({
  projectRoot: __dirname,
  resolver: {
     resolveRequest: MetroSymlinksResolver(),
  },
})

4 - extra step to build on android

pnpm install react-native-gradle-plugin jsc-android
Monoacid answered 11/3, 2024 at 16:27 Comment(0)
B
0

This worked for me => pnpm add -D @babel/preset-env along with the .npmrc file.

Bane answered 9/4, 2024 at 16:15 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.