Add Inlined React Runtime check for React 19 incompatibilities#1380
Add Inlined React Runtime check for React 19 incompatibilities#1380gunjanjaswal wants to merge 4 commits into
Conversation
Adds a static check that scans a plugin's JavaScript files for a bundled, outdated React runtime that breaks once WordPress upgrades to React 19. The primary, high-confidence signal is `Symbol.for( 'react.element' )`, which is only emitted by an inlined pre-React 19 JSX runtime (React 19 uses the `react.transitional.element` marker). The warning is suppressed when the runtime is externalized, detected via a `window.ReactJSXRuntime` reference or a `react-jsx-runtime` dependency in the sibling `*.asset.php` file. Usage of React APIs removed in React 19 (unmountComponentAtNode, findDOMNode, ReactCurrentOwner) is reported as a secondary signal. Registers the check, adds PHPUnit tests with passing/failing fixtures, and documents it in docs/checks.md and the changelog. Fixes WordPress#1356
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
PHPMD flagged $matched as an undefined variable in look_for_removed_react_apis since it was only created via the by-reference argument. Initialize it first.
…runtime-check # Conflicts: # docs/checks.md # includes/Checker/Default_Check_Repository.php
|
Hello, I've got these findings from Codex. Could you check it? Findings [P2] Removed API regex reports comments/strings as usage |
Address the review feedback on the React 19 runtime check: - Stop treating a react-jsx-runtime dependency in the sibling .asset.php file as proof the runtime is externalized. The Symbol.for( 'react.element' ) marker means the file already inlines a pre-19 runtime, so a declared dependency can hide a stale or mixed build. Only an in-file window.ReactJSXRuntime reference now suppresses the warning. - Ignore the removed-API identifiers when they appear only in comments or string literals, so changelog notes and translation strings no longer produce false positives. Update the fixtures and tests to cover both cases.
|
Thanks @davidperezgar, both are fair points. I pushed a fix for each. P1 (asset dependency bypass): You're right that the P2 (comments and strings): Also right. The raw scan would flag Happy to adjust either if you'd prefer a different approach. |
Closes #1356.
This adds a check (
inlined_react_runtime) for plugins that bundle their own copy of the React JSX runtime. WordPress is going to React 19 at some point, and the usual reason a plugin breaks across that jump isn't some exotic API, it's that the build inlinedreact/jsx-runtimeinto the bundle instead of loading it from WordPress. React 19 changed the shape of the element object, so anything an old bundled runtime creates gets rejected. The plugin runs fine today and then falls over the day WordPress updates, so the point is to catch it ahead of time.The detection is pretty crude, honestly: it greps the plugin's JS for
Symbol.for('react.element'), which only shows up when a pre-19 runtime got bundled in. React 19 switched that marker toreact.transitional.element, so anyone externalizing the runtime properly won't trip it. And if the runtime is externalized there's nothing to warn about, so it stays quiet when it spotswindow.ReactJSXRuntimein the file orreact-jsx-runtimelisted in the matching*.asset.php. On top of that it flags a few APIs that got dropped in 19 (unmountComponentAtNode,findDOMNode,ReactCurrentOwner). Everything's a warning, nothing errors out. It's wired intoDefault_Check_Repositorywith the usual docs and changelog entries.Inlined_React_Runtime_Check_Testscovers both sides: the-with-errorsfixture throws two warnings (inlined_jsx_runtimeon index.js,react_removed_apion legacy.js), and the-without-errorsone stays clean because the runtime's externalized there, once throughindex.asset.phpand once throughwindow.ReactJSXRuntime. I'm not married to the category or severity if you'd rather scope it differently.AI Usage Disclosure
AI assistance (Claude Code) was used to help draft the check and its tests. I reviewed and understand every line and take responsibility for it.