Add a prebuilt-hermes command and a workflow that publishes its archive - #440
Merged
Merged
Conversation
Building Hermes for Apple platforms is the expensive part of an iOS build, and it only changes when the pinned commit does. Build it once into an archive in the destroot layout hermes-engine.podspec expects from HERMES_ENGINE_TARBALL_PATH, and publish it as a release asset keyed by the pinned commit. Nothing consumes the archive yet — pod install still builds Hermes from source. This lands the command and the publishing workflow first, so the workflow is dispatchable and an asset exists before anything depends on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UkNbgdyuKgHaFwT27RahGH
kraenhansen
force-pushed
the
claude/hermes-source-build-cache-zk13mc
branch
from
August 13, 2026 14:09
af62873 to
f64468e
Compare
5 tasks
The workflow's pull_request trigger doesn't fire on `labeled`, so the label-gated jobs need a synchronize event to be evaluated against. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UkNbgdyuKgHaFwT27RahGH
This was referenced Aug 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Building Hermes for Apple platforms is the expensive part of an iOS build — 17m15s of an 18m58s
Build test appstep, measured in #439 — and it only changes when the pinned commit does.This lands the machinery for building it once, but nothing consumes it yet:
pod installstill builds Hermes from source, exactly as before. Splitting it out means theHermes prebuiltworkflow reaches the default branch and becomes dispatchable, so an asset exists before anything depends on it. #TBD flips the Cocoapods integration over.prebuilt-hermesA new command that resolves an archive of the pinned Hermes, prebuilt for Apple platforms, and prints its path. The archive holds the
destrootlayouthermes-engine.podspecexpects from a tarball pointed at byHERMES_ENGINE_TARBALL_PATH, which makeshermes_source_type()returnLOCAL_PREBUILT_TARBALLand skips the[RN] [1] Build Hermesc/[RN] [2] Build Hermesscript phases entirely.Resolution order: local cache → release asset published for the pinned commit → local build.
--no-download/--no-buildnarrow it,--print name|tag|urlreports without resolving.The per-platform framework builds are delegated to the Hermes checkout's own
utils/build-apple-framework.sh— the script that knows how to build that source tree — rather than reimplemented. Everything around it is TypeScript: the host compiler, the universal XCFramework and the archive.Details worth a look
The archive is keyed on the React Native version, not just the Hermes commit. React Native passes its own
ReactCommon/jsiasJSI_DIR; the framework and the app linking it sharejsi::Runtime, so a mismatch is an ABI break rather than a compile error. The name ishermes-<sha12>-rn<version>-<buildType>-<platforms>.tar.gz, which also makes it a correct CI cache key. It stays within[A-Za-z0-9._-]because GitHub rewrites anything else in a release asset name.destrootis archived alongsideLICENSEdeliberately. cocoapods-downloader flattens an archive whose sole top-level entry is a directory, which would strip thedestroot/prefix that every path inhermes-engine.podspecassumes.hermescis built universal and shipped indestroot/bin.react-native-xcode.shfalls back to$HERMES_ENGINE_PATH/destroot/bin/hermescwhenHERMES_CLI_PATHis unset, and the podspec deliberately does not point that at thehermes-compilernpm package for local tarballs — the compiler has to emit bytecode this VM can read. It's configured here rather than bybuild_host_hermesc, which takes no architectures, so the published archive also works on Intel Macs.macOS is left out of the universal XCFramework.
hermes-engine.podspecvendors macOS as a plain framework and every other platform out of the XCFramework, somacosxstays where it is instead of being merged and deleted.One build type, not per-configuration.
HERMES_ENGINE_TARBALL_PATHis resolved once atpod install, so it can't switch between Debug and Release the way React Native'sreplace_hermes_version.jsdoes for its own prebuilts. The default isdebug(Hermes' debugger enabled, CMakeRelease), the functional superset;--build-type releaseis there for the smaller one.The publishing workflow
.github/workflows/hermes-prebuilt.ymlbuilds the archive onmacos-latestand uploads it to a release taggedhermes-prebuilt-<sha12>, creating the release if missing.--latest=falsekeeps these out of the "latest release" slot, which belongs to the package releases changesets publishes. It triggers onworkflow_dispatchand on pushes tomain/nextthat touch the pin or the command, and caches by archive name so a re-run doesn't rebuild.Test plan
Checkpasses — theApple 🍎job still exercisesvendor-hermes, which was refactored here, so it is the regression check for thatHermes prebuiltand confirm it publishes an asset, then thatprebuilt-hermesdownloads it on a clean cacheNot verified from this worker: the archive has never been built or consumed, since that needs macOS and Xcode. What was verified is the CLI paths (naming,
--print, the 404-then-fallback flow), the type-check, lint, prettier, depcheck and publint.