- Published on
Navigating React Native Module Resolution: Lessons from Yesterday's Battle
- Authors
- Name
- Paras Daryanani
- @parasdaryanani
Yesterday, I was deep in the trenches grappling with module resolution in React Native. If you've been there, you know the feeling. If not, let me spare you the pain with some things I learned along the way.
1. Package exports need opting in.
If you're using newer npm libraries that use package exports, metro will complain that the module doesn't exist.
error: Error: Unable to resolve module ...
Infuriating, and confusing especially because VS Code autocomplete tells you the file is right there. Turns out, package exports are an unstable feature in Metro, which currently require explicit opt-in.
In your metro config, enable module resolution from package exports like this:
/**
* Metro configuration
* https://facebook.github.io/metro/docs/configuration
*
* @type {import('metro-config').MetroConfig}
*/
const config = {
resolver: {
unstable_enablePackageExports: true,
},
};
This works for react native 0.72 and up. You can read more about it here.
Now, if you're using Expo (version 0.49 when I wrote this), there's another layer to this.
2. Expo doesn't enable ESM modules by default
I.e. if your packages have .mjs
module files in their package.json, you've got a bit more to do, as Expo doesn't include .mjs
files by default.
Here's how you direct Metro to read .mjs
files:
/**
* Metro configuration
* https://facebook.github.io/metro/docs/configuration
*
* @type {import('metro-config').MetroConfig}
*/
const config = {
resolver: {
unstable_enablePackageExports: true,
sourceExts: config.resolver.sourceExts.push('mjs'),
},
};
You might think that's it, but hang on...
3. Not all ESM syntax is supported as yet
For instance, packages using import.meta
won't work in react native, resulting in undefined
errors during compilation.
You've got some options:
- Either, turn off
unstable_enablePackageExports
, though this destroys the purpose if you really need package exports. - Or, force react native to revert to
commonjs
for modules with unsupported ESM syntax. For the latter, tweak thepackage.json
of the problematic npm package innode_modules
. Direct theimport
property to the.js
instead of the.mjs
file:
".": {
"types": "./index.d.ts",
"import": {
"types": "./esm/index.d.mts",
// "default": "./esm/index.mjs",
"default": "./esm/index.js"
},
"module": "./esm/index.js",
"default": "./index.js"
},
After making the adjustments, give metro a refresh. Remember to use patch-package
to keep these changes in your git repo.
You might still see some Metro warnings in your terminal, indicating it's falling back to filesystem resolution for packages without defined exports. Don't worry, it's harmless and works just fine.
I hope my day's struggles have paved a smoother path for you. Keep coding, and remember that every challenge is an opportunity to learn and grow!