Skip to content

Commit 55eec1c

Browse files
authored
feat: use node to call codegen (#685)
### Summary We were using `npx` to call the React Native Community CLI for codegen. However, not every environment has `npx` available. This adds custom logic to invoke the RNCCLI only using the node binary. This also emits a better error message when the user doesn't have `@react-native-community/cli` installed on their library project. ### Test plan 1. Create a new architecture supported library 3. Call `yarn bob build --target codegen` 3. Make sure the command passes without any problems
1 parent 6069721 commit 55eec1c

File tree

2 files changed

+69
-7
lines changed

2 files changed

+69
-7
lines changed

packages/react-native-builder-bob/src/targets/codegen.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import kleur from 'kleur';
22
import type { Input } from '../types';
33
import { patchCodegen } from '../utils/patchCodegen';
4-
import { spawn } from '../utils/spawn';
54
import fs from 'fs-extra';
65
import path from 'path';
76
import del from 'del';
7+
import { runRNCCli } from '../utils/runRNCCli';
88

99
type Options = Input;
1010

@@ -33,11 +33,9 @@ export default async function build({ root, report }: Options) {
3333
}
3434

3535
try {
36-
await spawn('npx', ['@react-native-community/cli', 'codegen'], {
37-
stdio: 'ignore',
38-
});
36+
await runRNCCli(['codegen']);
3937

40-
patchCodegen(root, packageJson, report);
38+
await patchCodegen(root, packageJson, report);
4139

4240
report.success('Generated native code with codegen');
4341
} catch (e: unknown) {
@@ -47,14 +45,24 @@ export default async function build({ root, report }: Options) {
4745
`Errors found while generating codegen files:\n${e.stdout.toString()}`
4846
);
4947
} else if ('message' in e && typeof e.message === 'string') {
50-
report.error(e.message);
48+
if (
49+
e.message.includes(
50+
"Error: Cannot find module '@react-native-community/cli/package.json'"
51+
)
52+
) {
53+
report.error(
54+
"You don't have `@react-native-community/cli` in your root package's dev dependencies. Please install it and make sure it uses the same version as your application."
55+
);
56+
} else {
57+
report.error(e.message);
58+
}
5159
} else {
5260
throw e;
5361
}
5462
} else {
5563
throw e;
5664
}
5765

58-
throw new Error('Failed generate the codegen files.');
66+
process.exit(1);
5967
}
6068
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { type SpawnOptions } from 'node:child_process';
2+
import { spawn } from './spawn';
3+
import path from 'node:path';
4+
import fs from 'fs-extra';
5+
import assert from 'node:assert';
6+
7+
// This is a special case for calling bob from the XCode scripts
8+
// XCode scripts don't have the node binary properly set
9+
// We expose an env value for node instead.
10+
const NODE_BINARY = process.env['NODE_BINARY'] || 'node';
11+
12+
/**
13+
* Runs the React Native Community CLI with the specified arguments
14+
*/
15+
export async function runRNCCli(
16+
args: string[],
17+
options: SpawnOptions = {
18+
stdio: 'ignore',
19+
}
20+
) {
21+
const rncCliBinaryName = await getCliBinaryName();
22+
23+
const RNC_CLI_BINARY_PATH = path.resolve(
24+
process.cwd(), // We are always expected to run in the library
25+
'node_modules',
26+
'.bin',
27+
rncCliBinaryName
28+
);
29+
30+
return await spawn(NODE_BINARY, [RNC_CLI_BINARY_PATH, ...args], options);
31+
}
32+
33+
async function getCliBinaryName(): Promise<string> {
34+
const rncCliPackagePath = await spawn(NODE_BINARY, [
35+
'-e',
36+
`console.log(require.resolve('@react-native-community/cli/package.json'))`,
37+
]);
38+
39+
const rncCliPackage = await fs.readJson(rncCliPackagePath);
40+
const binProperty = rncCliPackage.bin as Record<string, string>;
41+
assert(
42+
typeof binProperty === 'object',
43+
"React Native CLI doesn't specify proper binaries"
44+
);
45+
46+
const binaries = Object.keys(binProperty);
47+
const rncCliBinaryName = binaries[0] as string;
48+
assert(
49+
typeof rncCliBinaryName === 'string',
50+
"React Native Community CLI doesn't have any binaries to run"
51+
);
52+
53+
return rncCliBinaryName;
54+
}

0 commit comments

Comments
 (0)