Repository navigation
Babel preset: Remove jsx-source and jsx-self plugins - #59775
Merged
Merged
Conversation
## Summary In dev, `@react-native/babel-preset` adds `@babel/plugin-transform-react-jsx-source`, which embeds each file's absolute path in a `_jsxFileName` variable. Nothing has read that value for ordinary JSX since the preset moved to the automatic runtime in react/metro#849 (RN 0.70), because Babel extracts `__source` and discards it unless `development` is set. That leaves an unused declaration in every module with JSX. `createElement` paths (key-after-spread, per-file `@jsxRuntime classic`) do still pass `__source`, but React has ignored it since react/react#28265 (React 19). Source locations come from `_debugStack` and source maps instead. This removes both plugins, as `babel-preset-expo` did in expo/expo#45351. The motivation is that transforms become independent of the project root. Once #58584 lets checkouts share a transform cache, this also stops one checkout being served another's paths. The only observable difference I know of is that a custom classic factory (`/** @jsx h */`) no longer receives `__source`. I wouldn't expect anyone to be relying on that. ## Changelog [General][Removed] - Babel preset: Remove `@babel/plugin-transform-react-jsx-source` and `@babel/plugin-transform-react-jsx-self`, as React no longer reads their output ## Test plan AI-driven. On main, the RNTester Android dev bundle goes from 270 `_jsxFileName` declarations to zero, and those were the only occurrences of the checkout path, for a 0.75% smaller bundle. The rest ran with this change applied to the installed preset in a 0.88.0 template app (React 19.3.0) plus a probe screen, on an Android emulator: - Bundles: dev bundles built at two project roots are byte-identical except for the `sourceMappingURL` filename. - Shared cache: with `asyncRequireModulePath` set to `metro:runtime/modules/asyncRequire`, as in #58584, and a shared `FileStore`, the second root gets a full cache hit and a byte-identical bundle. Without this change, that bundle carries 71 of the first root's paths. - Runtime: element shape, inspector hierarchy, component stacks, symbolicated frames, LogBox content and open-in-editor target all match the unpatched preset, over 3 rounds per variant and then 6 interleaved. - DevTools: driving the backend over CDP, source locations differ only for LogBox internals, and that set varies per run. - LogBox's hidden frame count varied between runs (10-13) in both variants, with matching app frames. I can't separate the variants at this sample size, but this change doesn't touch that code. Not tested: iOS, physical devices, or the DevTools frontend UI.
robhogan
marked this pull request as ready for review
November 3, 2026 09:47
Collaborator
Author
|
(CC @hoxyq) |
javache
approved these changes
Nov 3, 2026
|
@javache has imported this pull request. If you are a Meta employee, you can view this in D129319560. |
hoxyq
approved these changes
Nov 3, 2026
Collaborator
|
This pull request was successfully merged by @robhogan in 305ab93 When will my fix make it into a release? | How to file a pick request? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes absolute source paths appearing in (dev-only) transform output, which could cause fresh and shared-cache builds to differ cosmetically.
Summary
In dev,
@react-native/babel-presetadds@babel/plugin-transform-react-jsx-source, which embeds each file's absolute path in a_jsxFileNamevariable. Nothing has read that value for ordinary JSX since the preset moved to the automatic runtime in react/metro#849 (RN 0.70), because Babel extracts__sourceand discards it unlessdevelopmentis set. That leaves an unused declaration in every module with JSX.createElementpaths (key-after-spread, per-file@jsxRuntime classic) do still pass__source, but React has ignored it since react/react#28265 (React 19). Source locations come from_debugStackand source maps instead. This removes both plugins, asbabel-preset-expodid in expo/expo#45351.The motivation is that transforms become independent of the project root. Once #58584 lets checkouts share a transform cache, this also stops one checkout being served another's paths.
The only observable difference I know of is that a custom classic factory (
/** @jsx h */) no longer receives__source. At worst, that breaks a fragile assumption in dev only in a very niche case.Changelog
[General][Removed] - Babel preset: Remove
@babel/plugin-transform-react-jsx-sourceand@babel/plugin-transform-react-jsx-self, as React no longer reads their outputTest plan
AI-driven. On main, the RNTester Android dev bundle goes from 270
_jsxFileNamedeclarations to zero, and those were the only occurrences of the checkout path, for a 0.75% smaller bundle.The rest ran with this change applied to the installed preset in a 0.88.0 template app (React 19.3.0) plus a probe screen, on an Android emulator:
sourceMappingURLfilename.asyncRequireModulePathset tometro:runtime/modules/asyncRequire, as in Use metro:runtime for asyncRequireModulePath so Metro's transform cache is shareable across checkouts #58584, and a sharedFileStore, the second root gets a full cache hit and a byte-identical bundle. Without this change, that bundle carries 71 of the first root's paths.Not tested: iOS, physical devices, or the DevTools frontend UI.