Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/test-app/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ msbuild.binlog

# Ignoring the Podfile.lock as the `react-native-node-api-modules` hash updates too frequently
Podfile.lock

hermes/
3 changes: 2 additions & 1 deletion packages/react-native-node-api-modules/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"!android/build",
"ios",
"include",
"babel-plugin.js",
"scripts/patch-hermes.rb",
"weak-node-api/**",
"!weak-node-api/build/",
Expand Down Expand Up @@ -89,7 +90,7 @@
},
"peerDependencies": {
"@babel/core": "^7.26.10",
"react-native": "0.79.1"
"react-native": "0.79.1 || 0.79.2"
},
"codegenConfig": {
"name": "NodeApiHostSpec",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::UI.warn "!!! PATCHING HERMES WITH NODE-API SUPPORT !!!"

VENDORED_HERMES_DIR ||= `npx react-native-node-api-modules vendor-hermes --silent`.strip
VENDORED_HERMES_DIR ||= `npx react-native-node-api-modules vendor-hermes --silent '#{Pod::Config.instance.installation_root}'`.strip
if Dir.exist?(VENDORED_HERMES_DIR)
Pod::UI.info "Hermes vendored into #{VENDORED_HERMES_DIR.inspect}"
else
Expand Down
66 changes: 47 additions & 19 deletions packages/react-native-node-api-modules/src/node/cli/hermes.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,45 @@
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";

import { Command } from "@commander-js/extra-typings";
import { spawn, SpawnFailure } from "bufout";
import { oraPromise } from "ora";
import { prettyPath } from "../path-utils";
import { packageDirectorySync } from "pkg-dir";

const HERMES_PATH = path.resolve(__dirname, "../../../hermes");
import { getLatestMtime, prettyPath } from "../path-utils";

const HOST_PACKAGE_ROOT = path.resolve(__dirname, "../../..");
// FIXME: make this configurable with reasonable fallback before public release
const HERMES_GIT_URL = "https://github.com/kraenhansen/hermes.git";
const HERMES_GIT_TAG = "node-api-for-react-native-0.79.0";
const REACT_NATIVE_DIR = path.dirname(
require.resolve("react-native/package.json")
);

export const command = new Command("vendor-hermes")
.argument("[from]", "Path to a file inside the app package", process.cwd())
.option("--silent", "Don't print anything except the final path", false)
.option(
"--force",
"Don't check timestamps of input files to skip unnecessary rebuilds",
false
)
.action(async ({ force, silent }) => {
.action(async (from, { force, silent }) => {
try {
if (force) {
fs.rmSync(HERMES_PATH, { recursive: true, force: true });
const appPackageRoot = packageDirectorySync({ cwd: from });
assert(appPackageRoot, "Failed to find package root");
const hermesPath = path.join(HOST_PACKAGE_ROOT, "hermes");
if (force && fs.existsSync(hermesPath)) {
await oraPromise(
fs.promises.rm(hermesPath, { recursive: true, force: true }),
{
text: "Removing existing Hermes clone",
successText: "Removed existing Hermes clone",
failText: (error) =>
`Failed to remove existing Hermes clone: ${error.message}`,
isEnabled: !silent,
}
);
}
if (!fs.existsSync(HERMES_PATH)) {
if (!fs.existsSync(hermesPath)) {
await oraPromise(
spawn(
"git",
Expand All @@ -37,27 +51,41 @@ export const command = new Command("vendor-hermes")
"--branch",
HERMES_GIT_TAG,
HERMES_GIT_URL,
HERMES_PATH,
hermesPath,
],
{
outputMode: "buffered",
}
),
{
text: `Cloning custom Hermes into ${prettyPath(HERMES_PATH)}`,
text: `Cloning custom Hermes into ${prettyPath(hermesPath)}`,
successText: "Cloned custom Hermes",
failText: (err) => `Failed to clone custom Hermes: ${err.message}`,
isEnabled: !silent,
}
);
}
const hermesJsiPath = path.join(hermesPath, "API/jsi/jsi");
const reactNativePath = path.dirname(
require.resolve("react-native/package.json", {
// Ensures we'll be patching the React Native package actually used by the app
paths: [appPackageRoot],
})
);
const reactNativeJsiPath = path.join(
reactNativePath,
"ReactCommon/jsi/jsi/"
);

if (
fs.existsSync(reactNativeJsiPath) &&
(force ||
getLatestMtime(hermesJsiPath) > getLatestMtime(reactNativeJsiPath))
) {
await oraPromise(
fs.promises.cp(
path.join(HERMES_PATH, "API/jsi/jsi"),
path.join(REACT_NATIVE_DIR, "ReactCommon/jsi/jsi/"),
{
recursive: true,
}
),
fs.promises.cp(hermesJsiPath, reactNativeJsiPath, {
recursive: true,
}),
{
text: `Copying JSI from Hermes to React Native`,
successText: "Copied JSI from Hermes to React Native",
Expand All @@ -67,7 +95,7 @@ export const command = new Command("vendor-hermes")
}
);
}
console.log(HERMES_PATH);
console.log(hermesPath);
} catch (error) {
if (error instanceof SpawnFailure) {
error.flushOutput("both");
Expand Down