Expo + Nxでmonorepoな環境を作る

本記事は[React Native Advent Calendar 2020](https://qiita.com/advent-calendar/2020/react-native)の8日目の記事です

Expo, ReactNative初心者ですが、monorepoが必要になったのでExpo + Nxでmonorepoな環境を用意してみました。


## そもそもmonorepoと


自分は全然しらなかったですが、1つのリポジトリで複数のパッケージを管理することをmonorepoと言うらしいです。
気づいたらこういう流れになっているみたいですね。
(基本的にはPHPerなので知らなかった...)

リリースサイクルや、ロジックの共有もできるので便利かなと思います。

## Nxとはなにか？
[nrwl/nx](https://github.com/nrwl/nx)
monorepo用の拡張ツールです。
キャッシュのおかげでビルドが早かったり、色々と便利ですね。
(自分はそんなに使いこなせてないですが...)

## ExpoでNxを利用する
公式だと対応してないので,
ExpoでNxを利用するためには[JacopoPatroclo/nx-react-native-expo](https://github.com/JacopoPatroclo/nx-react-native-expo)が必要になります。

## monorepoを作ってみる。

実際にmonorepoを作ってみます。


### まずはNxのワークスペースを作成
まずはNxのワークスペースを作成します。
presetは `empty`を指定します。

```shell
$ npx create-nx-workspace --cli=nx --preset=empty

? Workspace name (e.g., org name)     polidog-monorepo-sample
? Use Nx Cloud? (It's free and doesn't require registration.) No
```


### nx-react-native-expoのnpmパッケージを追加する
ここでnx-react-native-expoのパッケージを追加します。

```shell
$ yarn add --dev nx-react-native-expo
```

## appを作成する


```sh
$ npx nx g nx-react-native-expo:app appA
```

ポイントなのは`x-react-native-expo:app`を指定している点かと思います。
これでexpoのプロジェクトが生成されています。

念の為にExpoのプロジェクトが生成されているかを確認してみた。

```sh
$ ls apps/app-a

drwxr-xr-x  20 polidog  staff  640 12  8 03:06 ./
drwxr-xr-x   4 polidog  staff  128 12  8 03:01 ../
-rw-r--r--   1 polidog  staff   98 12  8 03:01 .eslintrc.json
drwxr-xr-x   5 polidog  staff  160 12  8 03:09 .expo/
-rw-r--r--   1 polidog  staff  457 12  8 03:01 App.spec.tsx
-rw-r--r--   1 polidog  staff  524 12  8 03:01 App.tsx
-rw-r--r--   1 polidog  staff  478 12  8 03:01 app.json
drwxr-xr-x   5 polidog  staff  160 12  8 03:01 assets/
-rw-r--r--   1 polidog  staff  108 12  8 03:01 babel.config.js
-rw-r--r--   1 polidog  staff  132 12  8 03:01 index.js
-rw-r--r--   1 polidog  staff  325 12  8 03:01 jest.config.js
-rw-r--r--   1 polidog  staff  214 12  8 03:01 metro.config.js
drwxr-xr-x   3 polidog  staff   96 12  8 03:06 node_modules/
-rw-r--r--   1 polidog  staff  117 12  8 03:01 package.json
-rw-r--r--   1 polidog  staff   53 12  8 03:01 test-setup.d.ts
-rw-r--r--   1 polidog  staff  171 12  8 03:01 test-setup.js
-rw-r--r--   1 polidog  staff  207 12  8 03:01 test-setup.js.map
-rw-r--r--   1 polidog  staff  299 12  8 03:01 tsconfig.json
-rw-r--r--   1 polidog  staff  273 12  8 03:01 tsconfig.spec.json
-rw-r--r--   1 polidog  staff  287 12  8 03:01 webpack.config.js
```

## 起動してみる

```sh
$ yarn nx start app-a
```

特に問題もなく起動できてちょっとビビります。


## ライブラリを作成してみる

```sh
$ npx nx g nx-react-native-expo:lib data
```

このようにコマンドを実行すると`./libs/data`ディレクトリが作成されています。
ということで、適当にコードを用意して、appA側でimportさせたいと思います。

```ts
// libs/data/src/index.ts
export const now = () => Date.now()
```

続いてappA側を下記のように修正します。

```tsx
// apps/app-a/App.tsx

import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import  { now } from '@polidog-monorepo-sample/data'

export default function App() {
  const [nowTimestampe, setNowTimestamp] = React.useState(0.0)
  React.useEffect(() => {
    setNowTimestamp(now())
  }, [])
  
  return (
    <View style={styles.container}>
      <Text testID="heading">
        Timestamp: {nowTimestampe}
      </Text>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
```

ポイントとはimoprt文書くときに`@polidog-monorepo-sample/data`　って形になるところかと思います。


```ts
import  { now } from '@polidog-monorepo-sample/data'
```

## その他のコマンド

workspace.jsonを見るとわかりますが、他にも以下のコマンドが使えます

- bundle
- run-start
- run-ios
- run-android
- run-web
- publish

例:

```sh
$ yarn nx publish app-a
```

## まとめ
[JacopoPatroclo/nx-react-native-expo](https://github.com/JacopoPatroclo/nx-react-native-expo)を使うと非常に簡単にexpoでのmonorepoを実現出来ます。