Vite+React+Amplifyの初期設定方法！

# この記事の目的

**爆速のビルドツール[Vite](https://ja.vitejs.dev/)を試してみたい！**
この記事では、普段自分が使っているReact+Amplifyの構成にてプロジェクトを開始する場合の手順を、個人的なメモとしてまとめました。

# ソフトウェアのバージョン
主なソフトウェアのバージョンを記載します。

* node v18.9.0
* TypeScript 4.6.4
* Vite 3.1.0
* React 18.2.0

# 先にまとめ
AmplifyとReactを連携する場合に、Amplify公式ページではcreate-react-appを使う方法がガイドされています。Viteを使う場合も概ねこの方法が使えますが、そのままでは動かない箇所がいくつかあるため、エラー対応が必要となります。このセクションでは、エラー内容と対応の概略を記載します。具体的な手順は、「開発手順」のセクションで詳細に記載しています。

## エラー発生箇所１ amplify pull

```
✖ There was an error initializing your environment.
Failed to pull the backend.
🛑 Must use import to load ES Module: /Users/xxxxxxxx/my_first_vite/src/aws-exports.js
require() of ES modules is not supported.
require() of /Users/xxxxxxxx/my_first_vite/src/aws-exports.js from /snapshot/repo/build/node_modules/amplify-frontend-javascript/lib/frontend-config-creator.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.

```
以下の対応をおこないます。

* aws-exports.js を aws-exports.ts にリネーム
* package.json から、"type": "module" の行を削除

**Additional Info.** (2022-10-13追記）
[AWS AmplifyのDiscordコミュニティー](https://discord.com/channels/705853757799399426/705909048238800916/1029748307783843862)から以下のコメントをいただきました。(AmplifyCLIのバージョンアップで一部解決されるようです）
> For what it's worth, the ESM issue (where we have to remove "type": "module") is fixed with the latest version version of the CLI, 10.2.3

## エラー発生箇所２ yarn dev
```
Uncaught ReferenceError: global is not defined
```
以下の対応を行います。
index.htmlの変更

## エラー発生箇所３ amplify publish
```
2: import { ProviderError } from "@aws-sdk/property-provider";
3: import { Buffer } from "buffer";
4: import { request } from "http";
            ^
5: /**
6:  * @internal
error during build:
Error: 'request' is not exported by __vite-browser-external, imported by node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/credential-provider-imds/dist/es/remoteProvider/httpRequest.js
```

vite.config.tsを修正します。

# 開発手順

前提として、node, AmplifyCLI, Viteのインストールは済んでいるものとして、プロジェクト作成から記載します。

* Viteを用いてReactプロジェクトを作成する
* Amplifyのプロジェクトを作成する
* アプリの初期設定をする
* データモデル連携をする
* Amplify CLIを使ってホスティングする

## Viteを用いてReactプロジェクトを作成する
コマンドは下記のようになります。
```zsh
yarn create vite my_first_vite --template react-ts
```
"my_first_vite"というのがプロジェクト名になりますので、任意の値を指定してください。
--template react-tsでReactのTypeScriptテンプレートを適用しています。
なお、このコマンドを説明している公式サイト[[1]](https://vitejs.dev/guide/#scaffolding-your-first-vite-project)もあわせてお読みください。

## Amplifyのプロジェクトを作成する
Amplifyのプロジェクトの作成方法は複数ありますが、ここではAmplifyStudioを用います。

### AWSマネジメントコンソールでプロジェクトを作成
まずは、AWSのマネジメントコンソールから、AWS Amplify（以下Amplifyと呼ぶ）を選択し、
下図のように画面右上から[New app]>[Build an app]を選択します。
![Screen Shot 2022-10-12 at 9.23.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/8af4ad70-3c92-a54c-c57c-94b0f0907892.png)

次に、以下の画面でApp nameを入力し、[Confirm deployment]を押下します。
ここでは、my_first_viteとしていますが、任意で構いません。
![Screen Shot 2022-10-12 at 9.23.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/b46f1aa5-db10-9282-2418-27f9f5d285a3.png)

下図はデプロイ中の待機画面です。（5〜6分はかかります。）
![Screen Shot 2022-10-12 at 9.24.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/437ebb17-7097-f6cf-a228-44672469bfee.png)

画面が以下のように遷移したら、[Launch Studio]を押下し、Amplify Studioを立ち上げます。
![Screen Shot 2022-10-12 at 9.31.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/9e7cdec1-158b-4af7-50f6-5e259a892a6d.png)

### Amplify Studio起動後の作業について
Amplify Studioではさまざまなバックエンドのリソースの設定が可能です。
これを仔細に紹介するのが本記事の目的ではないので、ここでは簡単なデータモデルの定義だけを行います。
その他に、Figmaと連携してUIを生成する、Cognitoを用いて認証を組み込むといったことができますが、別記事[[2]](https://qiita.com/akiraabe/items/55f28fe4f721f74eb992)やAWSのチュートリアル[[3]](https://aws.amazon.com/jp/blogs/news/aws-amplify-studio-figma-to-fullstack-react-app-with-minimal-programming/)を参照ください。

#### データモデルの定義
以下のように、データモデルの定義を行います。終わったら[Save and Deploy]を押下します。
![Screen Shot 2022-10-12 at 9.48.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/bb3bd60b-3a36-7bda-a480-7a5f059c4a29.png)

デプロイ待ちの画面です。このタイミングでCloudFormationによりAppSyncやDynamoDBが作られますので、この処理は相応に時間がかかります。（10分くらいはかかるかもしれません）
![Screen Shot 2022-10-12 at 9.48.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/acb6f0b0-1d26-e570-b101-6603030e9d05.png)


デプロイが完了（成功）すると以下のような画面に遷移します。（[Done]を押すと画面が閉じます）

![Screen Shot 2022-10-12 at 10.03.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/9cd0154c-96f0-7ddd-aee5-77eb57db9d69.png)

ここで、②Update your app codeでプログラム言語、model、operationなどを選択すると、ソースコードの例がガイドされます。（簡易的な内容なので、詳細はドキュメント[[4]](https://docs.amplify.aws/lib/datastore/getting-started/q/platform/js/)を確認した方が良いです）

### Amplifyの資材をローカルにPullする

yarn create で作成したReactプロジェクトで、以下のように amplify pull コマンドを実行します。
（ここでは、VSCodeのターミナルで作業しています）

エラーが発生しますが、対処方法は後述します。

```
 amplify pull
? Select the authentication method you want to use: AWS profile

For more information on AWS Profiles, see:
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html

? Please choose the profile you want to use default
? Which app are you working on? xxxxxxxxxxxxxx                              
Backend environment 'staging' found. Initializing...
? Choose your default editor: Visual Studio Code
? Choose the type of app that you're building javascript
Please tell us about your project
? What javascript framework are you using react
? Source Directory Path:  src
? Distribution Directory Path: dist *** ここはデフォルトだとbuildですが明示的に変更しています ***
? Build Command:  npm run-script build
? Start Command: npm run-script start
✅ GraphQL schema compiled successfully.

Edit your schema at /Users/xxxxxxxx/my_first_vite/amplify/backend/api/myfirstvite/schema.graphql or place .graphql files in a directory at /Users/xxxxxxxx/my_first_vite/amplify/backend/api/myfirstvite/schema
Successfully generated models. Generated models can be found in /Users/xxxxxxxx/my_first_vite/src
? Do you plan on modifying this backend? Yes
⠙ Fetching updates to backend environment: staging from the cloud.✅ GraphQL schema compiled successfully.

Edit your schema at /Users/xxxxxxxx/my_first_vite/amplify/backend/api/myfirstvite/schema.graphql or place .graphql files in a directory at /Users/xxxxxxxx/my_first_vite/amplify/backend/api/myfirstvite/schema
✔ Successfully pulled backend environment staging from the cloud.
✖ There was an error initializing your environment.
Failed to pull the backend.
🛑 Must use import to load ES Module: /Users/xxxxxxxx/my_first_vite/src/aws-exports.js
require() of ES modules is not supported.
require() of /Users/xxxxxxxx/my_first_vite/src/aws-exports.js from /snapshot/repo/build/node_modules/amplify-frontend-javascript/lib/frontend-config-creator.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename aws-exports.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /Users/xxxxxxxx/my_first_vite/package.json.

```

:::note warn
エラーが発生しますので、メッセージに従って対応します。
:::

*  aws-exports.js を aws-exports.ts　にリネームします。（ただし、 amplify pull の都度、aws-eports.jsが作られるので、その都度リネームする必要があります）
*  package.json から、"type": "module" の行を削除します。


```diff:package.json
{
  "name": "my_first_vite",
  "private": true,
  "version": "0.0.0",
-  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@types/react": "^18.0.17",
    "@types/react-dom": "^18.0.6",
    "@vitejs/plugin-react": "^2.1.0",
    "typescript": "^4.6.4",
    "vite": "^3.1.0"
  }
}
```

上記の修正を加えた後に、amplify pull を再実行します。

## アプリの初期設定をする

このタイミングで一旦アプリを立ち上げてみます。

```zsh
# 依存モジュールのインストール
yarn install

# 開発サーバーの起動
yarn dev
```
この時点でのアプリは以下のようになっています。

![Screen Shot 2022-10-12 at 12.22.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/58329ef4-05a9-baa9-4715-081782c29970.png)


Amplifyを利用するようにアプリを変更します。

変更するファイルは以下の通りです。(プロジェクトルートを起点として記載)

* package.json
* src/index.css
* src/main.tsx
* src/App.tsx

package.jsonは差分を記載します。(変更したら、yarn installを実行してください)
```diff:package.json
  "dependencies": {
+    "@aws-amplify/ui-react": "^3.5.4",
+    "aws-amplify": "^4.3.36",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
```

index.cssは以下の内容で更新します。
```css:src/index.css
@import url('https://fonts.googleapis.com/css2?family=Inter:slnt,wght@-10..0,100..900&display=swap');
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

```

main.tsxは差分を記載します。
```diff_tsx:src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
+import { AmplifyProvider } from '@aws-amplify/ui-react';
+import { Amplify } from 'aws-amplify';
import App from './App'
import './index.css'
+import config from './aws-exports';

+Amplify.configure(config);

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
-  <React.StrictMode>
+  <AmplifyProvider
     <App />
+  </AmplifyProvider>
-  </React.StrictMode>
)
```


App.tsx は以下の内容で更新します。
```tsx:App.txs
import type { FC } from 'react';
import { Amplify } from 'aws-amplify';
// eslint-disable-next-line import/extensions
import '@aws-amplify/ui-react/styles.css';
import awsExports from './aws-exports';

Amplify.configure(awsExports);

const App: FC = () => {
  return (
    <h1>
      Hello Amplify+Vite!
    </h1>
  );
}

export default App;
```
:::note warn
しかし、この状態で開発サーバーを起動（yarn dev）すると、以下のエラーが出ます。
:::

![Screen Shot 2022-10-12 at 12.56.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/b0311aee-404f-f9bf-5823-7b53c9e7da64.png)


これは以下のようにして対処します。（差分を記載します）

```diff:index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React + TS</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
+    <script>
+      window.global = window;
+      window.process = {
+        env: { DEBUG: undefined },
+      };
+      var exports = {};
+    </script>
  </body>
</html>
```

これまでの結果として以下のような初期画面がブラウザーに表示されます。
![Screen Shot 2022-10-12 at 13.44.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/753741fa-e580-6d69-4051-a867d6969c73.png)

### この時点のソースコード
https://github.com/akiraabe/my_first_vite/tree/Initial

## データモデル連携をする

データモデルとの連携は手順を記載するのが手間なので、ソースコードを参照ください。

https://github.com/akiraabe/my_first_vite/tree/UsingAmplify
データの登録と一覧表示だけをおこなっています。


## Amplify CLIを使ってホスティングする
以下の手順でホスティングします。（AWSマネジメントコンソールでなく、AmplifyCLIをつかうのは、CloudFrontにWAFを設置したいからです。）

* amplify add hosting
* amplify publish

### amplify add hosting

以下のコマンドを実行します。

```zsh
amplify add hosting
✔ Select the plugin module to execute · Amazon CloudFront and S3
? Select the environment setup: PROD (S3 with CloudFront using HTTPS)
? hosting bucket name myfirstvite-xxxxxxxxxxxx-hostingbucket
Static webhosting is disabled for the hosting bucket when CloudFront Distribution is enabled.

You can now publish your app using the following command:
Command: amplify publish
```
### amplify publish
以下のコマンドを実行します。

:::note warn
ただし、これは失敗するので、後ほど修正を行います。
:::

```zsh
amplify publish

'request' is not exported by __vite-browser-external, imported by node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/credential-provider-imds/dist/es/remoteProvider/httpRequest.js
file: /Users/xxxxxxxxmy_first_vite/node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/credential-provider-imds/dist/es/remoteProvider/httpRequest.js:4:9
2: import { ProviderError } from "@aws-sdk/property-provider";
3: import { Buffer } from "buffer";
4: import { request } from "http";
            ^
5: /**
6:  * @internal
error during build:
Error: 'request' is not exported by __vite-browser-external, imported by node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/credential-provider-imds/dist/es/remoteProvider/httpRequest.js
```

#### エラー対応
vite.config.ts に以下の修正を加えます。その後に、amplify publishを再実行します。

```diff_ts:vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
+  resolve: {
+    alias: [
+      { find: './runtimeConfig', replacement: './runtimeConfig.browser' },
+      { find: '@', replacement: '/src' },
+    ],
+  },
  plugins: [react()]
})

```

# 感想
Viteはローカルの開発サーバーの起動も爆速（今回はコードベースが大して大きくないですが）なので使っていて快適です。
初期設定で多少の苦労はしますが、割に合うと感じました！

## 脚注
[[1] Scaffolding your first vite project](https://vitejs.dev/guide/#scaffolding-your-first-vite-project)
[[2] AmplifyStudio & Figma](https://qiita.com/akiraabe/items/55f28fe4f721f74eb992)
[[3] AWS AmplifyStudio Tutorial Blog](https://aws.amazon.com/jp/blogs/news/aws-amplify-studio-figma-to-fullstack-react-app-with-minimal-programming/)
[[4] Amplify DataStore Docs](https://docs.amplify.aws/lib/datastore/getting-started/q/platform/js/)