You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Under Vite there is nothing that performs the react-native → react-native-css/components swap, so every className is dropped. The page still renders — same DOM, same text, no error, no warning — it is just unstyled. That makes it easy to ship without noticing.
Opening this before a PR, per CONTRIBUTING's guidance to discuss API changes first. I have a working implementation and would be glad to submit it, adjust the approach, or drop it if you would rather solve this differently.
Two apps, byte-identical except for one Vite plugin, plus a script that asserts computed styles rather than "did it render":
[broken] className in DOM: false computed size: null x null
[fixed] className in DOM: true computed size: 320px x 160px
broken
fixed
Why it happens
NativeWind 4 exported a JSX runtime, so the documented Other Bundlers recipe worked anywhere. Its third requirement is no longer satisfiable on v5 — nativewind@5.0.0-preview.4 exports only ., ./babel, ./metro, ./types, ./theme, and setting jsxImportSource: "nativewind" fails the build:
Error: Missing "./jsx-dev-runtime" specifier in "nativewind" package
The work moved here, into a Metro-only resolver. I understand from the README that Metro is the officially supported bundler and that contributions for others are welcome — this is that contribution.
Proposed approach
Add a react-native-css/vite export applying the mapping nativeResolver already uses:
react-native-css/components is already a barrel re-exporting react-native with the wrappers layered on top, so no new module is introduced and the component list cannot drift.
I first tried porting webResolver (rewriting react-native-web/dist/exports/<X>/index.js → components/<X>) and abandoned it:
Rollup resolvers do not run during dependency pre-bundling. Making the rewrite fire requires excluding react-native-web from optimizeDeps, which exposes its CommonJS dependencies to the browser as raw CJS — inline-style-prefixer, fbjs, styleq, and others, each needing its own optimizeDeps.include entry, down to deep paths like inline-style-prefixer/lib/plugins/crossFade.js.
Both react-native and react-native-web must be matched, because vite-plugin-rnw applies that alias before user plugins run. Matching only react-native silently no-ops.
The mapping needs registering twice: as a Vite plugin for source files, and as an esbuild plugin in optimizeDeps.esbuildOptions.plugins for pre-bundled dependencies, since esbuild does not run Rollup resolvers.
Status
Implemented on p-larson/react-native-css@feat/vite-resolver: yarn lint, yarn typecheck, and the full yarn test suite (1056 passing) are green, with 5 new resolver tests. vite is added as an optional peer dependency so Metro-only users are unaffected. I also packed the branch and ran the reproduction against the real react-native-css/vite export end-to-end.
Happy to open the PR if the approach looks reasonable.
Summary
Under Vite there is nothing that performs the
react-native→react-native-css/componentsswap, so everyclassNameis dropped. The page still renders — same DOM, same text, no error, no warning — it is just unstyled. That makes it easy to ship without noticing.Opening this before a PR, per CONTRIBUTING's guidance to discuss API changes first. I have a working implementation and would be glad to submit it, adjust the approach, or drop it if you would rather solve this differently.
Reproduction: https://github.com/p-larson/nativewind-vite-storybook-repro
Two apps, byte-identical except for one Vite plugin, plus a script that asserts computed styles rather than "did it render":
Why it happens
NativeWind 4 exported a JSX runtime, so the documented Other Bundlers recipe worked anywhere. Its third requirement is no longer satisfiable on v5 —
nativewind@5.0.0-preview.4exports only.,./babel,./metro,./types,./theme, and settingjsxImportSource: "nativewind"fails the build:The work moved here, into a Metro-only resolver. I understand from the README that Metro is the officially supported bundler and that contributions for others are welcome — this is that contribution.
Proposed approach
Add a
react-native-css/viteexport applying the mappingnativeResolveralready uses:react-native-css/componentsis already a barrel re-exportingreact-nativewith the wrappers layered on top, so no new module is introduced and the component list cannot drift.I first tried porting
webResolver(rewritingreact-native-web/dist/exports/<X>/index.js→components/<X>) and abandoned it:Rollup resolvers do not run during dependency pre-bundling. Making the rewrite fire requires excluding
react-native-webfromoptimizeDeps, which exposes its CommonJS dependencies to the browser as raw CJS —inline-style-prefixer,fbjs,styleq, and others, each needing its ownoptimizeDeps.includeentry, down to deep paths likeinline-style-prefixer/lib/plugins/crossFade.js.It rewrites
react-native-web's own internal imports, producing exactly the initialization cycle in babel import-plugin still rewrites react-native-web internals, causing a circular-import crash on web (incomplete fix of #196 / #202) #380.Following
nativeResolveravoids both —react-native-webstays pre-bundled and its internals are never touched.Two details that are easy to get wrong:
react-native-cssmust be skipped (mirroringisFromThisModule). The barrel re-exportsreact-nativeand each wrapper uses its base component at module scope, so redirecting them recreates the babel import-plugin still rewrites react-native-web internals, causing a circular-import crash on web (incomplete fix of #196 / #202) #380 cycle.react-nativeandreact-native-webmust be matched, becausevite-plugin-rnwapplies that alias before user plugins run. Matching onlyreact-nativesilently no-ops.The mapping needs registering twice: as a Vite plugin for source files, and as an esbuild plugin in
optimizeDeps.esbuildOptions.pluginsfor pre-bundled dependencies, since esbuild does not run Rollup resolvers.Status
Implemented on
p-larson/react-native-css@feat/vite-resolver:yarn lint,yarn typecheck, and the fullyarn testsuite (1056 passing) are green, with 5 new resolver tests.viteis added as an optional peer dependency so Metro-only users are unaffected. I also packed the branch and ran the reproduction against the realreact-native-css/viteexport end-to-end.Happy to open the PR if the approach looks reasonable.
Environment
react-native-cssnativewindreact-native-webvite@storybook/react-native-web-vite