Skip to content

chore: do not build Hermes from source (-25% build time) (#25035)#25046

Merged
sethkfman merged 6 commits intomainfrom
chore/do-no-build-hermes-from-source-margelo
Jan 30, 2026
Merged

chore: do not build Hermes from source (-25% build time) (#25035)#25046
sethkfman merged 6 commits intomainfrom
chore/do-no-build-hermes-from-source-margelo

Conversation

@sethkfman
Copy link
Copy Markdown
Contributor

@sethkfman sethkfman commented Jan 22, 2026

Description

We are patching only React Native Android source code so we don't need to build also Hermes engine which is adding lot of build time. On my machine it reduced build time by about 25% and I guess it could be even more on CI.

Changelog

CHANGELOG entry: null

Related issues

Fixes:

Manual testing steps

Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]

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

Medium Risk
Build configuration now pulls com.facebook.react:hermes-android:0.76.9 from Maven and removes the local hermes-engine project, which could break Android builds if dependency substitution/version alignment is off. Runtime app behavior shouldn’t change, but CI/build tooling is impacted.

Overview
Switches Android builds to use prebuilt Hermes from Maven Central instead of compiling Hermes from the React Native source tree, via a new Yarn patch (.yarn/patches/react-native-patch-d76d50a92f.patch) that removes the hermes-engine Gradle project wiring and replaces it with compileOnly("com.facebook.react:hermes-android:0.76.9").

Updates android/settings.gradle dependency substitution to no longer substitute hermes-android/hermes-engine to local projects, adjusts the react-native patched dependency entry in package.json/yarn.lock, and removes the Android build script step that installed ICU libraries for Hermes compilation.

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

Description

Changelog

CHANGELOG entry:

Related issues

Fixes:

Manual testing steps

Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]

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.

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

## **Description**

We are patching only React Native Android source code so we don't need
to build also Hermes engine which is adding lot of build time. On my
machine it reduced build time by about 25% and I guess it could be even
more on CI.

## **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)

AI agent: Use format `CHANGELOG entry: [fix/feat/chore]: [User-facing
description in past tense]`.
Examples: `fix: resolved token name display issue`, `feat: added dark
mode toggle`, `chore: updated dependencies`.
For non-user-facing changes, use `CHANGELOG entry: null`.
-->

CHANGELOG entry:

## **Related issues**

<!--
AI agent: Replace with `Fixes: #[ISSUE_NUMBER]` using the actual issue
number you're implementing.
-->

Fixes:

## **Manual testing steps**

<!--
AI agent: Write specific, contextual Gherkin steps based on what you
actually implemented.
Do NOT use generic placeholders like "my feature name". Be concrete
about the feature, scenario, and steps.
-->

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **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**

<!--
AI agent: Check ALL boxes in this section (mark all as [x]).
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

<!--
AI agent: Leave ALL boxes unchecked ([ ]) - these are for reviewers to
check, not the author.
-->

- [ ] 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]
> Uses prebuilt Hermes to avoid compiling the engine from source,
reducing Android build time and setup complexity.
> 
> - Patch React Native (`ReactAndroid/build.gradle.kts`) to depend on
`compileOnly("com.facebook.react:hermes-android:0.76.9")` and drop the
`hermes-engine` preBuild dependency
> - Remove `hermes-engine` includes/substitutions from RN
`settings.gradle.kts` and app `android/settings.gradle` (resolve Hermes
from Maven instead)
> - Update Yarn config: apply a new RN patch
(`.yarn/patches/react-native-patch-d76d50a92f.patch`) via `package.json`
and `yarn.lock`
> - Clean build script: delete ICU install step and its invocation in
`prebuild_android()`
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
096aebf. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@github-actions
Copy link
Copy Markdown
Contributor

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.

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.02%. Comparing base (0f5817f) to head (997f274).
⚠️ Report is 125 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #25046      +/-   ##
==========================================
+ Coverage   79.96%   80.02%   +0.06%     
==========================================
  Files        4257     4268      +11     
  Lines      109331   109875     +544     
  Branches    22889    23011     +122     
==========================================
+ Hits        87429    87932     +503     
- Misses      15835    15841       +6     
- Partials     6067     6102      +35     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

sethkfman pushed a commit that referenced this pull request Jan 29, 2026
<!--
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.
-->

## **Description**

Previously there was production grade JS bundled (which is very slow)
during Android debug builds but it's useless because JS is loaded from
Metro for debug builds. **This affect only local debug builds.**

**Cold cache debug build: 6m 57s -> 1m 15s 🚀 
Hot cache debug build:  4m 29s -> 12s 🚀** 

_* Measured on my machine (with already included #25046 improvement)_ 
## **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)

AI agent: Use format `CHANGELOG entry: [fix/feat/chore]: [User-facing
description in past tense]`.
Examples: `fix: resolved token name display issue`, `feat: added dark
mode toggle`, `chore: updated dependencies`.
For non-user-facing changes, use `CHANGELOG entry: null`.
-->

CHANGELOG entry:

## **Related issues**

<!--
AI agent: Replace with `Fixes: #[ISSUE_NUMBER]` using the actual issue
number you're implementing.
-->

Fixes:

## **Manual testing steps**

<!--
AI agent: Write specific, contextual Gherkin steps based on what you
actually implemented.
Do NOT use generic placeholders like "my feature name". Be concrete
about the feature, scenario, and steps.
-->

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **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**

<!--
AI agent: Check ALL boxes in this section (mark all as [x]).
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

<!--
AI agent: Leave ALL boxes unchecked ([ ]) - these are for reviewers to
check, not the author.
-->

- [ ] 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]
> Optimizes Android debug build performance by avoiding JS/asset
bundling for specific debug flavors.
> 
> - Sets `react.debuggableVariants = ["qaDebug", "prodDebug",
"flaskDebug"]` in `android/app/build.gradle` to skip bundle generation
for these debuggable variants during builds
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
94ad613. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
github-merge-queue bot pushed a commit that referenced this pull request Jan 29, 2026
<!--
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.
-->

## **Description**

Credit: @Nodonisko 

Previously there was production grade JS bundled (which is very slow)
during Android debug builds but it's useless because JS is loaded from
Metro for debug builds. **This affect only local debug builds.**

**Cold cache debug build: 6m 57s -> 1m 15s 🚀 
Hot cache debug build:  4m 29s -> 12s 🚀** 

_* Measured on my machine (with already included #25046 improvement)_ ##
**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)

AI agent: Use format `CHANGELOG entry: [fix/feat/chore]: [User-facing
description in past tense]`.
Examples: `fix: resolved token name display issue`, `feat: added dark
mode toggle`, `chore: updated dependencies`.
For non-user-facing changes, use `CHANGELOG entry: null`. -->

CHANGELOG entry: null

## **Related issues**

<!--
AI agent: Replace with `Fixes: #[ISSUE_NUMBER]` using the actual issue
number you're implementing.
-->

Fixes:

## **Manual testing steps**

<!--
AI agent: Write specific, contextual Gherkin steps based on what you
actually implemented.
Do NOT use generic placeholders like "my feature name". Be concrete
about the feature, scenario, and steps.
-->

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **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**

<!--
AI agent: Check ALL boxes in this section (mark all as [x]). -->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding

Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

<!--
AI agent: Leave ALL boxes unchecked ([ ]) - these are for reviewers to
check, not the author.
-->

- [ ] 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]
> **Low Risk**
> Low risk build-time change limited to local Android debug variants;
main risk is misclassifying a variant as debuggable and skipping
bundling where it’s needed.
> 
> **Overview**
> Configures React Native Gradle to treat `qaDebug`, `prodDebug`, and
`flaskDebug` as *debuggable variants*, so Gradle skips JS bundle/assets
bundling for these builds (reducing local debug build time).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
35d5ca6. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->



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

## **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?
-->

## **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:

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **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 Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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.

Co-authored-by: Daniel Suchý <suchydan@gmail.com>
@sethkfman sethkfman marked this pull request as ready for review January 29, 2026 20:58
@sethkfman sethkfman requested a review from a team as a code owner January 29, 2026 20:58
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeAccounts, SmokeConfirmationsRedesigned, SmokeIdentity, SmokeNetworkAbstractions, SmokeNetworkExpansion, SmokeTrade, SmokeWalletPlatform, SmokeCard, SmokeRewards, SmokePerps, SmokeRamps, SmokeMultiChainAPI, SmokePredictions, FlaskBuildTests
  • Selected Performance tags: @PerformanceLaunch, @PerformanceLogin, @PerformanceAssetLoading
  • Risk Level: high
  • AI Confidence: 85%
click to see 🤖 AI reasoning details

E2E Test Selection:
This PR makes fundamental changes to the Android build infrastructure by switching from building Hermes (the JavaScript engine) from source to using a prebuilt version from Maven Central. The changes include:

  1. React Native patching (package.json, yarn.lock): Adds a new patch that modifies how React Native's build.gradle.kts handles Hermes dependencies
  2. New patch file: Changes React Native to use com.facebook.react:hermes-android:0.76.9 from Maven instead of building hermes-engine from source
  3. android/settings.gradle: Removes hermes-android/hermes-engine substitutions so they resolve from Maven
  4. scripts/build.sh: Removes ICU library installation since it's no longer needed when not building Hermes from source

This is a high-risk change because:

  • Hermes is the JavaScript engine that executes all React Native code
  • Any issues with the prebuilt Hermes could affect JavaScript execution, app startup, or any app functionality
  • The change affects the core build infrastructure for Android

Since this modifies the fundamental JavaScript execution layer, all E2E tests should run to validate that the app functions correctly with the prebuilt Hermes engine. A comprehensive test run will help catch any potential regressions in JavaScript execution, performance, or compatibility.

Performance Test Selection:
Since this PR changes the Hermes JavaScript engine from source-built to prebuilt Maven artifact, there could be performance implications. The prebuilt Hermes should theoretically have the same performance characteristics, but it's worth validating: 1) @PerformanceLaunch - App cold/warm start times could be affected by the JS engine initialization, 2) @PerformanceLogin - Session restoration and time to wallet ready state involves JS execution, 3) @PerformanceAssetLoading - Token list rendering and balance fetching involve significant JS processing. These tests will help ensure the prebuilt Hermes performs equivalently to the source-built version.

View GitHub Actions results

Copy link
Copy Markdown
Contributor

@Cal-L Cal-L left a comment

Choose a reason for hiding this comment

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

LGTM

@sonarqubecloud
Copy link
Copy Markdown

@sethkfman sethkfman added this pull request to the merge queue Jan 29, 2026
Merged via the queue into main with commit be610d8 Jan 30, 2026
99 checks passed
@sethkfman sethkfman deleted the chore/do-no-build-hermes-from-source-margelo branch January 30, 2026 00:15
@github-actions github-actions bot locked and limited conversation to collaborators Jan 30, 2026
@metamaskbot metamaskbot added the release-7.65.0 Issue or pull request that will be included in release 7.65.0 label Jan 30, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-7.65.0 Issue or pull request that will be included in release 7.65.0 size-S team-mobile-platform Mobile Platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants