Skip to content

Commit 17d9aa6

Browse files
committed
support 0.85
1 parent 4bbf30b commit 17d9aa6

2 files changed

Lines changed: 156 additions & 13 deletions

File tree

src/bundle-runner.ts

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,75 @@ function getHermesOSBin() {
331331
if (os.platform() === 'linux') return 'linux64-bin';
332332
}
333333

334+
function getHermesExecutableName() {
335+
return os.platform() === 'win32' ? 'hermesc.exe' : 'hermesc';
336+
}
337+
338+
function dirnameOfPackage(
339+
packageJsonPath: string,
340+
projectRoot = process.cwd(),
341+
) {
342+
return path.dirname(
343+
require.resolve(packageJsonPath, {
344+
paths: [projectRoot],
345+
}),
346+
);
347+
}
348+
349+
export function resolveHermesCommand(projectRoot = process.cwd()): string {
350+
const osBin = getHermesOSBin();
351+
if (!osBin) {
352+
throw new Error(`Unsupported platform for Hermes: ${os.platform()}`);
353+
}
354+
355+
const executableName = getHermesExecutableName();
356+
const candidates: string[] = [];
357+
358+
try {
359+
const rnDir = dirnameOfPackage('react-native/package.json', projectRoot);
360+
candidates.push(path.join(rnDir, 'sdks', 'hermesc', osBin, executableName));
361+
} catch {
362+
// react-native is required for normal RN projects; keep looking so the
363+
// final error can include all candidates we were able to infer.
364+
}
365+
366+
try {
367+
const hermesCompilerDir = dirnameOfPackage(
368+
'hermes-compiler/package.json',
369+
projectRoot,
370+
);
371+
candidates.push(
372+
path.join(hermesCompilerDir, 'hermesc', osBin, executableName),
373+
);
374+
} catch {
375+
// RN 0.85+ uses hermes-compiler, older projects may still use other paths.
376+
}
377+
378+
try {
379+
const hermesEngineDir = dirnameOfPackage(
380+
'hermes-engine/package.json',
381+
projectRoot,
382+
);
383+
candidates.push(
384+
path.join(hermesEngineDir, osBin, executableName),
385+
path.join(hermesEngineDir, 'hermesc', osBin, executableName),
386+
);
387+
} catch {
388+
// RN 0.70-era projects commonly used hermes-engine; optional for newer RN.
389+
}
390+
391+
const hermesCommand = candidates.find((candidate) =>
392+
fs.existsSync(candidate),
393+
);
394+
if (hermesCommand) {
395+
return hermesCommand;
396+
}
397+
398+
throw new Error(
399+
`Cannot find hermesc. Tried:\n${candidates.map((candidate) => `- ${candidate}`).join('\n')}`,
400+
);
401+
}
402+
334403
async function checkGradleConfig(): Promise<GradleConfig> {
335404
let enableHermes = false;
336405
let crunchPngs: boolean | undefined;
@@ -365,18 +434,7 @@ async function compileHermesByteCode(
365434
shouldCleanSourcemap: boolean,
366435
) {
367436
console.log(t('hermesEnabledCompiling'));
368-
const rnDir = path.dirname(
369-
require.resolve('react-native', {
370-
paths: [process.cwd()],
371-
}),
372-
);
373-
let hermesPath = path.join(rnDir, `/sdks/hermesc/${getHermesOSBin()}`);
374-
375-
if (!fs.existsSync(hermesPath)) {
376-
hermesPath = `node_modules/hermes-engine/${getHermesOSBin()}`;
377-
}
378-
379-
const hermesCommand = `${hermesPath}/hermesc`;
437+
const hermesCommand = resolveHermesCommand();
380438

381439
const args = [
382440
'-emit-binary',

tests/bundle-runner.test.ts

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
22
import fs from 'fs';
33
import os from 'os';
44
import path from 'path';
5-
import { hasProjectDependency, resolveExpoCli } from '../src/bundle-runner';
5+
import {
6+
hasProjectDependency,
7+
resolveExpoCli,
8+
resolveHermesCommand,
9+
} from '../src/bundle-runner';
610

711
function mkTempDir(prefix: string): string {
812
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
@@ -18,6 +22,16 @@ function _writeFile(filePath: string, content = ''): void {
1822
fs.writeFileSync(filePath, content);
1923
}
2024

25+
function hermesOSBin(): string {
26+
if (os.platform() === 'win32') return 'win64-bin';
27+
if (os.platform() === 'darwin') return 'osx-bin';
28+
return 'linux64-bin';
29+
}
30+
31+
function hermesExecutableName(): string {
32+
return os.platform() === 'win32' ? 'hermesc.exe' : 'hermesc';
33+
}
34+
2135
describe('hasProjectDependency', () => {
2236
let tempRoot = '';
2337

@@ -118,3 +132,74 @@ describe('resolveExpoCli edge cases', () => {
118132
expect(resolved.usingExpo).toBe(false);
119133
});
120134
});
135+
136+
describe('resolveHermesCommand', () => {
137+
let tempRoot = '';
138+
139+
beforeEach(() => {
140+
tempRoot = mkTempDir('rn-update-hermes-');
141+
});
142+
143+
afterEach(() => {
144+
if (tempRoot && fs.existsSync(tempRoot)) {
145+
fs.rmSync(tempRoot, { recursive: true, force: true });
146+
}
147+
});
148+
149+
test('resolves hermes-compiler path used by React Native 0.85', () => {
150+
const hermesCommand = path.join(
151+
tempRoot,
152+
'node_modules',
153+
'hermes-compiler',
154+
'hermesc',
155+
hermesOSBin(),
156+
hermesExecutableName(),
157+
);
158+
writeJson(
159+
path.join(tempRoot, 'node_modules/hermes-compiler/package.json'),
160+
{
161+
name: 'hermes-compiler',
162+
version: '250829098.0.10',
163+
},
164+
);
165+
_writeFile(hermesCommand);
166+
167+
expect(resolveHermesCommand(tempRoot)).toBe(hermesCommand);
168+
});
169+
170+
test('keeps compatibility with legacy react-native sdks hermesc path', () => {
171+
const hermesCommand = path.join(
172+
tempRoot,
173+
'node_modules',
174+
'react-native',
175+
'sdks',
176+
'hermesc',
177+
hermesOSBin(),
178+
hermesExecutableName(),
179+
);
180+
writeJson(path.join(tempRoot, 'node_modules/react-native/package.json'), {
181+
name: 'react-native',
182+
version: '0.69.0',
183+
});
184+
_writeFile(hermesCommand);
185+
186+
expect(resolveHermesCommand(tempRoot)).toBe(hermesCommand);
187+
});
188+
189+
test('keeps compatibility with legacy hermes-engine package path', () => {
190+
const hermesCommand = path.join(
191+
tempRoot,
192+
'node_modules',
193+
'hermes-engine',
194+
hermesOSBin(),
195+
hermesExecutableName(),
196+
);
197+
writeJson(path.join(tempRoot, 'node_modules/hermes-engine/package.json'), {
198+
name: 'hermes-engine',
199+
version: '0.11.0',
200+
});
201+
_writeFile(hermesCommand);
202+
203+
expect(resolveHermesCommand(tempRoot)).toBe(hermesCommand);
204+
});
205+
});

0 commit comments

Comments
 (0)