Overview of React Native Builder Bob
maincreate-react-native-library to help developers set up new libraries efficiently.repository·main·Indexed 25 days ago
https://github.com/callstack/react-native-builder-bobA suite of CLI tools to scaffold and build React Native libraries for various targets. It includes create-react-native-library for project scaffolding and the bob CLI for compiling JavaScript files. Supported build targets include ES modules, CommonJS, TypeScript, Flow, and React Native Codegen for the New Architecture.
create-react-native-library to help developers set up new libraries efficiently.To ensure your library works across different environments (Node.js, modern bundlers, and legacy tools), your package.json should include main, types, and exports fields.
main: Used by legacy tools like Metro < 0.82.0.types: Used by legacy TypeScript setups (e.g., moduleResolution: "node10").exports: The modern standard for Node.js 12+ and modern bundlers. It uses conditional exports to resolve the correct entry point.Note: If you provide an Expo Config plugin (e.g., ./app.plugin.js), you must explicitly expose it in the exports field so other tools can access it.
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
"exports": {
".": {
"my-library-source": "./src/index.tsx",
"types": "./lib/typescript/src/index.d.ts",
"default": "./lib/module/index.js"
},
"./package.json": "./package.json",
"./app.plugin.js": "./app.plugin.js"
}Use create-react-native-library to scaffold a new React Native library project with pre-configured tools including TypeScript, Turbo Modules, Fabric, Kotlin (Android), Swift (iOS), and react-native-builder-bob. The CLI will prompt you with configuration questions to generate the project folder.
npx create-react-native-library@latest awesome-libraryThe codegen target generates React Native Codegen scaffold code. To use this, follow these integration steps:
"codegen" to your targets in package.json or bob.config.js.@react-native-community/cli as a devDependency.codegenConfig to package.json:"codegenConfig": {
"outputDir": {
"ios": "ios/generated",
"android": "android/generated"
},
"includesGeneratedCode": true
}#import <YourProjectName/YourProjectNameSpec.h>).react-native.config.js at the root with the cmakeListsPath:module.exports = {
dependency: {
platforms: {
android: {
cmakeListsPath: 'generated/jni/CMakeLists.txt',
},
},
},
};invokeLibraryCodegen task to example/android/app/build.gradle that runs npx bob build --target codegen.pre_install hook to example/ios/Podfile that runs npx bob build --target codegen.Instead of providing both import and require conditions, you can use tool-specific conditions in the exports field. This allows each tool to load the appropriate build without creating separate instances in the same runtime.
Example setup for Webpack, Vite, Rollup, Metro (React Native), and Node.js 22.10.0+:
react-native: For Metro in React Native.module: For bundlers like Webpack, Vite, or Rollup.module-sync: For Node.js 22.10.0+ (handles both import and require).default: Fallback for other environments.If using TypeScript, you may need to configure customConditions in your tsconfig.json to resolve these correctly.
{
"main": "./lib/commonjs/index.js",
"module": "./lib/module/index.js",
"types": "./lib/typescript/commonjs/src/index.d.ts",
"exports": {
".": {
"react-native": {
"types": "./lib/typescript/module/src/index.d.ts",
"default": "./lib/module/index.js"
},
"module": {
"types": "./lib/typescript/module/src/index.d.ts",
"default": "./lib/module/index.js"
},
"module-sync": {
"types": "./lib/typescript/module/src/index.d.ts",
"default": "./lib/module/index.js"
},
"default": {
"types": "./lib/typescript/commonjs/src/index.d.ts",
"default": "./lib/commonjs/index.js"
}
},
"./package.json": "./package.json"
}
}To upgrade react-native for development and testing purposes in a project generated by react-native-builder-bob, perform the following:
react-native, react, @types/react, and @types/react-native (and related packages like react-test-renderer) under devDependencies in your root package.json.react-native in the example app following standard React Native upgrade procedures (Expo or CLI).Note: Ensure that the versions of react and react-native match exactly between example/package.json and the root package.json to avoid issues.
To manually integrate react-native-builder-bob into an existing project, follow these steps:
Install the package as a development dependency:
yarn add --dev react-native-builder-bobConfigure build targets in your package.json under the react-native-builder-bob key (see Configuration Options for details).
Add a build script to your package.json. It is recommended to use the prepare script to ensure compatibility across different package managers and Git installations:
"scripts": {
"prepare": "bob build"
}Set up entry points in package.json (e.g., main, types, exports) to point to the generated files in your output directory.
Ignore generated files by adding your output directory (e.g., lib/) to .gitignore and .eslintignore.
Configure Jest to ignore the output directory by adding it to modulePathIgnorePatterns in your Jest configuration.
"scripts": {
"prepare": "bob build"
}If you need to support both ES modules (ESM) and CommonJS (CJS) environments, you can configure a dual package setup. This involves creating two builds of your library and mapping them via the exports field in package.json.
Add the commonjs target to your react-native-builder-bob configuration in package.json or bob.config.js:
"react-native-builder-bob": {
"source": "src",
"output": "lib",
"targets": [
["module", { "esm": true }],
["commonjs", { "esm": true }],
"typescript"
]
}package.json exportsUpdate the exports field to include import (for ESM) and require (for CJS) conditions. Each condition should include a types field for TypeScript and a default field for the JS code.
main: Point to the CommonJS build to support tools that do not recognize the exports field.module: Point to the ESM build for tools that use this non-standard field.types: Point to the CommonJS type definitions to support legacy TypeScript configurations (e.g., moduleResolution: "node10").{
"main": "./lib/commonjs/index.js",
"module": "./lib/module/index.js",
"types": "./lib/typescript/commonjs/src/index.d.ts",
"exports": {
".": {
"import": {
"types": "./lib/typescript/module/src/index.d.ts",
"default": "./lib/module/index.js"
},
"require": {
"types": "./lib/typescript/commonjs/src/index.d.ts",
"default": "./lib/commonjs/index.js"
}
},
"./package.json": "./package.json"
}
}To start using react-native-builder-bob to build JavaScript files for your React Native library, run the init command via npx within your project directory.
cd your-project
npx react-native-builder-bob@latest initTo configure an existing project to use bob, run the init command. This adds the necessary configuration and dependencies to your project. It is recommended to run this using npx to ensure you are using the latest version.
npx react-native-builder-bob@latest initThe build command compiles and prepares your project according to your configuration. This command is typically integrated into your package's publishing workflow by adding it to the prepare or prepack scripts in your package.json.
"scripts": {
"prepare": "bob build"
}If your library uses a custom condition (like my-library-source) to resolve source files during development, you must configure your tools to recognize this condition:
Add the condition to testEnvironmentOptions.customExportConditions. When using the React Native Jest preset, ensure you include the default React Native conditions as well.
Add the condition to resolve.conditions in your Vite configuration.
Pass the condition to the conditions array in the Metro configuration.
// Jest
{
"jest": {
"preset": "@react-native/jest-preset",
"testEnvironmentOptions": {
"customExportConditions": ["require", "react-native", "my-library-source"]
}
}
}// Vite
import { defineConfig } from 'vite';
export default defineConfig({
resolve: {
conditions: ['my-library-source'],
},
});// react-native-monorepo-config
const config = withMetroConfig(getDefaultConfig(__dirname), {
root,
dirname: __dirname,
conditions: ['my-library-source'],
});