Как я апгрейдила проект с NX на последнюю версию 0.72.3 React Native
Tags: reactnative, nx
Published: 2023-08-25 11:05:55

Обновление `react-native` связано с большой болью у разработчиков, часто это занимает много рабочего времени и сил, особенно если проект использует большое количество библиотек или имеет нестандартную структуру. 

В этой статье я расскажу с чем мне пришлось столкнуться в проекте c монорепозиторием `NX` и что мне помогло решить эту проблему.

### Переход по гайду на новую версию React Native

Изначальные версии зависимостей:

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

Имея монорепозиторий нужно было перейти на последний `React Native`. При переезде на 0.72.3 версию по [React Native Helper](https://react-native-community.github.io/upgrade-helper/) проекты собираются, но в итоге  мы получаем ошибку:

```
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)

Проблема в том, что `Metro` собрал проект не совсем корректно, сборка через `Metro` проходит в несколько этапов:

1. `Metro` строит граф всех модулей, 
2. транспилирует модуля в формат, понятный React Native 
3. и сериализует их, объединяя модули для создания одного или нескольких bundle

Но так как проект использует `NX`, его структура отличается от базовой и мы имеем разные конфигурационные файлы на разных уровнях проекта. 

Рассмотрим структуру репозитория на `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

```
### Изменение конфига 
В данной структуре проекта каждое приложение имеет свой набор конфигурационных файлов, таких как `metro.config.js`, `package.json` и другие. Однако помимо этих конфигов, существуют также файлы в корневой директории репозитория, которые также необходимо учесть в процессе сборки. У самого `NX` есть _withNxMetro_ - эта функция, которая позволяет объединить конфиги `NX` и пользовательские в одну. В итоге, для достижения необходимого конфига в файле `metro.config.js`, мы внесем следующие изменения:

1. Начнем со слияния дефолтных и пользовательских конфигов с помощью функции _mergeConfig_, следуя рекомендациям из гайда `React Native`.
2. Затем, результат этого слияния передадим в функцию _withNxMetro_ для объединения с конфигом `NX`.

```
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: [],
})
```
После такого апгрейда `metro.config.js` проект запуститься и мы увидим первый экран приложения, который мы так долго хотели увидеть снова. 🎉<br>

Финальные весии библиотек:
```
"nx": "16.6.0",
"react-native": "0.72.3",
```

#### Подытожим:
1. Апдейтимся по [гайду](https://react-native-community.github.io/upgrade-helper/)
2. Апгрейдим версии библиотек с `NX`
3. Меняем `metro.config.js` 

### Заключение 
Надеюсь, что это статья помогла решить проблему тех, кто столкнулся с такой ошибкой или все еще сидит на старых версиях `NX` и `React Native`.<br>