- Daishi Kato's Read the Code
- Posts
- React Native Confusion with Newer Versions
React Native Confusion with Newer Versions
Behavioral Change with Module Resolution
Hi,
This might be a well-known issue in the React Native community, but recent versions have changed the behavior of module resolution. Don't get me wrong—it’s generally a good move.
Metro and the "exports"
Field
Previously, Metro (the bundler used in React Native) didn't support the "exports"
field in package.json
. It was only available with the opt-in flag unstable_enablePackageExports
.
With this flag enabled, Metro starts to understand and respect the "exports"
field.
Here’s how it looks in Zustand’s package.json
:
🔗 View on GitHub
"exports": {
"./package.json": "./package.json",
".": {
"import": {
"types": "./esm/index.d.mts",
"default": "./esm/index.mjs"
},
"default": {
"types": "./index.d.ts",
"default": "./index.js"
}
},
"./*": {
"import": {
"types": "./esm/*.d.mts",
"default": "./esm/*.mjs"
},
"default": {
"types": "./*.d.ts",
"default": "./*.js"
}
}
}
Roughly speaking:
When the
import
condition is met, the bundler picks the ESM build.Otherwise, it falls back to the CJS build.
If a bundler doesn’t understand the
"exports"
field at all, it defaults to using CJS.
The Hermes and import.meta
Problem
The issue arises because the most-used JavaScript runtime in React Native—Hermes—still does not fully support ESM. It throws an error when encountering import.meta
.
My hope was that Hermes would support import.meta
before unstable_enablePackageExports
became stable.
Unfortunately, that didn't happen.
Now it seems that enablePackageExports
is enabled by default, but Hermes still errors on import.meta
.
The Workaround
From the discussion, I concluded that using the ESM build in React Native is either a bad idea or simply too early. As a workaround, I added a new condition in the exports
field specifically for React Native users.
Final Thoughts
What’s concerning is that my original plan was to eventually drop CJS and fully move to ESM. But that now seems like a bad idea if the entire React Native ecosystem still relies on CJS.
Happy coding.
Reply