Describe the bug
With react-native-worklets' bundle mode enabled (getBundleModeMetroConfig), the app crashes on launch, before AppRegistry registers anything:
RangeError: Maximum call stack size exceeded (native stack depth)
Invariant Violation: "main" has not been registered.
The stack is get NativeModules repeated, from the lazy getters in react-native-css/dist/commonjs/components/index.cjs.
Cause
Two Metro resolvers both rewrite react-native, and react-native-css hands its own react-native imports to the resolver below it:
- App code imports
react-native. Worklets bundle mode resolves it to react-native-worklets/bundleMode/shims/reactNativeShim.js.
- The shim runs
module.exports = require('react-native'). react-native-css's nativeResolver redirects that to react-native-css/components.
react-native-css/components/index.cjs imports react-native. Because the origin is internal, nativeResolver returns the parent resolver's result, and the parent (worklets) sends it back to the shim.
- The shim's exports are the react-native-css components, whose getters call
require('react-native'), which returns the shim again. The getters recurse forever.
It loops whichever order the two configs are applied in. nativeResolver already exempts react-native/index.js as an origin. The internal-origin path has a similar problem: it trusts the parent resolver to return the real package.
Workaround (in metro.config.js, after both wrappers):
const path = require('node:path');
const reactNativeCssDir = `${path.sep}node_modules${path.sep}react-native-css${path.sep}`;
const resolveRequest = config.resolver.resolveRequest;
config.resolver.resolveRequest = (context, moduleName, platform) =>
moduleName === 'react-native' &&
context.originModulePath.includes(reactNativeCssDir)
? context.resolveRequest(context, moduleName, platform)
: resolveRequest(context, moduleName, platform);
Suggested fix: in nativeResolver, resolve react-native from an internal origin with Metro's default context.resolveRequest instead of the parent resolver. react-native-css's components always need the real package.
Reproduction
npx rn-new@next --nativewind, add react-native-worklets, then in metro.config.js:
const { getDefaultConfig } = require('expo/metro-config');
const { withNativewind } = require('nativewind/metro');
const { getBundleModeMetroConfig } = require('react-native-worklets/bundleMode');
let config = getDefaultConfig(__dirname);
config = withNativewind(config);
config = getBundleModeMetroConfig(config);
module.exports = config;
Launch on iOS. The crash happens during module init, before any component renders.
Versions
- nativewind 5.0.0-rc.0
- react-native-css 3.1.0-rc.0
- react-native-worklets 0.13.0 (react-native-reanimated 4.7.1)
- react-native 0.86.3, expo 57.0.27
- tailwindcss 4.3.3
- iOS simulator, Hermes
Possibly related: #455 has the same error text, but a different trigger (styled() around react-native-svg at render time).
Describe the bug
With react-native-worklets' bundle mode enabled (
getBundleModeMetroConfig), the app crashes on launch, beforeAppRegistryregisters anything:The stack is
get NativeModulesrepeated, from the lazy getters inreact-native-css/dist/commonjs/components/index.cjs.Cause
Two Metro resolvers both rewrite
react-native, and react-native-css hands its ownreact-nativeimports to the resolver below it:react-native. Worklets bundle mode resolves it toreact-native-worklets/bundleMode/shims/reactNativeShim.js.module.exports = require('react-native'). react-native-css'snativeResolverredirects that toreact-native-css/components.react-native-css/components/index.cjsimportsreact-native. Because the origin is internal,nativeResolverreturns the parent resolver's result, and the parent (worklets) sends it back to the shim.require('react-native'), which returns the shim again. The getters recurse forever.It loops whichever order the two configs are applied in.
nativeResolveralready exemptsreact-native/index.jsas an origin. The internal-origin path has a similar problem: it trusts the parent resolver to return the real package.Workaround (in
metro.config.js, after both wrappers):Suggested fix: in
nativeResolver, resolvereact-nativefrom an internal origin with Metro's defaultcontext.resolveRequestinstead of the parent resolver. react-native-css's components always need the real package.Reproduction
npx rn-new@next --nativewind, addreact-native-worklets, then inmetro.config.js:Launch on iOS. The crash happens during module init, before any component renders.
Versions
Possibly related: #455 has the same error text, but a different trigger (
styled()around react-native-svg at render time).