Repository navigation
Metro nativeResolver skips className support for all node_modules when the project path contains a react-native directory #684
Description
What happened?
On native platforms, Uniwind stops applying className styles to every component that comes from node_modules (e.g. all of HeroUI Native's Card, Surface, Button, etc. render with no background, padding, radius or fill) whenever the app's absolute path contains a directory named react-native, e.g. ~/Developer/react-native/my-app. The same class strings work on Views in the app's own source.
Root cause: nativeResolver in packages/uniwind/src/bundler/adapters/metro/resolvers.ts decides whether a module is React Native internals with a substring match on the whole absolute path:
const isFromNodeModules = context.originModulePath.includes(`${sep}node_modules${sep}`)
const isFromReactNative = context.originModulePath.includes(`${sep}react-native${sep}`)
|| context.originModulePath.includes(`${sep}@react-native${sep}`)
// ...
|| (isFromReactNative && isFromNodeModules && !isReactNativeAnimated) // Is from react-native but not AnimatedFor /Users/me/Developer/react-native/my-app/node_modules/heroui-native/lib/module/components/surface/surface.js, both flags are true (because of the parent react-native/ folder), so the react-native → uniwind/components rewrite is skipped for every dependency. App files don't contain /node_modules/, so they keep working, which makes this look like a component-library bug.
Quick check:
const p = '/Users/me/Developer/react-native/my-app/node_modules/heroui-native/lib/module/components/surface/surface.js'
p.includes('/node_modules/') && p.includes('/react-native/') // true → resolver skips the swapSuggested fix (only look at the path after the last node_modules segment). We're running this as a local pnpm patch, and it fixes the problem while keeping the React Native internals and the Animated exception behaving as before:
const afterNodeModules = context.originModulePath.split(`${sep}node_modules${sep}`).at(-1) ?? ''
const isFromReactNative = afterNodeModules.startsWith(`react-native${sep}`)
|| afterNodeModules.startsWith(`@react-native${sep}`)(startsWith('react-native' + sep) also avoids matching sibling packages like react-native-svg.)
Steps to Reproduce
mkdir -p /tmp/react-native && cd /tmp/react-native. The parent folder name is what matters.- Create an Expo app there and set up Uniwind + HeroUI Native per their quick-starts (
withUniwindConfiginmetro.config.js,global.cssimportingtailwindcss,uniwind,heroui-native/styles, app wrapped inGestureHandlerRootView+HeroUINativeProvider). - Render
<Card><Card.Body><Card.Title>Hi</Card.Title></Card.Body></Card>and<Button>Press</Button>. - Run on Android. The Card and Button have no background, radius, padding or fill.
- Move the same project to a path without a
react-nativesegment (e.g./tmp/rn/…), clear the Metro cache, and run again. The components are styled correctly.
Snack or Repository Link
No repository link: the bug depends only on the directory the project is cloned into, not on its contents, so any repo reproduces it once it's placed under a react-native/ folder (steps above). Happy to put one up if you'd still like it.
Uniwind version
1.12.0 (the same code is on main)
React Native Version
0.86.3 (Expo SDK 57; heroui-native 1.0.9 and 1.0.10)
Platforms
Android (the code path is the native resolver, so iOS should be affected the same way)
Expo
Yes
Additional information
- I've searched for similar issues in this repository and found none (isInternal guard compares Metro origin paths against a require.resolve'd base — pnpm symlink layouts misclassify uniwind's own files (react-native → uniwind/components self-rewrite) #598 is a different
isInternalpath-classification bug in the same resolver)
Activity
github-actions commentedon Sep 21, 2026
This issue must be reported using the official issue templates: Bug report or Bug report (Uniwind Pro).