Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: run tasks in parallel with workers #792

Merged
merged 1 commit into from
Mar 29, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 10 additions & 24 deletions packages/react-native-builder-bob/src/build.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import path from 'path';
import fs from 'fs-extra';
import kleur from 'kleur';
import * as logger from './utils/logger';
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 path from 'path';
import yargs from 'yargs';
import { type Options, type Target } from './types';
import fs from 'fs-extra';
import { loadConfig } from './utils/loadConfig';
import yargs from 'yargs';
import * as logger from './utils/logger';
import { run } from './utils/workerize';

export const args = {
target: {
@@ -147,21 +143,11 @@ async function buildTarget({

switch (targetName) {
case 'commonjs':
await buildCommonJS({
root,
source: path.resolve(root, source),
output: path.resolve(root, output, 'commonjs'),
exclude,
options: targetOptions,
variants,
report,
});
break;
case 'module':
await buildModule({
await run(targetName, {
root,
source: path.resolve(root, source),
output: path.resolve(root, output, 'module'),
output: path.resolve(root, output, targetName),
exclude,
options: targetOptions,
variants,
@@ -183,7 +169,7 @@ async function buildTarget({
return false;
}) ?? false;

await buildTypescript({
await run('typescript', {
root,
source: path.resolve(root, source),
output: path.resolve(root, output, 'typescript'),
@@ -195,15 +181,15 @@ async function buildTarget({
}
break;
case 'codegen':
await buildCodegen({
await run('codegen', {
root,
source: path.resolve(root, source),
output: path.resolve(root, output, 'typescript'),
report,
});
break;
case 'custom':
await customTarget({
await run('custom', {
options: targetOptions,
source: path.resolve(root, source),
report,
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'fs-extra';
import path from 'path';
import type { Report } from '../../../types';
import kleur from 'kleur';

export const CODEGEN_DOCS =
'https://reactnative.dev/docs/the-new-architecture/using-codegen#configuring-codegen';
@@ -50,7 +51,9 @@ export async function patchCodegenAndroidPackage(
// If this issue is ever fixed in react-native, this check will prevent the patching from running.
if (!(await fs.pathExists(codegenJavaPath))) {
report.info(
`Could not find ${codegenJavaPath}. Skipping patching codegen java files.`
`Could not find ${kleur.blue(
path.relative(projectPath, codegenJavaPath)
)}. Skipping patching codegen java files.`
);
return;
}
94 changes: 94 additions & 0 deletions packages/react-native-builder-bob/src/utils/workerize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import kleur from 'kleur';
import {
Worker,
isMainThread,
parentPort,
workerData,
} from 'node:worker_threads';
import codegen from '../targets/codegen';
import commonjs from '../targets/commonjs';
import custom from '../targets/custom';
import module from '../targets/module';
import typescript from '../targets/typescript';
import type { Report, Target } from '../types';

type WorkerData<T extends Target> = {
target: T;
data: Omit<Parameters<(typeof targets)[T]>[0], 'report'>;
};

const targets = {
commonjs,
module,
typescript,
codegen,
custom,
} as const;

export const run = async <T extends Target>(
target: T,
{ report, ...data }: Parameters<(typeof targets)[T]>[0]
) => {
if (!isMainThread) {
throw new Error('Worker can only be run from the main thread');
}

const worker = new Worker(__filename, {
workerData: {
target,
data,
} satisfies WorkerData<T>,
env: {
...process.env,
FORCE_COLOR: process.stdout.isTTY ? '1' : '0',
},
});

worker.on('message', (message) => {
switch (message.type) {
case 'info':
report.info(message.message);
break;
case 'warn':
report.warn(message.message);
break;
case 'error':
report.error(message.message);
break;
case 'success':
report.success(message.message);
break;
}
});

worker.on('error', (error) => {
report.error(error.message);
});

worker.on('exit', (code) => {
if (code !== 0) {
report.error(`exited with code ${kleur.red(code)}`);
}
});
};

if (!isMainThread) {
const { target, data } = workerData as WorkerData<Target>;

const report: Report = {
info: (message) => parentPort?.postMessage({ type: 'info', message }),
warn: (message) => parentPort?.postMessage({ type: 'warn', message }),
error: (message) => parentPort?.postMessage({ type: 'error', message }),
success: (message) => parentPort?.postMessage({ type: 'success', message }),
};

if (target in targets) {
// @ts-expect-error - typescript doesn't support correlated union types https://github.com/microsoft/TypeScript/issues/30581
targets[target]({ ...data, report }).catch((error) => {
console.log(error);
process.exit(1);
});
} else {
throw new Error(`Unknown target: ${target}`);
}
}
Loading
Oops, something went wrong.