Open samsnori opened 9 months ago
Workaround
For now, I'm creating a mount point which solves this issue.
Great thing about this solution is that you don't have to change any of the configs either.
cd <home>/main-app
cd app
mkdir shared-lib-mounted
sudo mount --bind ../../shared-lib shared-lib-mounted
I'm very curious why symlinks aren't working though. I'm sure it turns out to be something silly
Hi @samsnori - thanks for the report and particularly for all the detail here.
Could you clarify what import
you're using in your JS/TS source, or what you'd like that to look like?
I'm also curious about the use of extraNodeModules
- normally the values there would be expected to be directories containing package.json
files (ie, valid packages). It sounds like you might be wanting to use something like import {Button} from 'shared-package'
, or are you just using relative paths and it's not working when the relative path includes a symlink?
Hi @robhogan thanks for you reply. In my shared-lib
directory, I've got a couple of JS files that I like to use across projects. These do not belong to a package so there is no index.js or package.json. E.g. for this test I created a file shared-lib/src/components/Button.jsx
which contains:
/* ------------------------------------------------------- */
import { View, Text } from 'react-native';
/* ------------------------------------------------------- */
function Button(props) {
return (
<View>
<Text>This is my fake button</Text>
</View>
);
}
/* ------------------------------------------------------- */
export {
Button
};
Then I would like to import this anywhere in my main-app
like:
import { Button } from 'shared-lib/components/Button'
This works when I use a plain directory (or mount point) but not when using a symlink. This is why I suspect that the symlink is causing this.
Tbh, the extraNodeModules
is something that I copied from one of the many articles I found about this. I haven't tested if things will work when I remove this, I wouldn't think so, but I'll do a test.
Interesting, thanks - tbh Iβm surprised that works at all without a package.json
, but the inconsistency is surprising in any case. An import that isnβt a relative or absolute file path should only resolve under those settings if it begins with a package name.
I donβt think weβve done a lot of testing on the interaction between extraNodeModules
and symlinks, what youβre seeing does seem like a bug one way or another. Iβll see if I can reproduce.
Even more weird,
I have the following dependencies in my shared-lib and it does not work at all giving the following error:
Error: Unable to resolve module @babel/runtime/helpers/asyncToGenerator from /Users/vitorsilvalima/projects/diggy/packages/core/node_modules/zod/lib/helpers/parseUtil.js:
"dependencies": {
"dayjs": "1.10.8",
"mongoose": "^6.7.5",
"zod": "^3.22.4"
}
However, it works if I remove zod or if I install babel-runtime in my shared-lib which makes no sense at all.
Yes, I've experienced that too. The state of RN tooling is extremely sad.
To be honest I think the issue is not entirely the fault of Metro, it's the whole "npm" / package / tooling space. The biggest flaw I see which causes -a lot- of these issues, is that each bundler or packager has it's own module resolution solutions. NPM should have provided a solution that could be used by bundlers instead.
It's also good to realize that Metro is most likely not going to spend time on this; the very first issue that was posted already mentioned similar issues. I understand the main developers have other priorities.
For me, I found a solution which "works" but is ugly.
Even more weird,
I have the following dependencies in my shared-lib and it does not work at all giving the following error:
Error: Unable to resolve module @babel/runtime/helpers/asyncToGenerator from /Users/vitorsilvalima/projects/diggy/packages/core/node_modules/zod/lib/helpers/parseUtil.js:
"dependencies": { "dayjs": "1.10.8", "mongoose": "^6.7.5", "zod": "^3.22.4" }
However, it works if I remove zod or if I install babel-runtime in my shared-lib which makes no sense at all.
I just ran into a similar issue in my project, where I include a module (with package.json, etc.) from an external path. I got Metro to include it by using resolver.extraNodeModules, but it wouldn't use the other dependencies from the local node_modules. After lots of searching, trial & error (and swearing, lots of swearing) I finally found a solution that works (at least for me):
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const path = require("path");
const myExtraModuleDir = path.resolve(__dirname, "../../myExtraModule");
const extraNodeModules = {
'myExtraModule': myExtraModuleDir,
};
const watchFolders = [
// Include extra module dir to work around Metro's bug where resolver.extraNodeModules
// does not work without corresponding watchFolders, see also
// https://github.com/facebook/metro/issues/834
myExtraModuleDir
];
const config = {
watchFolders: watchFolders,
resolver: {
extraNodeModules: new Proxy(extraNodeModules, {
get: (target, name) =>
// redirects dependencies referenced from myExtraModule/ to local node_modules
name in target ? target[name] : path.join(process.cwd(), `node_modules/${name}`),
}),
// unstable_enableSymlinks: true, // defaults to true since Metro v0.79.0
},
resetCache: true, // https://metrobundler.dev/docs/configuration/#resetcache
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
That "Proxy" part did the trick, inspired by this StackOverflow thread: Metro extraNodeModules does not work - Error: Unable to resolve module.
Seriously, this really should be easier and more straightforward.
@stefang42 Thank you, it works for me!
metro=0.80.12
Do you want to request a feature or report a bug?
I've got a question or otherwise a bug report.
What is the current behavior?
I'm trying to import files from a shared library. I've got a git repository in which I store sources that I like to use throughout several applications. This is just a collection of Javascript files. This is not a package (e.g. doesn't have a package.json). This library is stored at
<home>/shared-lib
. I'm now building a React Native app in<home>/main-app/app
and in this main app, I would like to use a file, e.g.<home>/shared-lib/src/components/Button.jsx
.After doing some research it seems that you should be able to get this to work via
metro.config.js
as mentioned:I've created the following files and directory hierarchy. Note that there are several symlinks as I've been experimenting to get this to work. For example notice the
app/shared-lib
,app/shared-lib-nosymlink
, but alsomain-app/shared-lib
andmain-app/shared-lib-no-symlink
. Note the different values fordir_name
in the metro.config.js below, which I've used to test different things in the metro.config.js below. Interestingly, when I use themain-app/app/shared-lib-no-symlink
version everything works fine. But when I try to use a component from any of the symlink directories, I run into an error like: Unable to resolve module shared-lib/src/components/Button.The contents of the
shared-lib-*
directories only contains:I've updated my metro.config.js, from the
<home>/main-app/app/
directory in such a way that it should work with symlinks. E.g.<home>/main-app/app/mettro.config.js
looks like:My goal is to include a source file into my project that is stored in another git repository outside the current React Native project. From my understanding, this should be possible using the metro.config.js as posted above. Obviously this doesn't work. What am I doing wrong?
If the current behavior is a bug, please provide the steps to reproduce and a minimal repository on GitHub that we can
yarn install
andyarn test
.I'm not sure if this is a bug or if I've misunderstood how to do this correctly.
What is the expected behavior?
I would love to be able to use source files that are located somewhere else into my project. These source files do not belong to a package per se; just a repository with sources.
Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system.