Skip to content

Commit f167e26

Browse files
build: Enable React Compiler for Browserify builds, fix react-compiler/react-compiler ESLint rule violations (#37480)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## Motivation This commit enables React Compiler for Babel-transformed Browserify builds, and for ESLint (via the `react-compiler/react-compiler` ruleset). We can expect long-term UI performance benefits and developer time savings from this change. The Compiler transparently adds memoization code for React components and hooks, among other optimizations, and enforces React best practices. ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Because enabling React Compiler requires addressing all violations of the `react-compiler/react-compiler` rule, this commit contains a large number of formatting changes and renames that do not require close review, alongside refactors and logical changes that do. I would suggest that reviewers primarily focus on whether a given change is problematic, rather than on whether it is necessary. If the motivation for any change is unclear, it's safe to assume that it fixes an error thrown in CI. The objective of this commit is to ship fixes that unblock React Compiler without introducing regressions in functionality or performance. Suggestions on implementing React best practices will be catalogued and addressed in follow-up tickets. The 10% bundle size increase is due to new memoizations being applied as React Compiler transforms files during the build process, which is the tradeoff for improvements in runtime interaction and responsiveness metrics. Despite this change, the UI startup and pageLoad benchmark results show no evidence of degradations in initial load time. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/37480?quickstart=1) ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null (non-user facing but regressions possible) ## **Related issues** - Epic: #33059 - Previous: #37383 - Next: #38007 ## **Manual testing steps** 1. Create a Browserify dev build by running `yarn start`. 2. Inspect `./dist/(chrome|firefox)/ui-[3-17].js`. 3. Search for "`_reactCompilerRuntime.c`". 4. There should be many examples of React Compiler-optimized code that uses a `$` variable e.g. ```js const $ = (0, _reactCompilerRuntime.c)(22); const { pathname } = (0, _reactRouterDomV5Compat.useLocation)(); const dispatch = (0, _reactRedux.useDispatch)(); const t = (0, _useI18nContext.useI18nContext)(); let t0; if ($[0] !== pathname) { t0 = (0, _snaps2.decodeSnapIdFromPathname)(pathname); $[0] = pathname; $[1] = t0; } else { t0 = $[1]; } ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Enables React Compiler in Browserify Babel builds and enforces the react-compiler ESLint rule, with broad hook/memoization refactors, selector renames, tests updates, and dependency/policy changes. > > - **Build/Tooling**: > - Enable React Compiler via Babel override for `ui/**/{components,contexts,hooks,layouts,pages}` with `babel-plugin-react-compiler` (target 17). > - Add `react-compiler-runtime` and `babel-plugin-react-compiler` deps; update `esbuild`, `koa` (v3), and related tooling. > - Enforce `react-compiler/react-compiler` ESLint rule and plugin across JS/TS React configs. > - **Policies/Config**: > - Extend LavaMoat policies and depcheck ignores for React Compiler packages and updated sub-deps. > - **UI/Hook Refactors (compliance + perf)**: > - Replace patterns violating React Compiler (e.g., `useMemo` state updates, unstable callbacks, missing keys) with `useCallback`/`useRef`/guards; fix array checks, keys, debounce handling, and effect deps. > - Improve polling hooks (`usePolling`, `useMultiPolling`) with input change detection and cleanup; stabilize navigation and debounce handlers. > - Add `isNativeAsset` and use in `AssetPage`; compute asset balances immutably. > - **Reliability/Null Safety**: > - Guard optional `request?.metadata?.id` across confirmations/snaps flows; miscellaneous null-safe checks. > - **Selectors/Types**: > - Rename selectors: `useSafeChainsListValidationSelector` → `getUseSafeChainsListValidation`; `use4ByteResolutionSelector` → `getUse4ByteResolution` (and propagate). > - Tighten types (e.g., `ownerId` optional handling, asset type helpers). > - **Tests**: > - Update tests to use `renderHook` for hooks; adjust mocks to renamed selectors and new patterns. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c47e3f6. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: MetaMask Bot <[email protected]>
1 parent c9eaf77 commit f167e26

File tree

119 files changed

+2475
-1581
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

119 files changed

+2475
-1581
lines changed

.depcheckrc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ ignores:
88
- '@lavamoat/webpack'
99
- '@lavamoat/allow-scripts'
1010
- '@babel/runtime'
11+
- 'react-compiler-runtime'
1112
- '@fortawesome/fontawesome-free'
1213
- 'punycode'
1314
# injected via build system
@@ -83,6 +84,7 @@ ignores:
8384
- 'core-js-pure' # polyfills
8485
# babel
8586
- '@babel/plugin-transform-logical-assignment-operators'
87+
- 'babel-plugin-react-compiler'
8688
# used in image optimization script
8789
- 'sharp'
8890
# trezor

.eslintrc.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,9 @@ module.exports = {
320320
jsx: true,
321321
},
322322
},
323-
plugins: ['react'],
323+
plugins: ['react', 'react-compiler'],
324324
rules: {
325+
'react-compiler/react-compiler': 'error',
325326
'react/no-unused-prop-types': 'error',
326327
'react/no-unused-state': 'error',
327328
'react/jsx-boolean-value': 'error',
@@ -362,8 +363,9 @@ module.exports = {
362363
jsx: true,
363364
},
364365
},
365-
plugins: ['react'],
366+
plugins: ['react', 'react-compiler'],
366367
rules: {
368+
'react-compiler/react-compiler': 'error',
367369
'react/no-unused-prop-types': 'warn',
368370
'react/no-unused-state': 'warn',
369371
'react/jsx-boolean-value': 'off',

babel.config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,23 @@ const path = require('path');
22

33
module.exports = function (api) {
44
api.cache(false);
5+
const slash = `\\${path.sep}`;
56
return {
67
parserOpts: {
78
strictMode: true,
89
},
910
targets: {
1011
browsers: ['chrome >= 89', 'firefox >= 89'],
1112
},
13+
overrides: [
14+
{
15+
test: new RegExp(
16+
`^${path.join(__dirname, 'ui')}${slash}(?:components|contexts|hooks|layouts|pages)${slash}(?:.(?!\\.(?:test|stories|container)))+\\.(?:m?[jt]s|[jt]sx)$`,
17+
'u',
18+
),
19+
plugins: [['babel-plugin-react-compiler', { target: '17' }]],
20+
},
21+
],
1222
plugins: [
1323
// `browserify` is old and busted, and doesn't support `??=` (and other
1424
// logical assignment operators). This plugin lets us target es2020-level

0 commit comments

Comments
 (0)