Skip to content

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

Open
Saadnajmi wants to merge 10 commits into
microsoft:0.83-mergefrom
Saadnajmi:hermes-v1-enable
Open

fix(0.83, hermes): resolve hermes from version files instead of merge-base#3011
Saadnajmi wants to merge 10 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, in doing so, retires the fork-specific Hermes resolution machinery in favor of the version files upstream now ships.

Root cause: resolve-hermes.mts queried com/facebook/react/react-native-artifacts/<rn-version> for the Hermes tarball. Upstream relocated the Hermes artifact at 0.83 to com/facebook/hermes/hermes-ios/<hermes-version> — keyed by the Hermes version in sdks/hermes-engine/version.properties, decoupled from the RN version in react#53985. The old coordinate 404s at 0.83, so every "Resolve Hermes" run silently fell back to a ~30 min from-source build.

What changed

1. Download prebuilt Hermes from upstream's real coordinate

  • resolve-hermes.mts reads version.properties (HERMES_VERSION_NAME by default → V0 0.14.0; HERMES_V1_VERSION_NAME when RCT_HERMES_V1_ENABLED=1) and downloads com/facebook/hermes/hermes-ios/<version>, mirroring the CocoaPods release_tarball_url in hermes-utils.rb. The existing recompose step merges the standalone macosx/hermesvm.framework into the universal hermesvm.xcframework.

2. Keep 0.83 on V0 (defer V1 to 0.84)

  • The earlier from-source V1 machinery (static_h resolution, CMAKE_BUILD_TYPE, inspector-header guard, HERMES_V1_ENABLED define) is reverted to 0.83-merge. RN 0.83's default engine is V0 (0.14.0); V1-as-default is an upstream 0.84 change ([RN][HermesV1] Use Hermes V1 as default engine react/react-native#54989, not backported). V1 is inherited naturally at the 0.84 merge.

3. Retire fork-specific Hermes resolution (reduce divergence from upstream)

  • resolve-hermes.mts resolve-commit now emits the pinned .hermesversion / .hermesv1version tag (a valid facebook/hermes checkout ref) instead of the merge-base heuristic.
  • hermes.js reverted to be byte-identical to facebook/react-native 0.83-stable — removes the RN-version→Hermes mapping, BUILD_FROM_HERMES_COMMIT, and a latent RN-version-into-hermes-coordinate 404.
  • hermes-utils.rb: hermes_commit_at_merge_base deleted; podspec_source_build_from_github_main restored to upstream.
  • microsoft-hermes.js: hermesCommitAtMergeBase removed. findMatchingHermesVersion / findVersionAtMergeBase are kept — still required for the reactnative-dependencies artifact, which upstream still keys by the RN version.

Why

Upstream pins the Hermes version in version.properties + .hermesversion (react#53985) — files that travel with the RN source at merge time. The fork's merge-base / RN-version resolution predated that and is now obsolete for Hermes, so deferring to the pinned files is both simpler and more correct, and removes standing fork↔upstream divergence (e.g. hermes.js is now diff-free).

Verification (local)

  • download-hermes Debughermes-ios/0.14.0 (200) → recompose → hermesvm.xcframework with 8 slices incl. macos-arm64_x86_64
  • RCT_HERMES_V1_ENABLED=1hermes-ios/250829098.0.2 (200); V0/V1 × debug/release all 200
  • resolve-commithermes-v0.14.0 (V0) / hermes-v250829098.0.2 (V1) — both valid facebook/hermes tags
  • hermes.js == upstream 0.83-stable; merge-base helpers gone repo-wide; ruby -c + eslint clean

Test plan (CI — validates the CocoaPods/iOS paths not exercisable locally)

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

Supersedes

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