Repository navigation
CSS entry module is not wrapped with Expo tree shaking: Property 'require' doesn't exist #696
Description
What happened?
With Expo's tree shaking flags (EXPO_UNSTABLE_METRO_OPTIMIZE_GRAPH=1 EXPO_UNSTABLE_TREE_SHAKING=1), an iOS Release build crashes at launch:
ReferenceError: Property 'require' doesn't exist
The exported bundle has the uniwind CSS entry module at top level, outside a __d(...) module wrapper. Its require('uniwind') is not rewritten to r(d[0]):
var{Uniwind:Uniwind}=require('uniwind');Uniwind.__reinit(t=>({...}),['light','dark'],'<fingerprint>',1,[2]);Without the flags, the same module is wrapped:
__d(function(g,r,i,a,m,e,d){var{Uniwind:o}=r(d[0]);o.__reinit(...)},1,[2]);What we found:
- The uniwind Metro transformer replaces the CSS entry file with JS (
const { Uniwind } = require('uniwind'); Uniwind.__reinit(...)). It transforms that code as<file>.css.jsand setsoutput[0].data.css. Metro keeps the module pathglobal.css. - With
optimizeon, the Metro transform worker does not wrap modules.@expo/metro-configwraps them later, inbuild/serializer/reconcileTransformSerializerPlugin.js. That pass returns early for a path that matches/\.(s?css|sass)$/(line 212 in 58.0.5, line 142 in 57.0.12). So the uniwind module is never wrapped, and itsrequireis never rewritten. - Metro then appends
,<moduleId>,[deps]before the last)of the code. In the output above,1,[2]lands inside the__reinit(...)arguments. - When we removed the CSS check from that line in a local copy, the optimized export wrapped the module correctly and had no top-level
require.
This follows #500. After that issue the code changed from import to require, which moved the failure from Hermes compilation to app launch. The fix may belong in uniwind (for example, a module path that does not end in .css) or in Expo's reconcile pass. We report it here first because uniwind produces JS for the CSS path.
Steps to Reproduce
- Clone the gist below:
git clone https://gist.github.com/a27bd66ef154e9ea222473836c58c0b2.git uniwind-repro && cd uniwind-repro - Run
npm install --legacy-peer-deps. The flag is needed because uniwind's peer range does not matchreact-native@0.88.0-rc.1. - Run
EXPO_UNSTABLE_METRO_OPTIMIZE_GRAPH=1 EXPO_UNSTABLE_TREE_SHAKING=1 npx expo export --platform ios --no-bytecode --output-dir dist-opt. - Run
grep -c "^var{Uniwind:Uniwind}=require('uniwind')" dist-opt/_expo/static/js/ios/*.js. It prints1. - Run the same export without the two variables (
--output-dir dist-plain). The samegrepprints0. - In a Release build with the two variables set, the app crashes at launch with
ReferenceError: Property 'require' doesn't exist.
Snack or Repository Link
https://gist.github.com/peterferguson/a27bd66ef154e9ea222473836c58c0b2
Uniwind version
1.12.0 (also reproduced on 1.6.4)
React Native Version
0.88.0-rc.1
Platforms
iOS (Android not tested)
Expo
Yes: expo 58.0.0-preview.4, @expo/metro-config 58.0.5 (the crash in our app is on 58.0.4)
Activity
github-actions commentedon Oct 1, 2026
New release v1.12.1 is published: https://github.com/uni-stack/uniwind/releases/tag/v1.12.1