React usage check: address review feedback - #2
Merged
gunjanjaswal merged 12 commits intoSep 24, 2026
Merged
gunjanjaswal merged 12 commits into
gunjanjaswal merged 12 commits into
Conversation
The check is about compatibility, not performance: all but one of its results are about code that stops working when WordPress upgrades React. Only the development-build note is about size and speed. Follows the directory convention of the other checks, where the directory and namespace mirror the primary category.
The replacement was substituted into the translated sentence through a placeholder, which works for the APIs whose replacement is a code identifier but not for the two that need prose: "a ref on the element" and "JSX or createElement()" reached the user in English whatever the locale. Give those two the complete sentence as their own translatable string and keep the shared one for the replacements that are code. The reported text is unchanged.
2.0.0 and 2.1.0 are both released, so @SInCE 2.0.0 claimed the check had been available for two releases that never contained it. The next release is 2.2.0. Drop the changelog entry as well. It was inserted into the released 2.0.0 section, and per docs/releasing.md the changelog is written when the release is cut, which is why the other checks added since 2.1.0 do not carry one.
Comments and string literals were blanked with a single regular expression, which failed in two ways. It could not tell a regex literal from a division, so the quote in `var re = /"/g;` opened what looked like a string and blanked the code after it. Any removed API called later in such a file went unreported. PCRE also exhausted its recursion limit on the long string literals of a bundled file. preg_replace_callback then returned null and the fallback handed back the raw contents, so nothing was blanked at all and a mention in a comment was reported as a call, undoing what blanking is for. Walk the contents token by token instead. A slash opens a regular expression where no value precedes it and divides otherwise, which also covers `return/^a$/` and a slash inside a character class. There is no backtracking, so file size no longer matters: a 3 MB literal that used to defeat PCRE now scans in well under a second.
The fingerprints for `react/jsx-runtime` and `react` matched too readily once the file mentioned the element symbol for an unrelated reason, which `react-is` does and which reaches a great many bundles through `prop-types`. `jsxs?\s*[:=]` then matched a syntax highlighter defining `Prism.languages.jsx`, or a parser option object holding `jsx: true`, and reported an error against a plugin with no React problem at all. The same applies to `preact/compat`, which names the element symbol and exports React's internals sentinel while creating Preact vnodes. It never touches the React WordPress ships, yet it was reported as inlining react. Require `_owner`, a field React 19 dropped from the element object, so a package is only implicated when the file also builds pre-19 elements. The renderer is exempt: it consumes elements rather than creating them, so a file holding only a copy of `react-dom` has no factory, and `__reactFiber$` is specific enough by itself. That exemption also stops such a file from being reported as inlining react as well as react-dom. Verified against react, react-dom and react/jsx-runtime for 16, 17 and 18 in both development and production, and against the bundles of astra-sites and wp-table-builder, all of which are still detected.
Positions were counted by splitting on PHP_EOL, the line ending native to the machine running the check. A plugin's line endings have nothing to do with that, so a file written with line feeds collapsed onto line 1 when checked on Windows, and a file written with carriage returns alone collapsed onto line 1 everywhere. Split on all three line endings instead, counting a carriage return followed by a line feed once. The regression fixture uses carriage returns alone, the case that was wrong on every platform and the one line ending git will not rewrite on checkout.
The guard accepted any mention of window.React as proof that the package was externalized, reads and writes alike. A build that publishes itself under the global therefore silenced the very error it should raise: it can only publish a copy it carries, and it replaces the copy WordPress loaded for every script that runs after it. Take a read of the global as proof of externalizing, and let an assignment anywhere in the file override every read in it. The packages now carry the name of their global rather than a pattern, since two patterns are built from it. fiber-inspector.js restores coverage of the read: it is now the only file among those expected to stay silent whose silence depends on the guard.
The marker that establishes a pre-19 build is the name of the element symbol, which was matched only between quotes. Some minifiers rewrite every string in a bundle as a template literal, leaving a build with no quoted string in it at all, and such a file passed as having no React inlined. Accept the backtick alongside the two quotes. Only this marker read a delimiter; the rest match bare substrings.
The bundles WordPress ships patch React 19 into accepting the pre-19 element shape and warning about it, so whether an inlined copy fails outright depends on where its elements end up. Hedge the claim to match, and record in the class docblock why the severity is still an error: the patch is there to carry plugins through the upgrade, not to make the older shape supported. The removed-API warnings keep saying such a call stops working, because those APIs are gone from React 19 with nothing standing in for them.
The comment justified the skip for an inlined renderer, where a removed API found in the file is React's own code, but not for the other two packages, where the call may well be the plugin's own. Record the rest of the reasoning: a deprecated call is a small thing to raise beside a bundled copy of React, and it is not lost, because the marker goes when the inlined copy does and the next run reports it.
1 task
Author
|
@gunjanjaswal This is another batch of improvements for the main PR. Please have a look when you have time. |
jsnajdr
force-pushed
the
feedback/react-usage-check
branch
from
September 24, 2026 09:23
ccabd5e to
43d7f0b
Compare
Author
|
I decided to revert the new |
The check graded a development build above a production one, but nothing recorded why one should outrank the other, and the numbers were close enough to a submission threshold to matter. Report both at the default severity and let the message carry the difference.
A development build was detected by the documentation links React embeds in its warnings, and reported with its own wording. Inlining the package is the problem either way, so the second message and the sniffing behind it bought a branch through the reporting path and little else.
Owner
|
Merged, thanks — this is a big tightening. The |
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.
Addresses review feedback in WordPress#1380 (comment)