react-native-builder-bob?We often 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:
So the code needs to be precompiled so these tools can parse it. In addition, we need to generate type definition files for TypeScript etc.
To handle such multiple targets, one solution could is to have multiple babel configs (or TypeScript configs) and have a babel-cli command in our package.json for compilation. Ideally, we should also keep the configs in sync between our several projects.
As an example, this is a command that we had in one of the packages:
As you can see, it's quite long and hard to read. 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. While it can be used for any library, it's primarily tailored to React Native projects to minimize the configuration required.
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 consumer of the library will need to install the native library and add it to the dependencies section of their package.json. It makes sure that:
Don't add the native library to dependencies of your library, 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.
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:
Bump versions of the following packages under devDependencies in the package.json:
react-nativereact@types/react@types/react-nativeIf you have any other related packages such as react-test-renderer, make sure to bump them as well.
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.
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.
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:
example directory by configuring watchFolders, to use the appropriate peer dependencies, and to import source code of the library in the example. This configuration exists in the example/metro.config.js file.paths property under compilerOptions. This configuration exists in the tsconfig.json file at the root.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.
You may have come across the yarn link and npm link commands, or used npm install ../path/to/folder or yarn add ../path/to/folder to test libraries locally. These commands may work for simple packages without build process, but they have different behavior from how a published package works, e.g. .npmignore is not respected, the structure of node_modules is different, etc. So we don't recommended using these approaches to test libraries locally.
For more accurate testing, there are various other approaches:
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:
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:
Or if you use npm:
Yalc
Yalc acts as a local repository for packages that can be used to test packages locally. It's similar to the previous workflow, but more convenient to use.
You can find installation and usage instructions in the Yalc documentation.
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.
If users are using Yarn 1, they may get a warning when installing your library:
This is because the example app is configured as a Yarn workspace, and there is a bug in Yarn 1 which causes this warning to be shown for third-party packages. It has no impact for the consumers of the library and the warning can be ignored. If consumers would like to get rid of the warning, there are 2 options:
Disable workspaces
If the consumer doesn't use Yarn workspaces, they can disable it by adding the following to the .yarnrc file in the root of their project:
Upgrade to Yarn 3
Yarn 1 is no longer maintained, so it's recommended to upgrade to Yarn 3. Yarn 3 works with React Native projects with the node-modules linker. To upgrade, consumers can follow the official upgrade guide.
It's also necessary to use node-modules linker. To use it, consumers can add the following to the .yarnrc.yml file in the root of their project: