Skip to content

Commit

Permalink
feat: use node to call codegen (#685)
Browse files Browse the repository at this point in the history
### 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
  • Loading branch information
atlj authored Nov 15, 2024
1 parent 6069721 commit 55eec1c
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 7 deletions.
22 changes: 15 additions & 7 deletions packages/react-native-builder-bob/src/targets/codegen.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import kleur from 'kleur';
import type { Input } from '../types';
import { patchCodegen } from '../utils/patchCodegen';
import { spawn } from '../utils/spawn';
import fs from 'fs-extra';
import path from 'path';
import del from 'del';
import { runRNCCli } from '../utils/runRNCCli';

type Options = Input;

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

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

patchCodegen(root, packageJson, report);
await patchCodegen(root, packageJson, report);

report.success('Generated native code with codegen');
} catch (e: unknown) {
Expand All @@ -47,14 +45,24 @@ export default async function build({ root, report }: Options) {
`Errors found while generating codegen files:\n${e.stdout.toString()}`
);
} else if ('message' in e && typeof e.message === 'string') {
report.error(e.message);
if (
e.message.includes(
"Error: Cannot find module '@react-native-community/cli/package.json'"
)
) {
report.error(
"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."
);
} else {
report.error(e.message);
}
} else {
throw e;
}
} else {
throw e;
}

throw new Error('Failed generate the codegen files.');
process.exit(1);
}
}
54 changes: 54 additions & 0 deletions packages/react-native-builder-bob/src/utils/runRNCCli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { type SpawnOptions } from 'node:child_process';
import { spawn } from './spawn';
import path from 'node:path';
import fs from 'fs-extra';
import assert from 'node:assert';

// This is a special case for calling bob from the XCode scripts
// XCode scripts don't have the node binary properly set
// We expose an env value for node instead.
const NODE_BINARY = process.env['NODE_BINARY'] || 'node';

/**
* Runs the React Native Community CLI with the specified arguments
*/
export async function runRNCCli(
args: string[],
options: SpawnOptions = {
stdio: 'ignore',
}
) {
const rncCliBinaryName = await getCliBinaryName();

const RNC_CLI_BINARY_PATH = path.resolve(
process.cwd(), // We are always expected to run in the library
'node_modules',
'.bin',
rncCliBinaryName
);

return await spawn(NODE_BINARY, [RNC_CLI_BINARY_PATH, ...args], options);
}

async function getCliBinaryName(): Promise<string> {
const rncCliPackagePath = await spawn(NODE_BINARY, [
'-e',
`console.log(require.resolve('@react-native-community/cli/package.json'))`,
]);

const rncCliPackage = await fs.readJson(rncCliPackagePath);
const binProperty = rncCliPackage.bin as Record<string, string>;
assert(
typeof binProperty === 'object',
"React Native CLI doesn't specify proper binaries"
);

const binaries = Object.keys(binProperty);
const rncCliBinaryName = binaries[0] as string;
assert(
typeof rncCliBinaryName === 'string',
"React Native Community CLI doesn't have any binaries to run"
);

return rncCliBinaryName;
}

0 comments on commit 55eec1c

Please sign in to comment.