Skip to content

Commit

Permalink
feat(bob): support custom target definitions (#732)
Browse files Browse the repository at this point in the history
### Summary

This adds the `custom` target to bob. Users are able to pass arbitrary
scripts via this target and bob will call those scripts.

### Test plan

1. Configure bob in a new project
2. Define the `custom` target
3. Define a script that generates some files
4. Call bob build and make sure the script was called with the right
package manager

---------

Co-authored-by: Satyajit Sahoo <[email protected]>
  • Loading branch information
atlj and satya164 authored Jan 28, 2025
1 parent f06514d commit 5b42f44
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 1 deletion.
12 changes: 12 additions & 0 deletions docs/pages/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,18 @@ Generates the [React Native Codegen](https://reactnative.dev/docs/the-new-archit

You can ensure your Codegen generated scaffold code is stable through different React Native versions by shipping it with your library. You can find more in the [React Native Official Docs](https://reactnative.dev/docs/the-new-architecture/codegen-cli#including-generated-code-into-libraries).

#### `custom`

Define a custom build target. This is useful to call code generators during the build process.

##### `script`

Accepts a script name. `bob` will call the matching script defined under `package.json`'s `scripts` property. The build process **will throw and exit** if the target is defined without this option.

##### `clean`

You can pass a path to this option and `bob` will delete all the files on that path. The path is resolved relatively to where `build` was called from.

#### `commonjs`

Enable compiling source files with Babel and use CommonJS module system.
Expand Down
9 changes: 9 additions & 0 deletions packages/react-native-builder-bob/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import buildCommonJS from './targets/commonjs';
import buildModule from './targets/module';
import buildTypescript from './targets/typescript';
import buildCodegen from './targets/codegen';
import customTarget from './targets/custom';
import type { Options, Report, Target } from './types';

type ArgName = 'target';
Expand Down Expand Up @@ -584,6 +585,14 @@ async function buildTarget(
report,
});
break;
case 'custom':
await customTarget({
options: targetOptions,
source: path.resolve(root, source),
report,
root,
});
break;
default:
logger.exit(`Invalid target ${kleur.blue(targetName)}.`);
}
Expand Down
72 changes: 72 additions & 0 deletions packages/react-native-builder-bob/src/targets/custom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import kleur from 'kleur';
import path from 'path';
import fs from 'fs-extra';
import type { Input } from '../types';
import { spawn } from '../utils/spawn';
import dedent from 'dedent';
import del from 'del';

type Options = Omit<Input, 'output'> & {
options?: {
script?: string;
clean?: string;
};
};

export default async function customTarget({ options, root, report }: Options) {
if (options?.script == null) {
report.error(
dedent(
`No script was provided with the custom target.
Example: ${kleur.green('{["custom", { "script": "generateTypes" }}')}`
)
);
process.exit(1);
}

const pathToClean = options.clean
? path.relative(root, options.clean)
: undefined;

if (pathToClean) {
report.info(`Cleaning up ${kleur.blue(pathToClean)}`);

await del([path.resolve(root, pathToClean)]);
}

const packageManagerExecutable = process.env.npm_execpath ?? 'npm';
const packageManagerArgs = ['run', options.script];

// usr/bin/yarn -> yarn
const packageManagerName = path.basename(packageManagerExecutable);
report.info(
`Running ${kleur.blue(packageManagerName)} ${kleur.blue(
packageManagerArgs.join(' ')
)}`
);

try {
await spawn(packageManagerExecutable, packageManagerArgs, {
stdio: ['ignore', 'ignore', 'inherit'],
});
} catch (e) {
report.error(
`An error occurred when running ${kleur.blue(options.script)}`
);
process.exit(1);
}

report.success(`Ran the ${kleur.blue(options.script)} script succesfully`);

if (options.clean && pathToClean && !(await fs.pathExists(pathToClean))) {
report.warn(
`Custom target with the ${kleur.blue(
options.script
)} script has ${kleur.blue(options.clean)} as the ${kleur.bold(
'clean'
)} option but this path wasn't created after running the script. Are you sure you've defined the ${kleur.bold(
'clean'
)} path correctly?`
);
}
}
7 changes: 6 additions & 1 deletion packages/react-native-builder-bob/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ export type Input = {
report: Report;
};

export type Target = 'commonjs' | 'module' | 'typescript' | 'codegen';
export type Target =
| 'commonjs'
| 'module'
| 'typescript'
| 'codegen'
| 'custom';

export type Options = {
source?: string;
Expand Down

0 comments on commit 5b42f44

Please sign in to comment.