From 77351aa831363a033b0a0d6a5f7f87f18fa20295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Gu=CC=88ner?= Date: Fri, 15 Nov 2024 17:42:39 +0300 Subject: [PATCH] feat: use node to call rnccli codegen ### SummaryWe 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.### Test plan1. Create a new architecture supported library2. Call `yarn bob build --target codegen`3. Make sure the command passes without any problems4. Call `yarn prepare` --- .../src/targets/codegen.ts | 8 ++- .../src/utils/runRNCCli.ts | 54 +++++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 packages/react-native-builder-bob/src/utils/runRNCCli.ts diff --git a/packages/react-native-builder-bob/src/targets/codegen.ts b/packages/react-native-builder-bob/src/targets/codegen.ts index ecb1c04b2..e55ce2169 100644 --- a/packages/react-native-builder-bob/src/targets/codegen.ts +++ b/packages/react-native-builder-bob/src/targets/codegen.ts @@ -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; @@ -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) { diff --git a/packages/react-native-builder-bob/src/utils/runRNCCli.ts b/packages/react-native-builder-bob/src/utils/runRNCCli.ts new file mode 100644 index 000000000..744bf1cc8 --- /dev/null +++ b/packages/react-native-builder-bob/src/utils/runRNCCli.ts @@ -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 { + 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; + 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; +}