Repository navigation
Conversation
Since React Native 0.88, `@react-native/babel-preset` inlines `Platform.OS` and `Platform.select` itself (react/react-native#57848), whenever Metro sets `caller.inlinePlatform`: https://github.com/react/react-native/blob/v0.89.0-rc.0/packages/react-native-babel-preset/src/configs/main.js#L165-L167 Metro's own implementation in `inline-plugin` runs after ESM has been lowered to CommonJS, so it can only match on names. It inlines `.OS` on any top-level binding called `Platform`, whether or not it's React Native's, and misses some genuine imports. RN's plugin tracks bindings back to React Native's `Platform` module, so Metro's has been redundant since 0.88, and occasionally wrong. This removes platform inlining from `inline-plugin`, which still inlines `__DEV__` and `process.env.NODE_ENV`, and narrows its options to `{dev}`. Metro still sets the `inlinePlatform` transform option and passes it through to Babel - that's what enables RN's plugin. Projects on React Native < 0.88 with this Metro will lose platform inlining, so this is breaking. RN and Expo both pin Metro, so in practice that only affects projects overriding Metro's version. Expo's fork of the transform worker already skips `inlinePlugin`. Changelog: ``` - **[Breaking]**: Remove Metro's `Platform.OS` / `Platform.select` inlining, which `@react-native/babel-preset` performs since React Native 0.88 ``` Test plan: Built a React Native 0.89.0-rc.0 app (`@react-native/metro-config` and `@react-native/babel-preset` from npm) with this branch's transform worker, for iOS and Android, dev and prod, unminified, and compared against `main`. The entry point reads `Platform.OS` through a named import, a namespace import, a deep import of `Libraries/Utilities/Platform` and `require('react-native').Platform`, and calls `Platform.select`. All are inlined on both. The bundles, including all of React Native's own `Platform` uses, are byte-identical except for one line in a local module that declares an unrelated `const Platform = {OS: ...}`, which `main` wrongly inlined: ```diff - var os = exports.os = "ios"; + var os = exports.os = Platform.OS; ```
Metro review: Looks goodRisk: medium · Commit: This PR removes No findings. Verified
Not run: I didn't repeat the author's end-to-end test (comparing React Native 0.89.0-rc.0 app bundles against main). I did check the preset code it depends on. I didn't benchmark: the change only removes visitor work from the per-file transform worker and claims no performance gain. Nothing here is Windows-specific, so I didn't run anything on Windows. Automated review by Claude. Advisory only: it never approves or blocks, and a maintainer makes the call. |
Since React Native 0.88,
@react-native/babel-presetinlinesPlatform.OSandPlatform.selectitself (react/react-native#57848), whenever Metro setscaller.inlinePlatform:https://github.com/react/react-native/blob/v0.89.0-rc.0/packages/react-native-babel-preset/src/configs/main.js#L165-L167
Metro's own implementation in
inline-pluginruns after ESM has been lowered to CommonJS, so it can only match on names. It inlines.OSon any top-level binding calledPlatform, whether or not it's React Native's, and misses some genuine imports. RN's plugin tracks bindings back to React Native'sPlatformmodule, so Metro's has been redundant since 0.88, and occasionally wrong.This removes platform inlining from
inline-plugin, which still inlines__DEV__andprocess.env.NODE_ENV, and narrows its options to{dev}. Metro still sets theinlinePlatformtransform option and passes it through to Babel - that's what enables RN's plugin.Projects on React Native < 0.88 with this Metro will lose platform inlining, so this is breaking. RN and Expo both pin Metro, so in practice that only affects projects overriding Metro's version. Expo's fork of the transform worker already skips
inlinePlugin.Changelog:
Test plan:
Built a React Native 0.89.0-rc.0 app (
@react-native/metro-configand@react-native/babel-presetfrom npm) with this branch's transform worker, for iOS and Android, dev and prod, unminified, and compared againstmain. The entry point readsPlatform.OSthrough a named import, a namespace import, a deep import ofLibraries/Utilities/Platformandrequire('react-native').Platform, and callsPlatform.select. All are inlined on both.The bundles, including all of React Native's own
Platformuses, are byte-identical except for one line in a local module that declares an unrelatedconst Platform = {OS: ...}, whichmainwrongly inlined: