Skip to content

fix(0.83, hermes): resolve hermes from version files instead of merge-base#3011

Merged
Saadnajmi merged 12 commits into
microsoft:0.83-mergefrom
Saadnajmi:hermes-v1-enable
Jul 10, 2026
Merged

fix(0.83, hermes): resolve hermes from version files instead of merge-base#3011
Saadnajmi merged 12 commits into
microsoft:0.83-mergefrom
Saadnajmi:hermes-v1-enable

Conversation

@Saadnajmi

@Saadnajmi Saadnajmi commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes Hermes resolution for the macOS SPM prebuild on 0.83-merge, and takes the opportunity to delete a bunch of fork-specific resolution code now that upstream ships the version files we need.

The bug: resolve-hermes.mts was downloading the Hermes tarball from com/facebook/react/react-native-artifacts/<rn-version>. Upstream moved Hermes out of there in 0.83 (react#53985) — it now lives at com/facebook/hermes/hermes-ios/<hermes-version>, keyed off the Hermes version in sdks/hermes-engine/version.properties. So the old URL 404s on 0.83 and every Resolve Hermes run quietly fell back to a ~30 min build from source.

What's in here

Download from the right place. resolve-hermes.mts reads version.properties (HERMES_VERSION_NAME, or HERMES_V1_VERSION_NAME when RCT_HERMES_V1_ENABLED=1) and pulls com/facebook/hermes/hermes-ios/<version>, same as the CocoaPods podspec does. Recompose still splices the standalone macosx/hermesvm.framework into the universal xcframework.

Stay on V0 for 0.83. I reverted the from-source V1 bits from the earlier commits (static_h, CMAKE_BUILD_TYPE, the inspector-header guard, the HERMES_V1_ENABLED define). 0.83 ships V0 (0.14.0) by default; V1-as-default is a 0.84 thing (react#54989, not backported). We pick it up for free at the 0.84 merge.

Drop the fork's homegrown resolution. Now that Hermes is pinned in version.properties + .hermesversion — files that come along with the RN source at merge time — the old merge-base heuristic isn't needed:

  • resolve-commit just reads the pinned .hermesversion / .hermesv1version tag (both are real refs in facebook/hermes) instead of cloning Hermes and guessing a commit from the merge-base timestamp.
  • hermes.js goes back to being byte-for-byte identical to upstream 0.83-stable. That drops the RN-version→Hermes mapping, BUILD_FROM_HERMES_COMMIT, and a latent bug where it fed the RN version into the Hermes coordinate and 404'd.
  • hermes-utils.rb: deleted hermes_commit_at_merge_base, restored podspec_source_build_from_github_main to upstream.
  • microsoft-hermes.js: dropped hermesCommitAtMergeBase. Kept findMatchingHermesVersion / findVersionAtMergeBase — those are still doing real work for reactnative-dependencies, which upstream still keys by RN version.

Net it's about +120/−400 across 5 files.

Checked locally

  • download-hermes Debughermes-ios/0.14.0 (200) → recompose → hermesvm.xcframework with 8 slices including macos-arm64_x86_64
  • RCT_HERMES_V1_ENABLED=1hermes-ios/250829098.0.2 (200); V0/V1 × debug/release all resolve
  • resolve-commithermes-v0.14.0 (V0) / hermes-v250829098.0.2 (V1)
  • hermes.js matches upstream 0.83-stable; no merge-base helpers left anywhere; ruby -c + eslint pass

On the recompose: I checked when the macOS slice starts shipping in the universal xcframework natively (so we can eventually delete this step). It first shows up in V1 250829098.0.15 (facebook/hermes#1971); the V0 line (0.14.x) doesn't have it yet, so recompose is still needed for both versions we currently pin.

Needs CI to confirm

Can't run the CocoaPods/iOS paths locally, so relying on CI for:

  • Resolve Hermes reports recomposed=true (fast path taken, from-source jobs skipped)
  • Prebuild macOS Core / Build * link the recomposed Hermes
  • Build RNTester / * (ios / macos / visionos) — exercises the hermes.js and hermes-utils.rb reverts

Supersedes

#2952, #2957 (folded in here)

@Saadnajmi Saadnajmi requested a review from a team as a code owner July 7, 2026 10:04
Comment thread .github/workflows/microsoft-resolve-hermes.yml Outdated
Comment thread packages/react-native/Package.swift Outdated
Saadnajmi and others added 5 commits July 7, 2026 14:17
Package.swift and ios-prebuild/hermes.js already reference hermesvm.xcframework
(the HermesV1 product introduced in RN 0.83), but the Resolve Hermes job still
recomposed hermes.xcframework and resolved Hermes commits on the legacy `main`
branch. With the upstream build scripts now unconditionally producing hermesvm,
this left the SPM build path internally inconsistent.

- microsoft-hermes.js: resolve commits on Hermes `static_h` branch; add
  `hermesV1Tag()` helper that reads sdks/.hermesv1version
- resolve-hermes.mts: recompose hermesvm.xcframework / hermesvm.framework
- microsoft-resolve-hermes.yml: bump cache key (hermes-v1- -> hermesv1-engine-)
  so stale V0-shaped caches aren't reused as V1 artifacts

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HermesV1's static_h CMakeLists requires CMAKE_BUILD_TYPE to be set; the
upstream `build_host_hermesc` helper in build-apple-framework.sh doesn't
pass it, so the from-source fallback in Resolve Hermes failed at the
hermesc step with "Please set CMAKE_BUILD_TYPE". Invoke cmake directly
from the workflow with -DCMAKE_BUILD_TYPE=Release (the host compiler is
always built Release for perf, matching configure_apple_framework's
behavior in Debug builds of the apple frameworks).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HermesV1 (static_h) replaces the legacy API/hermes/inspector/ headers with
API/hermes/cdp/, so the unconditional cp commands in build_apple_framework
and prepare_dest_root_for_ci fail with 'No such file or directory' when
building from V1 sources. Guard each copy with compgen so the copy is
skipped cleanly when the source directory is empty.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Package.swift links against hermesvm.xcframework (HermesV1) but never
defines HERMES_V1_ENABLED, so headers like
ReactCommon/hermes/inspector-modern/chrome/Registration.h still try to
#include <hermes/inspector/RuntimeAdapter.h> — a legacy header V1 dropped.
Set HERMES_V1_ENABLED=1 in the shared cxxSettings (alongside USE_HERMES);
this matches what cocoapods/utils.rb does when RCT_HERMES_V1_ENABLED=1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Saadnajmi and others added 5 commits July 8, 2026 14:14
… 0.84

Upstream 0.83-stable defaults to Hermes V0 (sdks/.hermesversion =
hermes-v0.14.1); V1 is opt-in via RCT_HERMES_V1_ENABLED and only becomes
the default in 0.84 (react#54989, commit bbe02de, not
backported to 0.83). The `hermes` -> `hermesvm` product rename, however,
already landed in 0.83 (react#53094), so the fork's
resolve-hermes.mts genuinely needed to catch up to the new artifact name.

Reduce the PR to just that V0-compatible rename catch-up and revert the
V1-engine bits to match upstream 0.83:

- resolve-hermes.mts: keep hermes.* -> hermesvm.* (needed on 0.83).
- Package.swift: drop HERMES_V1_ENABLED define (inherited at 0.84 merge).
- microsoft-hermes.js: revert static_h -> main; drop unused hermesV1Tag().
- hermes-utils.rb: revert static_h/main gate back to main (V0).
- build-apple-framework.sh: revert inspector-header guard (V0 ships them).
- microsoft-resolve-hermes.yml: revert cache-key rename + cmake hermesc
  change (build_host_hermesc works for V0).

Net: 6 files -> 1; the five reverted files now match upstream/0.83-merge.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… coordinate

resolve-hermes.mts queried com/facebook/react/react-native-artifacts/<rn-version>
for the Hermes tarball, but upstream publishes prebuilt Hermes under
com/facebook/hermes/hermes-ios/<HERMES_VERSION> (keyed by the Hermes version,
not the react-native version). That coordinate has no Hermes classifier, so the
download always 404'd and every 0.83 Resolve Hermes run fell back to an
expensive from-source build.

Point the download at upstream's real coordinate and read the Hermes version
from sdks/hermes-engine/version.properties, mirroring the CocoaPods
release_tarball_url: HERMES_VERSION_NAME by default (RN 0.83 ships V0 0.14.0),
or HERMES_V1_VERSION_NAME when RCT_HERMES_V1_ENABLED=1. The existing recompose
step then merges the standalone macOS slice into the universal xcframework.

Verified locally end-to-end:
- download-hermes Debug -> hermes-ios/0.14.0 (200), recompose -> hermesvm.xcframework
  with 8 slices incl. macos-arm64_x86_64 (recomposed=true)
- RCT_HERMES_V1_ENABLED=1 -> hermes-ios/250829098.0.2 (200)
- V0/V1 x debug/release URLs all resolve 200 on repo1.maven.org

Result: 0.83 downloads upstream's prebuilt Hermes (on par with RN 0.83's default
V0 engine) and no longer builds Hermes from source, so the from-source V1
machinery is unnecessary on 0.83.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The macOS 'resolve Hermes' from-source fallback resolved a Hermes commit
from the merge base with facebook/react-native. Now that upstream pins the
Hermes version in sdks/.hermesversion (V0) and sdks/.hermesv1version (V1) —
files that travel with the RN source — resolve-commit reads the pinned tag
(a valid actions/checkout ref) instead. Retires the merge-base heuristic
from this path; the from-source fallback jobs are unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…n files

Revert scripts/ios-prebuild/hermes.js fully to upstream (facebook/0.83-stable),
removing the fork's [macOS] Hermes machinery: the RN-version mapping, the
build-from-hermes-commit source type, and buildFromHermesCommit. This also
removes a latent bug where the react-native version was fed into the Hermes
Maven coordinate (com/facebook/hermes/hermes-ios/<ver>), which 404s on 0.83.
In macOS CI this path is short-circuited anyway (HERMES_VERSION=prebuilt).

In sdks/hermes-engine/hermes-utils.rb, restore podspec_source_build_from_github_main
to upstream and delete the [macOS] hermes_commit_at_merge_base helper (plus its
now-unused open3/json/tmpdir requires). Hermes resolution on 0.83 stays covered:
the release tarball (hermes-ios/0.14.0) serves the prebuilt path, and
BUILD_FROM_GITHUB_TAG (sdks/.hermesversion / .hermesv1version) serves from-source.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…t-hermes

Deletes hermesCommitAtMergeBase() (and its now-unused abort helper and os/path
imports) now that Phases 1-2 removed its callers in resolve-hermes.mts and
hermes.js. The RN-version resolvers (findMatchingHermesVersion,
findVersionAtMergeBase, getLatestStableVersionFromNPM) are retained — they still
key the reactnative-dependencies artifact, which legitimately stays
react-native-version-keyed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Saadnajmi Saadnajmi changed the title fix(hermes): enable HermesV1 (hermesvm.xcframework) resolution fix(hermes): download prebuilt Hermes from the correct coordinate; retire fork-specific resolution (0.83) Jul 8, 2026
@Saadnajmi Saadnajmi changed the title fix(hermes): download prebuilt Hermes from the correct coordinate; retire fork-specific resolution (0.83) fix(0.83, hermes): resolve hermes from version files instead of merge-base Jul 8, 2026
Rewrite the function docstrings to describe what the code does (inputs,
outputs, behavior) instead of narrating the change or its relationship to
upstream. Drops the "mirrors the CocoaPods podspec", "the fork previously
queried ...", and "as of RN 0.83 upstream renamed ..." asides.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread .github/scripts/resolve-hermes.mts Outdated
Comment thread .github/scripts/resolve-hermes.mts Outdated
Comment thread .github/scripts/resolve-hermes.mts Outdated
Record that the universal hermesvm.xcframework gained a native macOS slice
in Hermes V1 250829098.0.15 (facebook/hermes#1971), while the V0 line
(0.14.x) does not yet include it — so recompose is still required for the
currently pinned versions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Saadnajmi Saadnajmi merged commit 711bf5f into microsoft:0.83-merge Jul 10, 2026
49 checks passed
@Saadnajmi Saadnajmi deleted the hermes-v1-enable branch July 10, 2026 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants