Reputation: 17407
For reasons that are out of my control, I need to resolve a module that is outside of my react-native project directory. So, consider the following directory structure:
react-native-project/
├─ App.jsx
├─ babel.config.js
external-directory/
├─ Foo.jsx
I would like any import Foo from 'Foo'
inside of react-native-project
to resolve ../external-directory/Foo.jsx
. My first attempt at this was to use babel-plugin-module-loader
with the following configuration:
plugins: [
[
'module-resolver',
{
alias: {
Foo: '/absolute/path/to/external-directory/Foo',
},
},
],
],
This doesn't work, with metro emitting the following error:
error: Error: Unable to resolve module /absolute/path/to/external-directory/Foo from /absolute/path/to/react-native-project/App.jsx:
None of these files exist:
* ../external-directory/Foo(.native|.ios.js|.native.js|.js|.ios.jsx|.native.jsx|.jsx|.ios.json|.native.json|.json|.ios.ts|.native.ts|.ts|.ios.tsx|.native.tsx|.tsx)
* ../external-directory/Foo/index(.native|.ios.js|.native.js|.js|.ios.jsx|.native.jsx|.jsx|.ios.json|.native.json|.json|.ios.ts|.native.ts|.ts|.ios.tsx|.native.tsx|.tsx)
This error message is wrong: ../external-directory/Foo.jsx
does exist. I've verified this numerous times. I've also set up a standalone babel package to test an identical import scenario, and babel correctly resolves the external module.
The other approach I took was to add a custom resolveRequest
function in my metro.config.js:
const defaultResolver = require('metro-resolver').resolve;
module.exports = {
...
resolver: {
resolveRequest: (context, moduleName, platform, realModuleName) => {
if (moduleName === 'Foo') {
return {
filePath: '/absolute/path/to/external-directory/Foo.jsx',
type: 'sourceFile',
};
} else {
return defaultResolver(
{
...context,
resolveRequest: null,
},
moduleName,
platform,
realModuleName,
);
}
},
},
};
This also doesn't work, emitting the following error message:
error: ReferenceError: SHA-1 for file /absolute/path/to/external-directory/Foo.jsx (/absolute/path/to/external-directory/Foo.jsx) is not computed.
Potential causes:
1) You have symlinks in your project - watchman does not follow symlinks.
2) Check `blockList` in your metro.config.js and make sure it isn't excluding the file path.
The potential causes do not apply in this scenario: There are no symlinks nor does the blockList contain the external directory (I explicitly configured blockList: null
to verify).
Is there any way to accomplish what I'm trying to do? Or does metro (either by design or incidentally) prevent this?
Upvotes: 2
Views: 6159
Reputation: 71
You can use a metro bundler build in option - extraNodeModules and watchFolders.
const path = require('path');
module.exports = {
resolver: {
...,
extraNodeModules: {
app: path.resolve(__dirname + '/../app')
}
},
...,
watchFolders: [
path.resolve(__dirname + '/../app')
]
};
Upvotes: 7