Open brownieboy opened 1 year ago
Moving to metro
Managed to get it working by adding watchFolders. Here is my config example:
const config = {
watchFolders: [path.join(__dirname, '..', '..')],
resolver: {
unstable_enableSymlinks: true,
unstable_enablePackageExports: true,
},
};
@uxigene,
watchFolders: [path.join(__dirname, '..', '..')],
Many thanks! Yes, that worked for me too 😊, although I'm not sure why that works 🤔.
You need to add the path import at the top of the file (metro.config.js) too, of course:
const path = require('path');
This doesn't seem to work for me, same error as the above on android, even after clearing builds, cache etc, @brownieboy @uxigene please can you update the repo with the working builds.
Also, can you please say specifically what node version, pnpm version you are using.
It seems very flaky.
For those using Expo SDK 50 + RN 0.73 with pnpm, it seems there are other file resolution issues too:
Okay I've been wrestling with getting the full pnpm experience with React Native without making any compromises like node-linker=hoisted
. The DX you get from pnpm in the long-term justifies losing 2 days on this.
I could only get my expo router app back up and running after going all in on Metro. Big shout out to this guide.
I'm guessing most folks who want to place their React Native projects inside a pnpm monorepo are also sharing code from tailwind packages etc. So here's my finished article. With this config pnpm monorepo's work like a charm. I've included my Nativewind and SVG transformer configs to show how easily you can extend Metro without accidentally breaking something else.
{
...
"expo": "^51.0.17",
"expo-router": "~3.5.23",
"react-native": "^0.74.5",
...
}
// Learn more: https://docs.expo.dev/guides/monorepos/
const path = require("path");
const { getDefaultConfig } = require("expo/metro-config");
const { FileStore } = require("metro-cache");
const { withNativeWind } = require("nativewind/metro");
const { makeMetroConfig } = require("@rnx-kit/metro-config");
const { mergeConfig } = require("metro-config");
const MetroSymlinksResolver = require("@rnx-kit/metro-resolver-symlinks");
const symlinksResolver = MetroSymlinksResolver();
const projectDir = __dirname;
const monorepoRoot = path.resolve(projectDir, "../..");
const defaultConfig = getDefaultConfig(projectDir);
/** @type {import('expo/metro-config').MetroConfig} */
const monorepoConfig = {
resolver: {
disableHierarchicalLookup: true,
nodeModulesPaths: [
path.resolve(projectDir, "node_modules"),
path.resolve(monorepoRoot, "node_modules"),
],
/**
* React Native has very frail symlink support for modern monorepo tools
* that rely on symlinks and global caches to dramatically increase the
* performance of installs e.g. pnpm. The best way around this is using
* Microsoft's rnx-kit. I've written more extensively about this in the
* README.
*
* @see https://gist.github.com/Zn4rK/ed60c380e7b672e3089074f51792a2b8
*/
resolveRequest: (context, moduleName, platform) => {
try {
// Symlinks resolver throws when it can't find what we're looking for.
const res = symlinksResolver(context, moduleName, platform);
if (res) {
return res;
}
} catch {
/**
* If we have an error, we pass it on to the next resolver in the chain,
* which should be one of expos.
* @see https://github.com/expo/expo/blob/9c025ce7c10b23546ca889f3905f4a46d65608a4/packages/%40expo/cli/src/start/server/metro/withMetroResolvers.ts#L47
*/
return context.resolveRequest(context, moduleName, platform);
}
},
},
/**
* Add the monorepo paths to the Metro config.
* This allows Metro to resolve modules from the monorepo.
*
* @see https://docs.expo.dev/guides/monorepos/#modify-the-metro-config
*/
watchFolders: [monorepoRoot],
/**
* Move the Metro cache to the `node_modules/.cache/metro` folder.
* This repository configured Turborepo to use this cache location as well.
* If you have any environment variables, you can configure Turborepo to invalidate it when needed.
* @see https://turbo.build/repo/docs/reference/configuration#env
*/
cacheStores: [
new FileStore({
root: path.join(projectDir, "node_modules", ".cache", "metro"),
})
]
};
/** @type {import('expo/metro-config').MetroConfig} */
const svgConfig = {
resolver: {
assetExts: defaultConfig.resolver.assetExts.filter((ext) => ext !== "svg"),
sourceExts: [...defaultConfig.resolver.sourceExts, "svg"],
},
transformer: {
// <3 -> https://github.com/kristerkari/react-native-svg-transformer/issues/141
assetPlugins: ['expo-asset/tools/hashAssetFiles'],
babelTransformerPath: require.resolve('react-native-svg-transformer/expo'),
},
};
/**
* Merging configs do not deeply merge arrays/functions. Keep this in mind to not
* override important properties. Order matters!
*
* @see https://metrobundler.dev/docs/configuration/#merging-configurations
*/
const finalConfig = makeMetroConfig(mergeConfig(defaultConfig, monorepoConfig, svgConfig));
/**
* Nativewind config must come last! Internally it uses withCssInterop to
* resolve css imports. If this is overridden, Nativewind will not work.
*
* @see https://github.com/nativewind/nativewind/issues/972#issuecomment-2329660147
*
* Striking a balance between Nativewind and rnx-kit was tricky
*
* @see https://github.com/nativewind/nativewind/issues/926
*/
module.exports = withNativeWind(finalConfig, {
input: path.join(projectDir, "./src/global.css"),
configPath: path.join(projectDir, "./tailwind.config.ts")
});
For official first-class support in Expo, it looks like non-hoisted pnpm support is scheduled for Expo SDK 52 - mentioned in @byCedric's post in the pnpm repo:
I'm revisiting this issue with React Native 0.76.1, and I still can't build with PNPM.
The experimental symlink support in Metro is now experimental no longer, and is enabled by default, which is good. But the earlier workaround with watchFolders: [path.join(__dirname, '..', '..')],
doesn't work any more.
I'm not using Expo.
Current error in Xcode is:
RunLoopObserver 'react/debug/react_native_assert.h' file not found
When I temporarily swapped out PNPM for Yarn, my app would build and launched the Simulator, so I'm pretty sure that it's (still) and PNPM/Symlink issue.
Update Actually, with an empty React Native text app, Xcode does build with PNPM in a monorepo. (I should have checked that first, of course.)
The errors above are something more specific to my actual app. I ended up going back to Yarn to work around it.
@brownieboy Metro’s symlink support is stable and enabled, but Metro only bundles your JavaScript and assets.
If you’re seeing errors about missing headers from Xcode, that’s not Metro. The RN community CLI may not fully support symlinks with native dependency autolinking.
Description
I have PNPM working with the new, experimental symlink support in RN 0.72.3. But it only works for me for a single RN package in a repo. It doesn't work for me in a Monorepo set up.
In my monorepo
pnpm ios
from the apps/app1 folder throws this error:pnpm android
throws this error:react-native
is in the apps/app1/node_modules folder, although it's a symlink (which is how PNPM works). That android/settings.gradle file also is there, and not as a symlink this time.React Native Version
0.72.3
Output of
npx react-native info
npx react-native info info Fetching system and libraries information... System: OS: macOS 13.3.1 CPU: (8) arm64 Apple M1 Memory: 68.48 MB / 16.00 GB Shell: version: "5.9" path: /bin/zsh Binaries: Node: version: 18.9.0 path: ~/Library/Caches/fnm_multishells/87821_1689716195576/bin/node Yarn: version: 1.22.19 path: ~/Library/Caches/fnm_multishells/87821_1689716195576/bin/yarn npm: version: 8.19.1 path: ~/Library/Caches/fnm_multishells/87821_1689716195576/bin/npm Watchman: version: 2023.06.12.00 path: /opt/homebrew/bin/watchman Managers: CocoaPods: version: 1.12.1 path: /Users/michaelbrown/.rvm/gems/ruby-3.0.0/bin/pod SDKs: iOS SDK: Platforms:
Steps to reproduce
Add new file, pnpm-workspace.yaml at root repo level:
That file is required for PNPM monorepo support, as PNPM does not use the
packages
field in the package.json.Run
pnpm i
to (re)install the dependencies.Enable the experimental symlink support in file apps/app1/metro.config.js:
Snack, code example, screenshot, or link to a repository
https://github.com/brownieboy/test-rn72-pnpm-monorepo