Skip to main content

Dependency Management

Ready for some magic? This guide will fundamentally change the way you maintain your React Native applications and libraries. It all centers on one tool -- the dependency manager.

tip

Not quite ready to make the leap? Learn more about dependencies first.

Onboarding

The first order of business is onboarding your React Native packages to the dependency manager. Do this for every React Native package you have. It can be done all at once, or gradually over multiple PRs.

First, add the dependency manager to your package.

yarn add @rnx-kit/align-deps --dev

Add new script commands for convenience. We'll use these later.

package.json
{
"scripts": {
"check-dependencies": "rnx-align-deps",
"fix-dependencies": "rnx-align-deps --write"
}
}

Next, generate the dependency manager configuration for your package. If your package produces a bundle, it's an app. Otherwise, it's a library.

yarn rnx-align-deps --init app
yarn rnx-align-deps --init library

Fix any React Native package versions that might have compatibility issues.

yarn fix-dependencies

Review and test your changes before committing. This is important, even for seemingly harmless updates.

Automating Everything

Once onboarding is done, you're ready to set up automation.

Automation validates your React Native dependencies during builds and PRs. It also keeps the dependency manager up-to-date, including the built-in list of known/good React Native package versions and releases. This list can change frequently, based on the volatility of the React Native ecosystem.

Builds

To validate dependencies during a build, you'll integrate the check-dependencies command into your build workflow.

In each of your React Native packages, add it to the build command:

package.json
{
"scripts": {
"build": "... existing-stuff ... && yarn fix-dependencies"
}
}

Replace yarn with npm run or pnpm, depending on your package manager.

When the validation process finds a compatibility problem, it fails with a detailed message, showing you what went wrong before you commit to the repo.

Using a Task Runner?

If you're using a task runner like Lage or Gulp, you can go for a more sophisticated integration. The advantage being that fix-dependencies could run as its own task with isolated logging and error handling. And, you can run it in parallel with other tasks.

Pull Requests

To validate dependencies during PRs, you'll use the dependency manager to check every package in your repo.

Add the dependency manager to your repo's root package.json.

yarn add @rnx-kit/align-deps --dev -W

Next, add this command to your PR loop. It runs the dependency manager from the root of the repo, scanning all packages. This include packages which haven't onboarded yet. For those, --requirements react-native@[version] controls the target React Native release to use when checking compatibility.

yarn rnx-align-deps --requirements react-native@0.66

When a compatibility problem is found, the command fails with a non-zero exit code, which causes the PR loop to fail. This protects the repo from risky changes.

In the PR logs, you'll see a detailed report, in diff format, explaining what went wrong.

error Found 3 violation(s) in 'packages/app/package.json':
react-native "^0.66.0" -> "^0.66.0-0" (dependencies)
react-native-macos "^0.66.0" -> "^0.66.0-0" (dependencies)
react-native-windows "^0.66.0" -> "^0.66.0-0" (dependencies)
- Current
+ Expected

{
"name": "@rnts/button",
"version": "0.0.1",
"private": true,
"license": "MIT",
"main": "src/index.ts",
"typings": "lib/index.d.ts",
"scripts": {
"clean": "rimraf ./lib",
"build": "yarn run clean && yarn run tsc && yarn run api-extract",
"api-extract": "api-extractor run --local --verbose"
},
"devDependencies": {
"@microsoft/api-extractor": "^7.19.4",
"@office-iss/react-native-win32": "^0.66.0",
"@rnx-kit/align-deps": "^2.0.0",
"@types/react-native": "^0.66.0",
- "rimraf": "^3.0.2",
"react": "17.0.2",
- "react-native": "^0.66.0",
- "react-native-macos": "^0.66.0",
- "react-native-windows": "^0.66.0",
+ "react-native": "^0.66.0-0",
+ "react-native-macos": "^0.66.0-0",
+ "react-native-windows": "^0.66.0-0",
+ "rimraf": "^3.0.2",
"typescript": "^4.5.5"
},
"rnx-kit": {
"kitType": "library",
"alignDeps": {
"requirements": {
"development": ["react-native@0.66"],
"production": ["react-native@0.66"]
},
"capabilities": [
"core-android",
"core-ios",
"core-macos",
"core-windows",
"react"
]
}
+ },
+ "peerDependencies": {
+ "react": "17.0.2",
+ "react-native": "^0.66.0-0",
+ "react-native-macos": "^0.66.0-0",
+ "react-native-windows": "^0.66.0-0"
}
}
error 'packages/button/package.json': Changes are needed to satisfy all requirements. Re-run with `--write` to apply them.
info Visit https://aka.ms/align-deps information about align-deps.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Fixing problems is automated, too! From your development terminal, run the same command with a --write parameter.

yarn rnx-align-deps --requirements react-native@0.66 --write

Review and test the fixes before pushing them to your PR.

Dependency Manager Updates

The dependency manager comes with a built-in list of known/good React Native package versions and releases. Keeping the dependency manager up-to-date gives you the latest compatibility data.

If you are in GitHub, use Dependabot to keep your packages up-to-date, including the dependency manager. If you host your repo elsewhere, you can use tools like Snyk instead.

When a dependency manager update happens, the associated PR loop may fail with incompatible package errors. This is OK. It means the built-in list of React Native package versions has changed, and you need to update your packages in response.

Run this command from the root of your repo. It uses the dependency manager to make the fixes automatically.

yarn rnx-align-deps --write

Review and test the fixes before pushing them to the PR with the dependency manager update.

Upgrading React Native

When you're ready to upgrade to a new release of React Native (or downgrade to an old release), you can use the dependency manager to help you out.

First, update your PR loop definition. Find the rnx-align-deps --requirements react-native@[version] command and change the target React Native version.

Then, run these commands from the root of your repo to change your React Native version and adjust all React Native dependencies to be compatible. Replace [version] with your target React Native version in major.minor format, such as "0.66" or "0.68".

yarn rnx-align-deps --set-version [version]
yarn rnx-align-deps --requirements react-native@[version] --write

Review and test your packages thoroughly before merging these changes.

Customization

Did you know that you can add your own packages to the dependency manager's built-in list?

If your repo uses React Native packages that aren't known to the dependency manager, add them to the list! Or if you want to align other dependencies automatically, add them to the list too!

First, write the list of packages you want to manage. Each one is expressed as a capability. You can use a .js module, a .json file, or a module name.

dependency-profile.json
{
"0.66": {
"@types/node": {
"name": "@types/node",
"version": "^16.0.0",
"devOnly": true
},
"chalk": {
"name": "chalk",
"version": "^4.1.0"
},
"native-base": {
"name": "native-base",
"version": "^3.3.11",
"capabilities": ["react"]
}
}
}
note

Look at native-base in the example above. It's wrapped in a 0.66 version tag. That means it only applies to React Native 0.66.

Next, configure each of your onboarded React Native packages to use the list.

package.json
 {
"rnx-kit": {
"alignDeps": {
+ "presets": [
+ "microsoft/react-native",
+ "path/to/dependency-profile.json"
+ ],
"requirements": {
"development": ["react-native@0.66"],
"production": ["react-native@0.66"]
},
"capabilities": [
"core-android",
"core-ios",
"core-macos",
"core-windows",
"react"
]
}
}
}

Now it's time to use the list. Run the dependency manager to update all of your packages.

yarn rnx-align-deps --requirements react-native@0.66 --presets microsoft/react-native,path/to/dependency-profile.json --write

Review and test the changes before continuing.

The last step is updating the automation. Each command needs an extra --presets [paths] parameter.

  • Pull Requests: Change the rnx-align-deps --requirements react-native@[version] command
  • Dependency Manager Updates: Change the rnx-align-deps --write command
  • Upgrading React Native: Change the rnx-align-deps --requirements react-native@[version] --write command

Finish Line

Congratulations! Your React Native apps and libraries are now up-to-date and compatible with each other! And they should stay that way thanks to the automation you've put in place!

Was this helpful? Help spread the word on Twitter.

And, if you customized your list of dependencies, please consider contributing your work so that everyone can use it (including you). You can create an issue with your customizations or even submit a pull request.