Skip to content

Babel preset: Remove jsx-source and jsx-self plugins - #59775

Merged
meta-codesync[bot] merged 1 commit into
mainfrom
pr59775
Nov 3, 2026
Merged

meta-codesync[bot] merged 1 commit into
mainfrom
pr59775

Conversation

@robhogan

@robhogan robhogan commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

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-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. 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-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 Use metro:runtime for asyncRequireModulePath so Metro's transform cache is shareable across checkouts #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.

## 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.
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Nov 3, 2026
@robhogan
robhogan requested review from huntie and javache November 3, 2026 09:47
@robhogan
robhogan marked this pull request as ready for review November 3, 2026 09:47
@robhogan

robhogan commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator Author

(CC @hoxyq)

@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Nov 3, 2026
@meta-codesync

meta-codesync Bot commented Nov 3, 2026

Copy link
Copy Markdown

@javache has imported this pull request. If you are a Meta employee, you can view this in D129319560.

@meta-codesync
meta-codesync Bot merged commit 305ab93 into main Nov 3, 2026
117 checks passed
@react-native-bot

Copy link
Copy Markdown
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?

@react-native-bot react-native-bot added the Merged This PR has been merged. label Nov 3, 2026
@javache
javache deleted the pr59775 branch November 3, 2026 21:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants