Skip to content

Conversation

@MajorLift
Copy link
Contributor

@MajorLift MajorLift commented Nov 3, 2025

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

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

Changelog

CHANGELOG entry: null (non-user facing but regressions possible)

Related issues

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.
  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

Before

After

Pre-merge author checklist

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.

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: useSafeChainsListValidationSelectorgetUseSafeChainsListValidation; use4ByteResolutionSelectorgetUse4ByteResolution (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.

Written by Cursor Bugbot for commit c47e3f6. This will update automatically on new commits. Configure here.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 3, 2025

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbot metamaskbot added the team-extension-platform Extension Platform team label Nov 3, 2025
@socket-security
Copy link

socket-security bot commented Nov 3, 2025

@socket-security
Copy link

socket-security bot commented Nov 3, 2025

Warning

MetaMask internal reviewing guidelines:

  • Do not ignore-all
  • Each alert has instructions on how to review if you don't know what it means. If lost, ask your Security Liaison or the supply-chain group
  • Copy-paste ignore lines for specific packages or a group of one kind with a note on what research you did to deem it safe.
    @SocketSecurity ignore npm/PACKAGE@VERSION
Action Severity Alert  (click "▶" to expand/collapse)
Warn Low
Potential code anomaly (AI signal): npm tsx is 100.0% likely to have a medium risk anomaly

Notes: This fragment appears to be a bundler-generated bootstrap/initialization piece that imports many modules and executes an initialization function (r). No explicit malicious activity is evident within this fragment itself, but the risk stems from side effects of the imported modules on load. A careful review of the implementations of the imported modules (especially those exporting r and those performing initialization, build-time, or network/file operations) is recommended to rule out hidden telemetry, backdoors, or undesired side effects.

Confidence: 1.00

Severity: 0.60

From: package.jsonnpm/[email protected]

ℹ Read more on: This package | This alert | What is an AI-detected potential code anomaly?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at [email protected].

Suggestion: An AI system found a low-risk anomaly in this package. It may still be fine to use, but you should check that it is safe before proceeding.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/[email protected]. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Ignoring alerts on:

View full report

@metamaskbot
Copy link
Collaborator

metamaskbot commented Nov 3, 2025

✨ Files requiring CODEOWNER review ✨

🔑 @MetaMask/accounts-engineers (2 files, +8 -8)
  • 📁 ui/
    • 📁 components/
      • 📁 app/
        • 📁 identity/
          • 📁 backup-and-sync-features-toggles/
            • 📄 backup-and-sync-features-toggles.tsx +8 -7
      • 📁 multichain/
        • 📁 account-list-item-menu/
          • 📄 account-list-item-menu.js +0 -1

👨‍🔧 @MetaMask/core-extension-ux (1 files, +0 -1)
  • 📁 ui/
    • 📁 components/
      • 📁 multichain/
        • 📁 account-list-item-menu/
          • 📄 account-list-item-menu.js +0 -1

🫰 @MetaMask/core-platform (1 files, +3 -0)
  • 📁 ui/
    • 📁 components/
      • 📁 app/
        • 📁 snaps/
          • 📁 snap-ui-renderer/
            • 📄 snap-ui-renderer.js +3 -0

🎨 @MetaMask/design-system-engineers (2 files, +4 -1)
  • 📁 ui/
    • 📁 components/
      • 📁 component-library/
        • 📁 select-wrapper/
          • 📄 select-wrapper.stories.tsx +2 -1
        • 📁 text-field/
          • 📄 text-field.tsx +2 -0

🧩 @MetaMask/extension-devs (8 files, +812 -451)
  • 📁 lavamoat/
    • 📁 browserify/
      • 📁 beta/
        • 📄 policy.json +96 -63
      • 📁 experimental/
        • 📄 policy.json +96 -63
      • 📁 flask/
        • 📄 policy.json +96 -63
      • 📁 main/
        • 📄 policy.json +96 -63
    • 📁 build-system/
      • 📄 policy-override.json +17 -1
      • 📄 policy.json +235 -72
    • 📁 webpack/
      • 📁 mv2/
        • 📄 policy.json +88 -63
      • 📁 mv3/
        • 📄 policy.json +88 -63

💎 @MetaMask/metamask-assets (2 files, +2 -4)
  • 📁 ui/
    • 📁 components/
      • 📁 app/
        • 📁 assets/
          • 📁 token-cell/
            • 📄 token-cell.test.tsx +2 -2
          • 📁 token-list/
            • 📄 token-list.tsx +0 -2

📜 @MetaMask/policy-reviewers (8 files, +812 -451)
  • 📁 lavamoat/
    • 📁 browserify/
      • 📁 beta/
        • 📄 policy.json +96 -63
      • 📁 experimental/
        • 📄 policy.json +96 -63
      • 📁 flask/
        • 📄 policy.json +96 -63
      • 📁 main/
        • 📄 policy.json +96 -63
    • 📁 build-system/
      • 📄 policy-override.json +17 -1
      • 📄 policy.json +235 -72
    • 📁 webpack/
      • 📁 mv2/
        • 📄 policy.json +88 -63
      • 📁 mv3/
        • 📄 policy.json +88 -63

Tip

Follow the policy review process outlined in the LavaMoat Policy Review Process doc before expecting an approval from Policy Reviewers.


🔗 @MetaMask/supply-chain (8 files, +812 -451)
  • 📁 lavamoat/
    • 📁 browserify/
      • 📁 beta/
        • 📄 policy.json +96 -63
      • 📁 experimental/
        • 📄 policy.json +96 -63
      • 📁 flask/
        • 📄 policy.json +96 -63
      • 📁 main/
        • 📄 policy.json +96 -63
    • 📁 build-system/
      • 📄 policy-override.json +17 -1
      • 📄 policy.json +235 -72
    • 📁 webpack/
      • 📁 mv2/
        • 📄 policy.json +88 -63
      • 📁 mv3/
        • 📄 policy.json +88 -63

@MajorLift MajorLift changed the base branch from main to jongsun/chore/251030-enable-rules-of-hooks November 3, 2025 19:48
@metamaskbot
Copy link
Collaborator

Builds ready [3eabf52]
UI Startup Metrics (1311 ± 102 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup13111129155710213891480
load112996813479412041293
domContentLoaded112296113389311991280
domInteractive2314128162151
firstPaint591101134544711231260
backgroundConnect2302192638235246
firstReactRender3120167163548
getState2185072433
initialActions61688617
loadScripts8987381112939701052
setupStore1072631115
numNetworkReqs1367921676
BrowserifyPower User HomeuiStartup20351747278138325552781
load1067914149821113611498
domContentLoaded1059907149021013471490
domInteractive271570174470
firstPaint59819713693749461369
backgroundConnect23621626916252269
firstReactRender27253122731
getState17715029032182290
initialActions51133513
loadScripts834684124120011001241
setupStore1392861228
numNetworkReqs15910331889308318
WebpackStandard HomeuiStartup8266851224948421075
load60454293480608846
domContentLoaded59653590876602820
domInteractive16114981438
firstPaint20855882212169819
backgroundConnect271279133061
firstReactRender28176283336
getState1262841418
initialActions3015349
loadScripts59353390075600812
setupStore1052131216
numNetworkReqs1467519872
WebpackPower User HomeuiStartup13321178194623515311946
load69359610171347801017
domContentLoaded669586916112745916
domInteractive251373205073
firstPaint36983980307619980
backgroundConnect761821472183214
firstReactRender28245982659
getState1396616326154163
initialActions31143514
loadScripts664584905109734905
setupStore96265926
numNetworkReqs1499828675271286
FirefoxBrowserifyStandard HomeuiStartup14771294197313415431743
load1265111316299413221440
domContentLoaded1265111316299413221440
domInteractive1213545460124231
firstPaint------
backgroundConnect4324135205283
firstReactRender26216462644
getState10419720826
initialActions41273312
loadScripts1240109316009013021414
setupStore1265571133
numNetworkReqs1266816761
BrowserifyPower User HomeuiStartup25952290331732928443317
load14731258190520416491905
domContentLoaded14731257190520416481905
domInteractive22796523159362523
firstPaint------
backgroundConnect742717845124178
firstReactRender433267105267
getState15010821034189210
initialActions11146153046
loadScripts14441231187520216231875
setupStore3871705048170
numNetworkReqs1397033599236335
WebpackStandard HomeuiStartup15991412210212716311918
load1365121116268713991541
domContentLoaded1365121116258713991540
domInteractive973023934112158
firstPaint------
backgroundConnect4622134205388
firstReactRender312274133072
getState84436916
initialActions51407417
loadScripts1337119416048313711502
setupStore177207231342
numNetworkReqs1367018767
WebpackPower User HomeuiStartup24872135314734228453147
load14481253179918316771799
domContentLoaded14471253179918316761799
domInteractive1227228866183288
firstPaint------
backgroundConnect1063125275213252
firstReactRender463192185892
getState1197317624134176
initialActions11263161163
loadScripts14121233174017216381740
setupStore3861043677104
numNetworkReqs13461338106240338
📊 Page Load Benchmark Results

Current Commit: 3eabf52 | Date: 11/3/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.05s (±64ms) 🟡 | historical mean value: 1.04s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 737ms (±62ms) 🟢 | historical mean value: 726ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 78ms (±15ms) 🟢 | historical mean value: 77ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.05s 64ms 1.02s 1.37s 1.26s 1.37s
domContentLoaded 737ms 62ms 706ms 1.03s 940ms 1.03s
firstPaint 78ms 15ms 60ms 216ms 88ms 216ms
firstContentfulPaint 78ms 15ms 60ms 216ms 88ms 216ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 68 Bytes (0%)
  • ui: 497.07 KiB (7%)
  • common: 38.75 KiB (0.45%)

@MajorLift MajorLift marked this pull request as ready for review November 4, 2025 12:24
@MajorLift MajorLift requested review from a team as code owners November 4, 2025 12:24
@github-project-automation github-project-automation bot moved this to Needs dev review in PR review queue Nov 4, 2025
@MajorLift MajorLift added the needs-qa Label will automate into QA workspace label Nov 5, 2025
@MajorLift MajorLift dismissed stale reviews from itsyoboieltr and david0xd via 189e390 November 25, 2025 18:46
tokenToFiatConversionRate: Numeric | undefined,
) {
const tokenToFiatConversionRateToString =
tokenToFiatConversionRate?.toString();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Dependency array excludes object causing stale closures

The useCallback dependency array uses tokenToFiatConversionRateToString instead of tokenToFiatConversionRate, but the callback function body references tokenToFiatConversionRate directly. This creates a stale closure where the callback captures an old version of tokenToFiatConversionRate even when its value changes, because toString() might return the same string for different Numeric object instances with the same value. The callback will use outdated conversion rates, causing incorrect currency calculations.

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toString() might return the same string for different Numeric object instances with the same value

  • Yes, we're intentionally taking advantage of this.
  • We're prioritizing preserving existing behavior. We want to minimize disruptive changes.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WONTFIX: Preexisting issue

Bug: Missing dependency in useMemo causes stale filtering

The sortedFilteredTokens useMemo hook uses shouldHideZeroBalanceTokens in its filtering logic on line 117 to determine whether to hide tokens with zero balance, but this variable is missing from the dependency array. When shouldHideZeroBalanceTokens changes, the memoized value won't recompute, causing the token list to continue showing or hiding zero-balance tokens based on the stale value until another dependency triggers a recomputation.

ui/components/app/assets/token-list/token-list.tsx#L92-L151

const sortedFilteredTokens = useMemo(() => {
if (!isMultichainAccountsState2Enabled) {
const balances = isEvm ? evmBalances : multichainAssets;
const filteredAssets = filterAssets(balances as TokenWithFiatAmount[], [
{
key: 'chainId',
opts: isEvm ? networksToShow : { [currentNetwork.chainId]: true },
filterCallback: 'inclusive',
},
]);
return sortAssets([...filteredAssets], tokenSortConfig);
}
const accountAssetsPreSort = Object.entries(accountGroupIdAssets).flatMap(
([chainId, assets]) => {
if (!allEnabledNetworksForAllNamespaces.includes(chainId)) {
return [];
}
// Mapping necessary to comply with the type. Fields will be overriden with useTokenDisplayInfo
return assets.filter((asset) => {
if (isTronResource(asset)) {
return false;
}
if (shouldHideZeroBalanceTokens && asset.balance === '0') {
return false;
}
return true;
});
},
);
const accountAssets = sortAssetsWithPriority(
accountAssetsPreSort,
tokenSortConfig,
);
return accountAssets.map((asset) => {
const token: TokenWithFiatAmount = {
...asset,
tokenFiatAmount: asset.fiat?.balance,
secondary: null,
title: asset.name,
address: 'address' in asset ? asset.address : (asset.assetId as Hex),
chainId: asset.chainId as Hex,
};
return token;
});
}, [
isEvm,
evmBalances,
multichainAssets,
networksToShow,
currentNetwork.chainId,
tokenSortConfig,
isMultichainAccountsState2Enabled,
accountGroupIdAssets,
// newTokensImported included in deps, but not in hook's logic

Fix in Cursor Fix in Web


@metamaskbot
Copy link
Collaborator

Builds ready [be6e749]
UI Startup Metrics (1280 ± 123 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup12801037160512313161520
load1026850130810110711230
domContentLoaded101984513039910611222
domInteractive2715132222379
firstPaint55389126340310011227
backgroundConnect21018825011215234
firstReactRender3720191184060
getState62111612873120
initialActions106113
loadScripts8156431101998551014
setupStore1363351624
numNetworkReqs41271473430143
BrowserifyPower User HomeuiStartup23081930321928124652924
load1062935159713410791414
domContentLoaded1047928158613410561402
domInteractive37181903136128
firstPaint608133152840910041279
backgroundConnect276211796118247587
firstReactRender944715124115135
getState19613771159213247
initialActions104112
loadScripts82870213641318341194
setupStore221061102645
numNetworkReqs1406739972199287
WebpackStandard HomeuiStartup89374714811199331187
load658571104494690850
domContentLoaded653565103993687843
domInteractive2715127242291
firstPaint26887888195266662
backgroundConnect1153571231
firstReactRender39232062938108
getState55151352770108
initialActions104112
loadScripts650564102892685835
setupStore16799131845
numNetworkReqs41281503530146
WebpackPower User HomeuiStartup18151478249222519472222
load6865681265108686936
domContentLoaded6765601237108677931
domInteractive35171673132115
firstPaint292921272216318696
backgroundConnect86861416627568
firstReactRender924613921109123
getState17712364752186220
initialActions103112
loadScripts6735581228106675921
setupStore23862143648
numNetworkReqs1597140379216340
FirefoxBrowserifyStandard HomeuiStartup14201170198218315331766
load1084939159212011711330
domContentLoaded1083938159212011711330
domInteractive57312373381113
firstPaint------
backgroundConnect63213255065186
firstReactRender291859103255
getState2611172222444
initialActions2027323
loadScripts1057914157511611011297
setupStore2892023129111
numNetworkReqs39281272732123
BrowserifyPower User HomeuiStartup26912119473847528373879
load12071018250023212241656
domContentLoaded12071018249423112241656
domInteractive12934599114120441
firstPaint------
backgroundConnect146311432170148395
firstReactRender84372443094135
getState27062845189307739
initialActions3139527
loadScripts1164950237021711581611
setupStore1566833185186591
numNetworkReqs102623156378236
WebpackStandard HomeuiStartup17431405312822718452137
load13721135271818014351599
domContentLoaded13721135271818014351599
domInteractive89271457142101144
firstPaint------
backgroundConnect71252053886154
firstReactRender33236293654
getState2411110152546
initialActions218124
loadScripts13421111269717513961567
setupStore248115212170
numNetworkReqs40281272832123
WebpackPower User HomeuiStartup31722188573387133904883
load14651173297841115502697
domContentLoaded14651173297841115502697
domInteractive122311044143101436
firstPaint------
backgroundConnect179271901283139985
firstReactRender1084333166110279
getState259631095223247873
initialActions208123
loadScripts13871152278031014971873
setupStore15371099214158671
numNetworkReqs101612526079245
📊 Page Load Benchmark Results

Current Commit: be6e749 | Date: 11/25/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±63ms) 🟡 | historical mean value: 1.04s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 727ms (±61ms) 🟢 | historical mean value: 729ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 77ms (±13ms) 🟢 | historical mean value: 78ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 63ms 1.01s 1.33s 1.26s 1.33s
domContentLoaded 727ms 61ms 698ms 1.01s 929ms 1.01s
firstPaint 77ms 13ms 60ms 192ms 88ms 192ms
firstContentfulPaint 77ms 13ms 60ms 192ms 88ms 192ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 2.28 KiB (0.05%)
  • ui: 751.07 KiB (10.67%)
  • common: 40.95 KiB (0.47%)

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WONTFIX: Preexisting issue

Bug: Missing dependencies in useEffect dependency array

The useEffect hook uses isInputUnchanged and isMatchingUpstream variables inside the effect (line 146) but they are missing from the dependency array. The effect calculates isUpstreamValue using these variables, which affects the behavior of processNewDecimalValue. When these values change, the effect won't re-run, causing stale values to be used and potentially incorrect currency conversion calculations. The removal of the eslint-disable comment for react-hooks/exhaustive-deps exposed this existing issue that should be fixed.

ui/components/app/currency-input/currency-input.js#L166-L174

// tokenDecimalValue does not need to be in here, since this side effect is only for upstream updates
}, [
hexValue,
asset?.address,
processNewDecimalValue,
isTokenPrimary,
assetDecimals,
isDisabled,
]);

Fix in Cursor Fix in Web


@MajorLift
Copy link
Contributor Author

MajorLift commented Nov 25, 2025

Hey @davidmurdoch following up on the requested changes!

@metamaskbot
Copy link
Collaborator

Builds ready [dda7ecb]
UI Startup Metrics (1306 ± 132 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup13061036156813213941560
load1054861128611311421251
domContentLoaded1049852127611211351245
domInteractive2815128242494
firstPaint4857713213959431247
backgroundConnect21219526613218247
firstReactRender371990114062
getState60191322571121
initialActions1011114
loadScripts84365010791099331037
setupStore1374251623
numNetworkReqs41281473430142
BrowserifyPower User HomeuiStartup21121809317524022042580
load1044920174914410491391
domContentLoaded1030910173814510381374
domInteractive36181703232117
firstPaint48210714003479441057
backgroundConnect25820259696231535
firstReactRender924115625112135
getState19113473361204240
initialActions105112
loadScripts81870414271408171162
setupStore231191142852
numNetworkReqs103652905497266
WebpackStandard HomeuiStartup84271312591018791075
load620543102488668821
domContentLoaded615539101988663814
domInteractive251497202183
firstPaint277106856187327659
backgroundConnect1163471328
firstReactRender3421162163750
getState5015117236792
initialActions107112
loadScripts613537101187661804
setupStore1474481639
numNetworkReqs41271503430146
WebpackPower User HomeuiStartup18231298242825119752259
load68458799688699903
domContentLoaded67457999188691898
domInteractive37181783133127
firstPaint28486883187313691
backgroundConnect61862113322499
firstReactRender934514223111136
getState17213524120183215
initialActions105113
loadScripts67157798187689890
setupStore251069163956
numNetworkReqs1657039177226330
FirefoxBrowserifyStandard HomeuiStartup15211258235018116241857
load1156981144710212091374
domContentLoaded1155980144710212091374
domInteractive70331663395136
firstPaint------
backgroundConnect76243045487201
firstReactRender301978103450
getState2814155212954
initialActions203123
loadScripts112096213628811681327
setupStore289134242581
numNetworkReqs40281262733123
BrowserifyPower User HomeuiStartup26762060437944228174040
load1207946251725012211524
domContentLoaded1207946251625012201524
domInteractive11734485100113411
firstPaint------
backgroundConnect121291071121124282
firstReactRender87392252999141
getState274731168212313753
initialActions2032323
loadScripts1157923242121811631466
setupStore1647763190181685
numNetworkReqs100572935998266
WebpackStandard HomeuiStartup19321548338827720642407
load14951250300820515841759
domContentLoaded14941250300820515841759
domInteractive853026745119167
firstPaint------
backgroundConnect953430660115229
firstReactRender362497114155
getState2812135202986
initialActions207123
loadScripts14531226297819815371675
setupStore36122384226142
numNetworkReqs40281272832125
WebpackPower User HomeuiStartup30232331515566530994693
load14231125279429314161978
domContentLoaded14231125279329314161977
domInteractive11332577114101409
firstPaint------
backgroundConnect137271186180130266
firstReactRender974334955100272
getState321361352264446881
initialActions3140427
loadScripts13681095259422313861781
setupStore14961105202154616
numNetworkReqs101592546079239
📊 Page Load Benchmark Results

Current Commit: dda7ecb | Date: 11/25/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±39ms) 🟡 | historical mean value: 1.05s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 726ms (±37ms) 🟢 | historical mean value: 731ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 77ms (±11ms) 🟢 | historical mean value: 77ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 39ms 1.01s 1.31s 1.07s 1.31s
domContentLoaded 726ms 37ms 699ms 985ms 750ms 985ms
firstPaint 77ms 11ms 60ms 164ms 88ms 164ms
firstContentfulPaint 77ms 11ms 60ms 164ms 88ms 164ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 2.32 KiB (0.05%)
  • ui: 754.79 KiB (10.72%)
  • common: 41.83 KiB (0.48%)

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WONTFIX: Preexisting issue

Bug: Missing dependency causes stale token list rendering

The shouldHideZeroBalanceTokens variable is used inside the useMemo hook at line 119 to filter assets, but it's missing from the dependency array at lines 144-157. When users toggle the "hide zero balance tokens" setting, the token list won't update to reflect the new preference until another dependency changes, causing the UI to display stale data that doesn't match the user's current settings.

ui/components/app/assets/token-list/token-list.tsx#L92-L157

);
const sortedFilteredTokens = useMemo(() => {
if (!isMultichainAccountsState2Enabled) {
const balances = isEvm ? evmBalances : multichainAssets;
const filteredAssets = filterAssets(balances as TokenWithFiatAmount[], [
{
key: 'chainId',
opts: isEvm ? networksToShow : { [currentNetwork.chainId]: true },
filterCallback: 'inclusive',
},
]);
return sortAssets([...filteredAssets], tokenSortConfig);
}
const accountAssetsPreSort = Object.entries(accountGroupIdAssets).flatMap(
([chainId, assets]) => {
if (!allEnabledNetworksForAllNamespaces.includes(chainId)) {
return [];
}
// Mapping necessary to comply with the type. Fields will be overriden with useTokenDisplayInfo
return assets.filter((asset) => {
if (isTronResource(asset)) {
return false;
}
if (shouldHideZeroBalanceTokens && asset.balance === '0') {
return false;
}
return true;
});
},
);
const accountAssets = sortAssetsWithPriority(
accountAssetsPreSort,
tokenSortConfig,
);
return accountAssets.map((asset) => {
const token: TokenWithFiatAmount = {
...asset,
tokenFiatAmount: asset.fiat?.balance,
secondary: null,
title: asset.name,
address: 'address' in asset ? asset.address : (asset.assetId as Hex),
chainId: asset.chainId as Hex,
};
return token;
});
}, [
isEvm,
evmBalances,
multichainAssets,
networksToShow,
currentNetwork.chainId,
tokenSortConfig,
isMultichainAccountsState2Enabled,
accountGroupIdAssets,
// newTokensImported included in deps, but not in hook's logic
newTokensImported,
allEnabledNetworksForAllNamespaces,
]);

Fix in Cursor Fix in Web


@metamaskbot
Copy link
Collaborator

Builds ready [2455a12]
UI Startup Metrics (1309 ± 130 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup13091067165513013751593
load1052859131010210941261
domContentLoaded1045855130610110891254
domInteractive2715112212280
firstPaint61388126641510441181
backgroundConnect22019928115225250
firstReactRender3922118144369
getState62211302377106
initialActions109113
loadScripts8336511060998791039
setupStore1374351625
numNetworkReqs41221483431142
BrowserifyPower User HomeuiStartup21881733297726523502722
load1030891148914210341380
domContentLoaded1016884145514210181363
domInteractive35171622831102
firstPaint54911614963799531258
backgroundConnect258200723109226569
firstReactRender894014824107126
getState19913169577211256
initialActions103113
loadScripts80968212221428071158
setupStore22992142561
numNetworkReqs1256737069149286
WebpackStandard HomeuiStartup88774614391249031198
load649572101992677875
domContentLoaded645566101291673869
domInteractive28161402623101
firstPaint24094886167225622
backgroundConnect1155071127
firstReactRender3821137194075
getState53191232766107
initialActions104113
loadScripts642564100189671859
setupStore16551101744
numNetworkReqs41271483430144
WebpackPower User HomeuiStartup19051294252324520792347
load662561112897677895
domContentLoaded653555111998667888
domInteractive35171643230136
firstPaint32892920225567840
backgroundConnect71860515425562
firstReactRender974718726111142
getState19614773075196252
initialActions105112
loadScripts650553111096665881
setupStore24763153950
numNetworkReqs1717242679221386
FirefoxBrowserifyStandard HomeuiStartup15311233210216416631805
load1159980140610112411337
domContentLoaded1159979140610112411336
domInteractive69331903791147
firstPaint------
backgroundConnect782525851110201
firstReactRender322187123461
getState2911198282660
initialActions205123
loadScripts112296313599212031295
setupStore3010255313098
numNetworkReqs40281252637120
BrowserifyPower User HomeuiStartup27262175428339029283499
load12031021174117712121662
domContentLoaded12031020174117712101661
domInteractive13656606122113500
firstPaint------
backgroundConnect13846601109138479
firstReactRender85372702792128
getState33476943240547852
initialActions2031323
loadScripts11671001171117111591561
setupStore16820775175202638
numNetworkReqs102623176182246
WebpackStandard HomeuiStartup17251472216317618452104
load1341118315789614051533
domContentLoaded1340118215699614051533
domInteractive822929645102167
firstPaint------
backgroundConnect68212733669157
firstReactRender34227793749
getState32111763227130
initialActions204123
loadScripts1312116615439213751485
setupStore259215292171
numNetworkReqs41281322838125
WebpackPower User HomeuiStartup31652075569884033825147
load14681170342241915532763
domContentLoaded14681170342241915532762
domInteractive122301188153100466
firstPaint------
backgroundConnect1832815982791421023
firstReactRender95412924797227
getState324431037248485831
initialActions3174723
loadScripts13681140244223814311798
setupStore16161154236152736
numNetworkReqs102592926082238
📊 Page Load Benchmark Results

Current Commit: 2455a12 | Date: 11/25/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±66ms) 🟡 | historical mean value: 1.05s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 725ms (±64ms) 🟢 | historical mean value: 731ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 74ms (±11ms) 🟢 | historical mean value: 77ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 66ms 1.00s 1.30s 1.25s 1.30s
domContentLoaded 725ms 64ms 695ms 986ms 925ms 986ms
firstPaint 74ms 11ms 56ms 156ms 88ms 156ms
firstContentfulPaint 74ms 11ms 56ms 156ms 88ms 156ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 52 Bytes (0%)
  • ui: 750.63 KiB (10.66%)
  • common: 40.48 KiB (0.46%)

@MajorLift MajorLift moved this from Needs more work from the author to Review in progress in PR review queue Nov 25, 2025
@metamaskbot
Copy link
Collaborator

Builds ready [9e269b9]
UI Startup Metrics (1332 ± 142 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup13321078188714214001582
load1067867151711911101251
domContentLoaded1061862151111911021243
domInteractive2815151262392
firstPaint56585137342110301218
backgroundConnect21719225412224243
firstReactRender392371104463
getState63211362679113
initialActions106113
loadScripts85166612951158951030
setupStore1574771727
numNetworkReqs41271483430144
BrowserifyPower User HomeuiStartup22361872304323222992697
load1078908150013611001435
domContentLoaded1062894147113510931389
domInteractive35171662934126
firstPaint76093150841710311369
backgroundConnect28121561193265520
firstReactRender1004417730122148
getState20811636232222269
initialActions105112
loadScripts83068612371328341151
setupStore211048102343
numNetworkReqs102672935298272
WebpackStandard HomeuiStartup89275013371219071178
load65357292788688853
domContentLoaded64856792288684846
domInteractive2816135242294
firstPaint23482903168221647
backgroundConnect1257091231
firstReactRender3823127184182
getState52191252668102
initialActions105112
loadScripts64556591886682836
setupStore16653101742
numNetworkReqs41281473430142
WebpackPower User HomeuiStartup19341325267523721102355
load6935911214103698959
domContentLoaded6835851207104689952
domInteractive40172063639142
firstPaint31498998213383713
backgroundConnect78762616024557
firstReactRender944513923113132
getState196128706102187265
initialActions106112
loadScripts6805831198102687943
setupStore231059142655
numNetworkReqs1726839574222327
FirefoxBrowserifyStandard HomeuiStartup14341192218818915491823
load1088945141910611611305
domContentLoaded1087945141910711611305
domInteractive63312614086138
firstPaint------
backgroundConnect72333675792224
firstReactRender3019109123352
getState2611148212487
initialActions103122
loadScripts105493012919111141240
setupStore2510129212389
numNetworkReqs39281222633120
BrowserifyPower User HomeuiStartup25932094425936327013207
load1155977165813711501475
domContentLoaded1155971165713711501473
domInteractive12438511102122415
firstPaint------
backgroundConnect1052746871119240
firstReactRender82381382293127
getState22061921169221671
initialActions411031138
loadScripts1123959160013011151438
setupStore17412759193193653
numNetworkReqs101613156481244
WebpackStandard HomeuiStartup15941351203916816632003
load12601066163611513061519
domContentLoaded12601065163511513051519
domInteractive61252243686131
firstPaint------
backgroundConnect66232313978140
firstReactRender301977103243
getState249136192554
initialActions205122
loadScripts12311053157410512761465
setupStore2210133202054
numNetworkReqs41281262738122
WebpackPower User HomeuiStartup30302156548279731204726
load14451142292138114962732
domContentLoaded14451142292138114962732
domInteractive1082954311490458
firstPaint------
backgroundConnect1612413092451331032
firstReactRender913929838100166
getState26775967221277871
initialActions3161623
loadScripts13801115263628014671816
setupStore15861109221134661
numNetworkReqs100552555980247
📊 Page Load Benchmark Results

Current Commit: 9e269b9 | Date: 11/26/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.08s (±77ms) 🟡 | historical mean value: 1.05s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 760ms (±73ms) 🟢 | historical mean value: 731ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 82ms (±14ms) 🟢 | historical mean value: 77ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.08s 77ms 1.04s 1.38s 1.34s 1.38s
domContentLoaded 760ms 73ms 718ms 1.04s 1.01s 1.04s
firstPaint 82ms 14ms 64ms 208ms 92ms 208ms
firstContentfulPaint 82ms 14ms 64ms 208ms 92ms 208ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 52 Bytes (0%)
  • ui: 750.63 KiB (10.66%)
  • common: 40.48 KiB (0.46%)

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WONTFIX: Preexisting issue

Bug: Missing dependency in useMemo causes stale closure

The useMemo hook uses shouldHideZeroBalanceTokens inside its callback at line 119 to filter assets, but this variable is not included in the dependency array at lines 145-157. This creates a stale closure where changes to shouldHideZeroBalanceTokens won't trigger recalculation of sortedFilteredTokens, causing the UI to display incorrect token lists when users toggle the zero balance filter setting.

ui/components/app/assets/token-list/token-list.tsx#L144-L157

}, [
isEvm,
evmBalances,
multichainAssets,
networksToShow,
currentNetwork.chainId,
tokenSortConfig,
isMultichainAccountsState2Enabled,
accountGroupIdAssets,
// newTokensImported included in deps, but not in hook's logic
newTokensImported,
allEnabledNetworksForAllNamespaces,
]);

Fix in Cursor Fix in Web


@metamaskbot
Copy link
Collaborator

Builds ready [c47e3f6]
UI Startup Metrics (1328 ± 134 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup13281055167913413851615
load1064864134311111141285
domContentLoaded1057860133110911081269
domInteractive28151232422103
firstPaint54292134840710091171
backgroundConnect22120027015229251
firstReactRender3920131144262
getState63191482876127
initialActions108125
loadScripts84565911241058901056
setupStore1453871732
numNetworkReqs41281463430143
BrowserifyPower User HomeuiStartup20271703268922321412509
load1002855143814610481372
domContentLoaded988841143114710351364
domInteractive3216138243099
firstPaint66710414533989451374
backgroundConnect23018763988211501
firstReactRender5941118136389
getState19114027327207249
initialActions103112
loadScripts79764912281438351167
setupStore18105482137
numNetworkReqs105672935698269
WebpackStandard HomeuiStartup91274912821219511186
load66856795193735870
domContentLoaded66356294293730863
domInteractive2715106222291
firstPaint28284877218303816
backgroundConnect12684101230
firstReactRender47232033543141
getState52202173064106
initialActions104112
loadScripts66056094091727860
setupStore1445181535
numNetworkReqs41281493430143
WebpackPower User HomeuiStartup18581356264328019992376
load7065901251119707970
domContentLoaded6955831245119692961
domInteractive38171923435128
firstPaint3201041013225429866
backgroundConnect71863315624572
firstReactRender664794107386
getState17813222620189220
initialActions103112
loadScripts6935811234118689952
setupStore23778152558
numNetworkReqs1657139777215374
FirefoxBrowserifyStandard HomeuiStartup14521157202217515781757
load1102930145811011681321
domContentLoaded1102930145811011681321
domInteractive62312653987134
firstPaint------
backgroundConnect69233285081180
firstReactRender27195362936
getState2511140172460
initialActions114122
loadScripts106891313019711111284
setupStore268106212890
numNetworkReqs39281282633122
BrowserifyPower User HomeuiStartup26222038437844628013868
load11711012170115811791573
domContentLoaded11711011170115811791572
domInteractive12434563109111425
firstPaint------
backgroundConnect13226508102145394
firstReactRender5836155176489
getState29374921214381769
initialActions217123
loadScripts1130985166414911311524
setupStore166131038209200723
numNetworkReqs99612455781237
WebpackStandard HomeuiStartup16721397241719217622060
load13031107160510913591543
domContentLoaded13031107160410913581543
domInteractive69251733895153
firstPaint------
backgroundConnect72282594572182
firstReactRender312290103554
getState35102514427163
initialActions204122
loadScripts12771091154110213301512
setupStore278147252188
numNetworkReqs40281252638120
WebpackPower User HomeuiStartup29752033551277031054735
load14301165290538514552616
domContentLoaded14301165290438514552616
domInteractive11428559119101439
firstPaint------
backgroundConnect159271360234129798
firstReactRender69412633467150
getState254601062200298722
initialActions3139524
loadScripts13561140270329613401782
setupStore1296733167126624
numNetworkReqs101632975981243
📊 Page Load Benchmark Results

Current Commit: c47e3f6 | Date: 11/26/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±63ms) 🟡 | historical mean value: 1.04s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 732ms (±78ms) 🟢 | historical mean value: 720ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 80ms (±44ms) 🟢 | historical mean value: 78ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 63ms 1.01s 1.33s 1.24s 1.33s
domContentLoaded 732ms 78ms 700ms 1.29s 922ms 1.29s
firstPaint 80ms 44ms 60ms 516ms 88ms 516ms
firstContentfulPaint 80ms 44ms 60ms 516ms 88ms 516ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 52 Bytes (0%)
  • ui: 751.9 KiB (10.67%)
  • common: 40.48 KiB (0.46%)

@davidmurdoch davidmurdoch self-requested a review November 26, 2025 20:07
@davidmurdoch davidmurdoch merged commit f167e26 into main Nov 26, 2025
175 of 176 checks passed
@davidmurdoch davidmurdoch deleted the jongsun/build/251103-enable-react-compiler branch November 26, 2025 20:08
@github-actions github-actions bot locked and limited conversation to collaborators Nov 26, 2025
@metamaskbot metamaskbot added the release-13.12.0 Issue or pull request that will be included in release 13.12.0 label Nov 26, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-13.12.0 Issue or pull request that will be included in release 13.12.0 size-XL team-extension-platform Extension Platform team

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

7 participants