Commit 2dc5e3a
Inline
Summary:
Adds a React Native-owned Babel plugin that inlines `Platform.OS` and
`Platform.select(...)`, from
`react-native/babel-preset` at the front of the preset's plugin list (importantly, before
the preset lowers ES modules to CommonJS).
Metro already inlines `Platform`, but its matcher (`metro-transform-plugins`'
`inline-plugin` via `createInlinePlatformChecks`) runs *after* ESM has been
lowered to CommonJS. By then a genuine `import {Platform} from 'react-native'`
has become `_reactNative.Platform.OS` and the specifier proving the value came
from React Native is gone. Metro compensates by matching on the local
identifier spelling - so `Platform.OS` inlines whether or not `Platform` is
actually React Native's, and a genuine deep or RN-relative import may be missed entirely.
`Platform` inlining is in any case much more of an RN concern than a Metro one - it has to be aware of RN APIs and module names, and even the module’s path.
This plugin recognises:
- `import {Platform} from 'react-native'` (including aliased imports)
- `import * as RN from 'react-native'`, uses of `RN.Platform`
- `import P from 'react-native/Libraries/Utilities/Platform'`
- the equivalent `require` forms, plus destructuring and immutable aliases
- RN's internal relative imports, e.g. `../../Utilities/Platform`
…and deliberately does *not* recognise anything it cannot prove - a bare
`Platform.OS` global, `React.Platform.OS`, or a same-named import from another
package.
Metro's late matcher is left fully enabled and remains responsible for
those historical forms, so this change is purely additive: it inlines genuine
imports Metro was missing, and changes nothing Metro already handled. Metro’s plugin will be deprecated and removed in future.
Notable details:
- Relative RN imports are resolved lexically, with no filesystem access and no
platform-extension resolution — the identity we need is the extension-less
module `<rn-root>/Libraries/Utilities/Platform`, and Metro picks
`Platform.ios.js` / `Platform.android.js` later. The RN package root is
identified by directory name, which covers `node_modules/react-native`,
`packages/react-native` and pnpm layouts alike, and rejects
`react-native-web` and friends (who would be expected to adjust the paths in their forks)
- Imports are left in place. Removing them would change dependency collection,
so it is handled separately.
- A no-platform build (`null`, or the empty string that RN's Jest preprocessor
passes) is a no-op — inlining `Platform.OS` to `""` would be wrong.
- The plugin source is added to the preset's `getCacheKey` so edits invalidate Metro's transform cache.
Changelog:
[General][Changed] - Inline `Platform.OS` and `Platform.select(...)` for
React Native `Platform` imports during the Babel preset, covering some cases that were previously left un-inlined.
Differential Revision: D114647943Platform within RN’s Babel preset1 parent 3f3425e commit 2dc5e3a
5 files changed
Lines changed: 1261 additions & 0 deletions
File tree
- packages
- react-native-babel-preset/src
- __tests__
- configs
- react-native-babel-transformer/src/__tests__
0 commit comments