マルチフロントエンドのAmplifyの環境切り替え自動化とCI/CD（Expo＋EAS Build）の設定

# 背景

- Amplifyで作られたWEBアプリケーションが既にある
- ExpoでiOS/Android版アプリの開発を始める
- アプリのリポジトリではAmplifyのBackendは編集しないが、Amplifyの認証くらいは使いたい
- [amplify-js](https://github.com/aws-amplify/amplify-js)には `aws-exports.js`だけあればよいので、そのファイルだけもらえるようなAmplifyの自動環境切り替えを実現したい
    - フロントエンドのリポジトリでは `amplify/` フォルダを無視（.gitignoreしてエディタからも非表示）してしまいたい
- 自動化できた折りにはCI/CD（EAS　Build）でも使いたい

# 参考

この辺りを参考にしていく

- [Team environments - Multiple frontends - AWS Amplify Docs](https://docs.amplify.aws/cli/teams/multi-frontend/)
- [Advanced workflows - Headless mode for CI/CD - AWS Amplify Docs #amplify-pull-sample-script](https://docs.amplify.aws/cli/usage/headless/#sample-script-3)

# 出来たもの

- [全ファイルをGistでDLできます](https://gist.github.com/goosys/3585da30df31e88b6eb00c161a450071)

## amplify-pullの自動化（CI/CD対応）

- AmplifyのProjectNameとAppIDを埋め込んでコミットしておく
- `amplify pull`の前に`amplify/`フォルダと`src/aws-exports.js`を削除
    - ※上書きされるだけなので削除の必要はないが念の為
- `amplify pull`の最後に聞かれる質問に自動でNoと答えるように設定 (`echo n |`)
    - ※Noと答えると`amplify/backend/`フォルダは削除される

```sh:bin/amplify-setup
#!/bin/bash
set -e
IFS='|'

AWS_PROFILE="your_aws_profile"
PROJECT_NAME="amplify_project_name"
APP_ID="amplify_app_id"

if [[ "${AWS_ACCESS_KEY_ID:+x}" && "${AWS_SECRET_ACCESS_KEY:+x}" ]]; then
  AWSCREDENTIALS="\"useProfile\":false,\
\"accessKeyId\":\"$AWS_ACCESS_KEY_ID\",\
\"secretAccessKey\":\"$AWS_SECRET_ACCESS_KEY\","
else
  AWSCREDENTIALS="\"useProfile\":true,\"profileName\":\"$AWS_PROFILE\","
fi

REACTCONFIG="{\
\"SourceDir\":\"src\",\
\"DistributionDir\":\"build\",\
\"BuildCommand\":\"npm run-script build\",\
\"StartCommand\":\"npm run-script start\"\
}"
AWSCLOUDFORMATIONCONFIG="{\
\"configLevel\":\"project\",\
$AWSCREDENTIALS\
\"region\":\"ap-northeast-1\"\
}"
AMPLIFY="{\
\"projectName\":\"$PROJECT_NAME\",\
\"appId\":\"$APP_ID\",\
\"envName\":\"$1\",\
\"defaultEditor\":\"code\"\
}"
FRONTEND="{\
\"frontend\":\"javascript\",\
\"framework\":\"react-native\",\
\"config\":$REACTCONFIG\
}"
PROVIDERS="{\
\"awscloudformation\":$AWSCLOUDFORMATIONCONFIG\
}"

rm -rf amplify src/aws-exports.js
echo n | amplify pull \
--amplify $AMPLIFY \
--frontend $FRONTEND \
--providers $PROVIDERS

# Thanks
# https://github.com/aws-amplify/amplify-cli/issues/5275#issuecomment-724069616
# https://github.com/aws-amplify/amplify-cli/issues/3292#issuecomment-788249445
# https://docs.amplify.aws/cli/usage/headless#amplify-pull-parameters
```

## EAS Buildの実行前フック

- EAS Buildの実行環境には`amplify`コマンドがないのでインストールする
- `eas build --profile`の値でAmplify環境を切り替える

```sh:bin/eas-build-pre-install
#!/bin/bash
set -e
IFS='|'

if which amplify >/dev/null; then
  :
else
  npm install --quiet -g @aws-amplify/cli
fi

if [[ $EAS_BUILD_PROFILE == "production" ]]; then
  ./bin/amplify-setup prd
else
  ./bin/amplify-setup stg
fi
```


## コマンドショートカットを追加

- Amplify環境切り替え系は `init:amplify:*` に設定
- EAS Buildの実行前フックは `eas-build-pre-install` に設定

```json:package.json
{
  "main": "index.js",
  "scripts": {
    "start": "expo start --dev-client",
    "android": "expo run:android --device",
    "ios": "expo run:ios --device",
    "init:clean": "rm -rf src/* amplify .expo/* android ios",
    "init:amplify": "yarn init:amplify:test",
    "init:amplify:test": "bin/amplify-setup test",
    "init:amplify:stg": "bin/amplify-setup stg",
    "init:amplify:prd": "bin/amplify-setup prd",
    "build:ios:stg": "eas build -p ios --profile preview",
    "build:android:stg": "eas build -p android --profile preview",
    "build:ios:prd": "eas build -p ios --profile production",
    "build:android:prd": "eas build -p android --profile production",
    "eas-build-pre-install": "./bin/eas-build-pre-install"
  }
}
```

## .gitignore

- `amplify/`フォルダごとGit管理から外す

```.gitignore
amplify/
aws-exports.js
```

# 使い方

- 構築済みのAmplify環境を切り替えたい場合は、以下のように実行する
  - `yarn init:amplify:test`
  - `yarn init:amplify:stg`
- 実行するとこんな感じになる
  - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64098/74c6dc62-652a-f15a-4af2-e73d3a21037b.png)

# GraphQL(Amplify API)も使いたい場合

このままでもAppSyncが使えるのでよいが、AmplifyがビルドしてくれるGraphQLも使いたい場合も少し変えれば対応できそう

- `.graphqlconfig.yml`をBackend用のAmplifyのリポジトリからコピーしてくる
  - あるいはこのリポジトリで一度Backend有りでpullしたあとに `amplify codegen add` を実行し生成する
- `amplify-setup`を以下のように修正する

```diff_shell:bin/amplify-setup
- rm -rf amplify src/aws-exports.js
+ rm -rf amplify src/aws-exports.js src/graphql src/API.ts
- echo n | amplify pull \
+ echo y | amplify pull \
  --amplify $AMPLIFY \
  --frontend $FRONTEND \
- --providers $PROVIDERS
+ --providers $PROVIDERS && \
+ amplify codegen
+ rm -rf amplify/backend
```

- 実行するとこんな感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64098/eac5d371-a576-4a86-0c1a-2b11b5ae24a9.png)

# EAS Build

EAS Buildでも動作確認

- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64098/f1b160d0-87ca-b457-39f6-015d3be3d24b.png)
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64098/22c1e3a1-5fe1-8668-cd75-82b8346209ab.png)
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64098/5d5023ab-0725-06b7-1175-0b9ed4de0d1f.png)

# おわり

これで、
ローカル開発時の環境切り替えも１コマンドで出来て、Expoでのビルドからのストアリリースまでも１コマンドで出来るようになってよかった

# 関連記事

https://qiita.com/goosys/items/7227052f6899bc0e6fc2#%E6%9C%80%E6%96%B0%E7%89%88sdk43%E3%81%A7%E3%81%AE%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%83%95%E3%83%AD%E3%83%BC