How I upgraded project from NX to the latest version 0.72.3 of React Native
Tags: nx, reactnative
Published: 2023-08-26 12:20:12

Updating `react-native` is often associated with significant challenges for developers, often consuming a considerable amount of working time and effort, especially when a project utilizes numerous libraries or possesses a non-standard structure.

In this article, I will share the experiences I encountered in a project using the `NX` monorepository and discuss what helped me overcome this issue.

###  Upgrading to the new version of React Native following the guide

Initial dependency versions:

```
"nx": "16.4.0",
"react-native": "0.71.10",
```

Having a monorepository, it was necessary to upgrade to the latest version of `React Native`. Upon upgrading to version 0.72.3 using the [React Native Helper](https://react-native-community.github.io/upgrade-helper/), the projects build successfully, but we encounter an error:

```
react-native could not be found within the project or in these directories:
  ../../node_modules
> 1 | import { AppRegistry } from 'react-native'
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dyw7pkhile6cz8330ax8.png)

The issue is that `Metro` built the project somewhat incorrectly. The build process through `Metro` involves several stages:
* 		`Metro` constructs a graph of all modules.
* 		It transpiles modules into a format understandable by `React Native`.
* 		Then, it serializes them, bundling the modules into one or more bundles.
However, since the project uses `NX`, its structure differs from the basic one, resulting in distinct configuration files at various project levels.
Let's take a look at the repository structure within `NX`:

```
monorepo-name/
├── apps/
│   └── mobile/
│		├── app.json
│		├── metro.config.js
│		├── package.json
│    	├── project.json 
│   └── mobile-e2e/
├── libs/ 
│   └── shared-ui-layout/
│       ├── src/
│       │   └── index.ts
│       ├── .babelrc
│       ├── jest.config.js
│       ├── project.json
│       ├── README.md
│       ├── test-setup.ts
│       ├── tsconfig.json
│       ├── tsconfig.lib.json
│       └── tsconfig.spec.json
├── tools/
├── babel.config.json
├── jest.config.js
├── jest.preset.js
├── nx.json
├── package-lock.json
├── package.json
└── tsconfig.base.json

```
### Configurations Adjustment

In this project structure, each application has its set of configuration files, such as `metro.config.js`, `package.json`, and others. However, besides these configurations, there are also files in the repository's root directory that need to be taken into account during the build process. `NX` itself provides the _withNxMetro_ function, which allows merging `NX` configurations and user-defined ones into a single configuration. As a result, to achieve the necessary configuration in the `metro.config.js` file, we will make the following changes:
* 		We will begin by merging the default and user-defined configurations using the _mergeConfig_ function, following the guidelines of the `React Native` guide.
* 		Then, we will pass the result of this merge to the _withNxMetro_ function to combine it with the `NX` configuration.

```
const { withNxMetro } = require('@nx/react-native')
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config')
const exclusionList = require('metro-config/src/defaults/exclusionList')

const defaultConfig = getDefaultConfig(__dirname)
const { assetExts, sourceExts } = defaultConfig.resolver

/**
 * Metro configuration
 * https://facebook.github.io/metro/docs/configuration
 *
 * @type {import('metro-config').MetroConfig}
 */
const customConfig = {
  transformer: {
    babelTransformerPath: require.resolve('react-native-svg-transformer'),
  },
  resolver: {
    assetExts: assetExts.filter(ext => ext !== 'svg'),
    sourceExts: [...sourceExts, 'svg'],
    blockList: exclusionList([/^(?!.*node_modules).*\/dist\/.*/]),
    unstable_enableSymlinks: true,
    unstable_enablePackageExports: true,
  },
}

module.exports = withNxMetro(mergeConfig(defaultConfig, customConfig), {
  // Change this to true to see debugging info.
  // Useful if you have issues resolving modules
  debug: false,
  // all the file extensions used for imports other than 'ts', 'tsx', 'js', 'jsx', 'json'
  extensions: [],
  // Specify folders to watch, in addition to Nx defaults (workspace libraries and node_modules)
  watchFolders: [],
})
```
After such an upgrade, the project's `metro.config.js` will launch, and we'll see the initial app screen that we've been longing to see again. 🎉<br>

Final library versions:

```
"nx": "16.6.0",
"react-native": "0.72.3",
```

#### To sum up:
1. Follow the update guide at this [link](https://react-native-community.github.io/upgrade-helper/).
2. Upgrade library versions with `NX`.
3. Modify the `metro.config.js` file.

### Conclusion
I trust that this article provided a solution for individuals who faced this issue or are still utilizing outdated versions of `NX` and `React Native`.

[Translation of this article into Russian](https://dev.to/irinaivanovaalex/kak-ia-apghrieidila-proiekt-s-nx-na-posliedniuiu-viersiiu-0723-react-native-1km)