• Stars
    star
    2,771
  • Rank 16,436 (Top 0.4 %)
  • Language
    JavaScript
  • Created over 5 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

👷‍♂️ Simple set of CLIs to scaffold and build React Native libraries for different targets

Bob

create-react-native-library react-native-builder-bob MIT License

👷‍♂️ Set of CLIs to scaffold and build React Native libraries for different targets.

Scaffold React Native libraries

If you want to create your own React Native module, scaffolding the project can be a daunting task. create-react-native-library can scaffold a new project for you with the following things:

  • Minimal boilerplate modules on which you can build upon
  • Example React Native app to test your modules
  • TypeScript to ensure type-safe code and better DX
  • Support for Turbo Modules & Fabric
  • Support for Kotlin on Android & Swift on iOS
  • Support for C++ to write cross-platform native code
  • Expo for libraries without native code and web support
  • ESLint, Prettier, TypeScript, Lefthook and Release It pre-configured
  • react-native-builder-bob pre-configured to compile your files
  • GitHub Actions pre-configured to run tests and lint on the CI

To create new project, run the following:

npx create-react-native-library@latest awesome-library

This will ask you few questions about your project and generate a new project in a folder named awesome-library.

Build React Native libraries

react-native-builder-bob can build code in your React Native library for following targets:

  • Generic CommonJS build
  • ES modules build for bundlers such as webpack
  • Flow definitions (copies .js files to .flow files)
  • TypeScript definitions (uses tsc to generate declaration files)
  • Android AAR files

If you created a project with create-react-native-library, react-native-builder-bob is already pre-configured to build your project. You don't need to configure it again.

The following configuration steps are for projects not created with create-react-native-library.

Automatic configuration

To automatically configure your project to use react-native-builder-bob, open a Terminal and run:

npx react-native-builder-bob@latest init

Manual configuration

To configure your project manually, follow these steps:

  1. First, install react-native-builder-bob in your project. Open a Terminal in your project, and run:
yarn add --dev react-native-builder-bob
  1. In your package.json, specify the targets to build for:

    "react-native-builder-bob": {
      "source": "src",
      "output": "lib",
      "targets": [
        ["commonjs", {"copyFlow": true}],
        "module",
        "typescript",
      ]
    }

    See options below for more details.

  2. Add bob to your prepack step:

    "scripts": {
      "prepack": "bob build"
    }
  3. Configure the appropriate entry points:

    "main": "lib/commonjs/index.js",
    "module": "lib/module/index.js",
    "react-native": "src/index.ts",
    "types": "lib/typescript/index.d.ts",
    "files": [
      "lib/",
      "src/"
    ]

    Make sure to change specify correct files according to the targets you have enabled.

    It's usually good to point to your source code with the react-native field to make debugging easier. Metro already supports compiling a lot of new syntaxes including JSX, Flow and TypeScript and it will use this field if present.

    If you're building TypeScript definition files, also make sure that the types field points to a correct path. Depending on the project configuration, the path can be different for you than the example snippet (e.g. lib/typescript/index.d.ts if you have only the src directory).

  4. Add the output directory to .gitignore and .eslintignore

    # generated files by bob
    lib/
  5. Add the output directory to jest.modulePathIgnorePatterns if you use Jest

    "modulePathIgnorePatterns": ["<rootDir>/lib/"]

And we're done 🎉

Options

The options can be specified in the package.json file under the react-native-builder-bob property, or in a bob.config.js file in your project directory.

source

The name of the folder with the source code which should be compiled. The folder should include an index file.

output

The name of the folder where the compiled files should be output to. It will contain separate folder for each target.

targets

Various targets to build for. The available targets are:

commonjs

Enable compiling source files with Babel and use commonjs module system.

This is useful for running the code in Node (SSR, tests etc.). The output file should be referenced in the main field of package.json.

By default, the code is compiled to support last 2 versions of modern browsers. It also strips TypeScript and Flow annotations, and compiles JSX. You can customize the environments to compile for by using a browserslist config.

In addition, the following options are supported:

  • configFile & babelrc (boolean): To customize the babel config used, you can pass the configFile option as true if you have a babel.config.js or babelrc option if you have a .babelrc. This may break the default configuration, so use these options only if you know what you're doing.

  • copyFlow (boolean): If your source code is written in Flow, You can specify the copyFlow option to copy the source files as .js.flow to the output folder. If the main entry in package.json points to the index file in the output folder, the flow type checker will pick these files up to use for type definitions.

  • sourceMaps (boolean): Sourcemaps are generated by default alongside the compiled files. You can disable them by setting the sourceMaps option to false.

Example:

["commonjs", { "configFile": true, "copyFlow": true }]
module

Enable compiling source files with Babel and use ES module system. This is essentially same as the commonjs target and accepts the same options, but leaves the import/export statements in your code.

This is useful for bundlers which understand ES modules and can tree-shake. The output file should be referenced in the module field of package.json.

Example:

["module", { "configFile": true }]
typescript

Enable generating type definitions with tsc if your source code is written in TypeScript.

The following options are supported:

  • project (string): By default, the tsconfig.json file in the root of your project is used to generate the type definitions. You can specify a path to a different config by using the project option. This can be useful if you need to use different configs for development and production.

  • tsc (string): The path to the tsc binary is automatically detected and defaults to the one installed in your project. You can use the tsc option to specify a different path.

Example:

["typescript", { "project": "tsconfig.build.json" }]
aar

Enable assembling Android AAR files for a library for React Native modules including native code.

The following options are supported:

  • reverseJetify (boolean): If your package is using AndroidX, it's possible to convert the AAR with the reverseJetify option to use the Android support Library using the jetifier package. This is useful to publish packages for older projects which haven't migrated to AndroidX.

  • androidPath (string): You can specify a custom path to the android directory if it's not in the default location (android in the root of your project).

  • androidBundleName: By default, the generated aar file is named as android.aar. You can specify a custom name using this option.

Example:

["aar", { "reverseJetify": true }]

Commands

The bob CLI exposes the following commands:

init

This configures an existing project to use bob by adding the required configuration and dependencies. This is usually run with npx:

npx react-native-builder-bob@latest init

build

This builds the project according to the configuration. This is usually run as part of the package's publishing flow, i.e. in the prepare or prepack scripts.

"scripts": {
  "prepack": "bob build"
}

FAQ

Why should I compile my project with react-native-builder-bob?

We write our library code in non-standard syntaxes such as JSX, TypeScript etc. as well as proposed syntaxes which aren't part of the standard yet. This means that our code needs to be compiled to be able to run on JavaScript engines.

When using the library in a React Native app, Metro handles compiling the source code. However, it's also possible to use them in other targets such as web, run in Node for tests or SSR etc. So we need to compile the source code for them as well.

Currently, to handle such multiple targets, we need to have multiple babel configs and write a long babel-cli command in our package.json. We also need to keep the configs in sync between our projects.

Just as an example, this is a command we have in one of the packages: babel --extensions '.js,.ts,.tsx' --no-babelrc --config-file=./babel.config.publish.js src --ignore '**/__tests__/**' --copy-files --source-maps --delete-dir-on-start --out-dir dist && del-cli 'dist/**/__tests__' && yarn tsc --emitDeclarationOnly. This isn't all, there's even a separate babel.config.publish.js file. And this only works for webpack and Metro, and will fail on Node due to ESM usage.

react-native-builder-bob wraps tools such as babel and typescript to simplify these common tasks across multiple projects. It's tailored specifically to React Native projects to minimize the configuration required.

How do I add a react-native library containing native code as a dependency in my library?

If your library depends on another react-native library containing native code, you should do the following:

  • Add the native library to peerDependencies

    This means that the user will need to install the native library and add it to their package.json. It makes sure that:

    • There are no version conflicts if another package also happens to use the same library, or if the user wants to use the library in their app. While there can be multiple versions of a JavaScript-only library, there can only be one version of a native library - so avoiding version conflicts is important.
    • The package manager installs it in correct location so that autolinking can work properly.

    Don't add the native library to dependencies, otherwise it may cause issues for the user even if it seems to work.

  • Add the native library to devDependencies

    This makes sure that you can use it for tests, and there are no other errors such as type errors due to the missing module.

  • Add the native library to dependencies in the package.json under example

    This is equivalent to the consumer of the library installing the dependency, and is needed so that this module is also available to the example app.

How to upgrade the react-native version in the generated project?

Since this is a library, the react-native version specified in the package.json is not relevant for the consumers. It's only used for developing and testing the library. If you'd like to upgrade the react-native version to test with it, you'd need to:

  1. Bump versions of the following packages under devDependencies in the package.json:

    • react-native
    • react
    • @types/react
    • @types/react-native

    If you have any other related packages such as react-test-renderer, make sure to bump them as well.

  2. Upgrade react-native in the example app.

    The example app is a React Native app that can be updated following the same process as a regular React Native app. The process will vary depending on if it's using Expo or React Native CLI. See the official upgrade guide for more details.

To avoid issues, make sure that the versions of react and react-native are the same in example/package.json and the package.json at the root.

How does the library get linked to the example app in the generated project?

If you generate a project with create-react-native-library, you get an example app to test your library. It's good to understand how the library gets linked to the example app in case you want to tweak how it works or if you run into issues.

There are 2 parts to this process.

  1. Aliasing the JavaScript code

    The JavaScript (or TypeScript) source code is aliased to be used by the example app. This makes it so that when you import from 'your-library-name', it imports the source code directly and avoids having to rebuild the library for JavaScript only changes. We configure several tools to make this work:

    • Babel is configured to use the alias in example/babel.config.js using babel-plugin-module-resolver. This transforms the imports to point to the source code instead.
    • Metro is configured to allow importing from outside of the example directory by configuring watchFolders, and to use the appropriate peer dependencies. This configuration exists in the example/metro.config.js file.
    • Webpack is configured to compile the library source code when running on the Web. This configuration exists in the example/webpack.config.js file.
    • TypeScript is configured to use the source code for type checking by using the paths property under compilerOptions. This configuration exists in the tsconfig.json file at the root.
  2. Linking the native code

    By default, React Native CLI only links the modules installed under node_module of the app. To be able to link the android and ios folders from the project root, the path is specified in the example/react-native.config.js file.

How to test the library in an app locally?

You may have come across the yarn link and npm link commands to test libraries locally. These commands work great for simple packages without build process, but they have different behavior from how a published package works.

For more accurate testing, we recommend following approaches:

  1. Local tarball with npm

    First, temporarily change the version in package.json to something like 0.0.0-local.0. This version number needs to be updated to something different every time you do this to avoid stale content.

    Run the following command inside your library's root:

    npm pack

    This will generate a file like your-library-name-0.0.0-local.0.tgz in the root of the project.

    Then, you can install the tarball in your app:

    yarn add ../path/to/your-library-name-0.0.0-local.0.tgz

    Or if you use npm:

    npm install ../path/to/your-library-name-0.0.0-local.0.tgz
  2. Verdaccio

    Verdaccio is a lightweight private npm registry that can be used to test packages locally. The advantage of using Verdaccio is that it allows to test the complete workflow of publishing and installing a package without actually publishing it to a remote registry.

    You can find installation and usage instructions in the Verdaccio documentation.

Development workflow

This project uses a monorepo using yarn. To setup the project, run yarn in the root directory to install the required dependencies.

yarn

While developing, you can run watch mode to automatically rebuild the changes:

yarn watch

To test the CLI locally, you can point to the bin/bob executable:

../bob/packages/create-react-native-library/bin/create-react-native-library

Before sending a pull request, make sure your code passes TypeScript and ESLint. Run the following to verify:

yarn typecheck
yarn lint

To fix formatting errors, run the following:

yarn lint --fix

Acknowledgements

Thanks to the authors of these libraries for inspiration:

Alternatives

There are other similar tools to scaffold React Native libraries. The difference is that the generated project with create-react-native-library is very opinionated and configured with additional tools.

LICENSE

MIT

More Repositories

1

react-native-paper

Material Design for React Native (Android & iOS)
TypeScript
12,811
star
2

linaria

Zero-runtime CSS in JS library
TypeScript
11,659
star
3

haul

Haul is a command line tool for developing React Native apps, powered by Webpack
TypeScript
3,643
star
4

react-native-testing-library

🦉 Simple and complete React Native testing utilities that encourage good testing practices.
TypeScript
3,078
star
5

react-native-pager-view

React Native wrapper for the Android ViewPager and iOS UIPageViewController.
TypeScript
2,711
star
6

repack

A Webpack-based toolkit to build your React Native application with full support of Webpack ecosystem.
TypeScript
1,471
star
7

reassure

Performance testing companion for React and React Native
TypeScript
1,269
star
8

react-native-slider

React Native component exposing Slider from iOS and SeekBar from Android
TypeScript
1,189
star
9

react-native-ios-kit

The missing React Native UI Kit for iOS
JavaScript
521
star
10

react-theme-provider

A set of utilities that help you create your own React theming system in few easy steps
JavaScript
466
star
11

react-native-fbads

Facebook Audience SDK integration for React Native
Java
439
star
12

super-app-showcase

Monorepository template for super app development with React Native and Re.Pack
JavaScript
413
star
13

react-native-image-editor

A library providing an API for cropping images from the web and the local file system.
Kotlin
373
star
14

react-native-brownfield

Set of helpers to make your brownfield integration smooth and easy.
Kotlin
241
star
15

react-native-paper-login-template

The easiest way to start with your application.
TypeScript
239
star
16

react-native-opentok

React Native OpenTok
Objective-C
202
star
17

component-docs

📝 Simple documentation for your React components
TypeScript
137
star
18

react-native-open-source-board

OSS board with triaged React Native issues.
125
star
19

async-storage

Cross platform storage for React, built on top of AsyncStorage
JavaScript
109
star
20

react-native-material-palette

Bringing Material Palette API to React Native
JavaScript
105
star
21

ts-regex-builder

Maintainable regular expressions for TypeScript and JavaScript.
TypeScript
83
star
22

react-native-multibundle

JavaScript
57
star
23

eslint-config-callstack

ESLint preset extending Flow, Prettier and Jest
JavaScript
52
star
24

repack-examples

Repository with examples for Re.Pack
Java
50
star
25

ai-meeting-transcription

AI Tool for meeting transcriptions
Jupyter Notebook
36
star
26

react-native-socket-mobile

React Native module for the Socket Mobile SDK.
JavaScript
35
star
27

web3-react-native-dapp-wagmi

TypeScript
30
star
28

fabric-library-with-custom-cpp-example

Add custom cpp state to your fabric library
Java
29
star
29

super-app-example

This repository presents a compact super-app example from Callstack's blog, illustrating the use of a monorepo structure together with Re.Pack and Module Federation.
Java
27
star
30

hapi-graphql-boilerplate

JavaScript
26
star
31

react-native-detox-example

Example integration of Detox and Jest
Objective-C
23
star
32

linaria-styled

Zero-runtime CSS in JS library for building React components
18
star
33

web3-cross-platform-dapp

TypeScript
17
star
34

parcel-plugin-linaria

Parcel plugin for Linaria (Experimental)
JavaScript
17
star
35

benz-ql

GraphQL server for the Mercedes APIs
JavaScript
16
star
36

generator-node-module

A Yeoman module to author Node libraries with Prettier, Jest, Flow and Babel.
JavaScript
16
star
37

react-native-snapshot-tests

An example of snapshot testing with React Native
Objective-C
16
star
38

delightful-ux-training-app

JavaScript
15
star
39

universal-react-app

JavaScript
12
star
40

workshop-navigation

Navigation in React Native workshop.
JavaScript
12
star
41

ai-cli

AI assistant in your terminal.
TypeScript
11
star
42

github-comment-bot

JavaScript
10
star
43

news-mini-app-showcase

JavaScript
9
star
44

ReactNativeNotes

Notes demo application showing the abilities of React Native for desktop connected with UWP development
TypeScript
9
star
45

talk-universal-react

JavaScript
8
star
46

ai-summarization

AI summarization tool
Jupyter Notebook
7
star
47

react-native-releases-script

Script to generate changelog for RN releases
7
star
48

web3-react-native-dapp-viem

TypeScript
6
star
49

callstack-hackathon-team-ferran

callstack-hackaton-team-ferran
JavaScript
5
star
50

callstack-hackathon-team-dratwa-wojtek

JavaScript
3
star
51

reassure-examples

Examples for Reassure setup with different frameworks.
JavaScript
3
star
52

web3-react-native-testing

Best practices for testing React Native web3 dapps
TypeScript
3
star
53

DMAIC-Performance-Workshop

Dedicated app for the DMAIC Performance Workshop
TypeScript
2
star
54

.github

Templates for all Callstack OSS projects
2
star
55

react-native-paper-codemod

JavaScript
2
star
56

web3-react-native-siwe

Sign-In With Ethereum (SIWE) implementation in React Native
TypeScript
2
star
57

AppleVisionBGFX

Usage of BGFX in visionOS
C++
2
star
58

sample-weather-app

JavaScript
1
star
59

callstack.github.io

Organisation Github Page
HTML
1
star
60

react-native-visionos-docs

Documentation website for react-native-visionos
JavaScript
1
star
61

workshop-universal-sunshine

Universal React Native & React app based on Sunshine: https://github.com/udacity/Sunshine-Version-2
1
star