Frequently Asked Questions
Why should I compile my project with 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:
- Browsers or bundlers such as webpack (opens in a new tab) (if we support Web)
- Node.js (opens in a new tab) for tests or SSR etc.
So the code needs to be precompiled so these tools can parse it. In addition, we need to generate type definition files for TypeScript (opens in a new tab) 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:
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
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.
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 consumer of the library will need to install the native library and add it to the
dependencies
section of theirpackage.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
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 thepackage.json
underexample
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:
-
Bump versions of the following packages under
devDependencies
in thepackage.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. -
Upgrade
react-native
in theexample
appThe 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 (opens in a new tab) or React Native CLI (opens in a new tab). See the official upgrade guide (opens in a new tab) 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.
-
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 (opens in a new tab) is configured to use the alias in
example/babel.config.js
using babel-plugin-module-resolver (opens in a new tab). This transforms the imports to point to the source code instead. - Metro (opens in a new tab) is configured to allow importing from outside of the
example
directory by configuringwatchFolders
, and to use the appropriate peer dependencies. This configuration exists in theexample/metro.config.js
file. - Webpack (opens in a new tab) is configured to compile the library source code when running on the Web. This configuration exists in the
example/webpack.config.js
file. - TypeScript (opens in a new tab) is configured to use the source code for type checking by using the
paths
property undercompilerOptions
. This configuration exists in thetsconfig.json
file at the root.
- Babel (opens in a new tab) is configured to use the alias in
-
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 theandroid
andios
folders from the project root, the path is specified in theexample/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, 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 like0.0.0-local.0
. This version number needs to be updated to something different every time you do this to avoid stale content (opens in a new tab).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
-
Yalc
Yalc (opens in a new tab) 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 (opens in a new tab).
-
Verdaccio
Verdaccio (opens in a new tab) 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 (opens in a new tab).
Users get a warning when they install my library
If users are using Yarn 1, they may get a warning when installing your library:
warning Workspaces can only be enabled in private projects.
This is because the example app is configured as a Yarn workspace, and there is a bug in Yarn 1 (opens in a new tab) 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:workspaces-experimental false
-
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 (opens in a new tab).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:nodeLinker: node-modules