Amplify CLIを使って、Amplifyプロジェクトを作成する方法

はいさい！ちゅらデータぬオースティンやいびーん！

# 概要
Amplify CLIを使って、ローカルでAmplifyのプロジェクトと開発環境を設置する方法を紹介します。

## 背景
### Amplifyとは
GCPのFirebaseと似て、AWSの各機能を一つにまとめるために作られたサービスです。

### なぜCLIを使うのか
Amplifyにはコンソールがありますが、正式ドキュメントの多くは、コンソールによる操作より、CLIによる操作を元に用意されています。

なので、CLIの使い方からAmplifyに入っていった方が後々助かると、筆者は考えます！

# Amplify CLIをインストールする
まずは、CLIをインストールしておきます。

https://docs.amplify.aws/cli/start/install/

### npmでグローバル・インストールする
```
npm install -g @aws-amplify/cli
```

### curlでインストール
個人的にはnpmのグローバルインストールを避けたいのでこちらの方がおすすめです。
```
curl -sL https://aws-amplify.github.io/amplify-cli/install | bash && $SHELL
```

# Amplify CLIの設定をする
以下のコマンドを実行すればCLIで初期設定ができます。
```
amplify configure
```
すると、AWSコンソールがブラウザで開かれ、ログインすれば、CLIで`Enter`キーを押せば次に進めます。
![スクリーンショット 2022-07-29 16.46.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/66354edf-dec8-ad08-9abc-a2c60f4e1f38.png)
すると、次にAmplify CLIはデフォルトの地域設定を求めます。
![スクリーンショット 2022-07-29 16.43.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/10bfffa6-99bc-2202-89a1-48fde75febe6.png)
そして次に、Amplify CLIがAWSサービスの設定を管理するためにIAMアカウントを作成してくれます。何も入力しなければ初期値の名前になりますが、任意のIAMアカウント名を設定することもできます。
　![スクリーンショット 2022-07-29 16.49.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/018ddf41-ae37-ed3b-9214-0aeec2ece36b.png)
`Enter`を押すと、またAWSコンソールに遷移します。今回は、IAM管理コンソールでAmplify用のIAMユーザーを作っていきます。

全てはデフォルトの設定で問題ありません。
![スクリーンショット 2022-07-29 16.50.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/e551a931-f454-cd87-e3d4-0ad0fe7e37f0.png)
こちらもデフォルトの設定で問題ありません。
![スクリーンショット 2022-07-29 16.51.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/2b079721-e35a-b16e-4e73-0465e4763322.png)
内容に問題なければユーザーを作成します。
![スクリーンショット 2022-07-29 16.54.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/3876714b-4e63-0d68-a722-cbcda71cfb8c.png)
すると`accessIdKey`が出ますが、これをAmplify CLIに入力します。
![スクリーンショット 2022-07-29 16.55.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/74ddf47a-805c-d0d4-f027-c8043825662e.png)
`secretAccessKey`も入力します。
![スクリーンショット 2022-07-29 16.56.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/88f59342-cb72-2422-3b21-cac530831e81.png)
そしてAWSの`~/.aws/`にこのIAMユーザーの設定を保存するためのプロファイル名を求めます。
![スクリーンショット 2022-07-29 16.57.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/f4eb66a4-4f5c-c484-a8b9-23f69b9877d2.png)
ここまでくれば、Amplify CLIを使って新しいプロジェクトを立ち上げる準備ができているはず！

# 新しいAmplifyプロジェクトを立ち上げる
CLIで新規プロジェクトを作成するには、以下のコマンドを実行します。
```
amplify init
```
すると、プロジェクト名を入力するプロンプトが出ます。ここは任意の名前を入力します。
ハイフンなどのシンボルが入力できないのでご注意ください。
![スクリーンショット 2022-07-29 17.03.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/8fe917ae-dba2-30d3-1887-37964e5ace86.png)
次の画面ではデフォルトの設定で進めるのか、それとも詳細に設定するのかを決めます。

今回は`n`で詳細を決めていきます。
![スクリーンショット 2022-07-29 17.05.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/6c54bd33-fcd6-677c-b246-f02859ff95f8.png)
`environment`とは環境のことで、同じAmplifyのプロジェクトの中で、開発環境、試験環境、本番環境それぞれに作れます。
今回は`dev`にしておきます。

次は、開発において使っているIDEを設定することができます。
![スクリーンショット 2022-07-29 17.06.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/c0deb2b3-9986-fb27-64f7-f097560371c6.png)
VSCodeを選択すると、このような設定ファイルが.vscodeのダイレクトリに出力されます。
![スクリーンショット 2022-07-29 17.08.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/48c89df3-c0dd-c6d2-d48c-444db4ededd1.png)
次の設置は、デフォルトにしましたが、解説します。
![スクリーンショット 2022-07-29 17.09.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/1cd6a3fe-41d2-8b40-5d30-e32fd70762e5.png)
|英語|意味| 選択肢 |
| --- | --- | --- |
|Choose the type of app that you're building|どのようなアプリを作るか| Android, Flutter, iOS, javascriptから選択できます。基本的にJavaScriptでいいです。 |
|What javascript framework are you using|どのようなフレームワークを使うか|React, Vue, Angularなど、それらのフレームワークを選択すると雛形のようなフロントエンドを`src`に入れてくれます。基本的に`none`にして、自分で必要なパッケージをインストールしていくことを推奨します。`Next.js`等であれば、雛形を使った方がいいでしょう。|
|Source Directory Path|フロントエンドのソースコードの保存先|`src`または`lib`でいいかと思います。|
|Distribution Directory Path|ビルド成果物の保存先|`dist`でいいでしょう。|
|Build Command|フロントエンドをビルドするためのコマンド。これは`amplify publish`を実行したときに使われます。|自分は`yarn`を使うので、`yarn build`で`package.json`の`scripts`に入れる`build`のコマンドを実行するようにします。|

最後に、プロジェクトを作成するためにどのAWS CLIのアカウントを使えばいいかを指定します。先ほど`amplify configure`で設定したアカウントを使いましょう。
![スクリーンショット 2022-07-29 17.19.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/4d33cc7a-0e3e-4b26-8f1f-6e57ef672939.png)
AWSサービスを用意するのに時間がかかりますので待ちますが、その間にフロントエンドのセットアップをしましょう。
![スクリーンショット 2022-07-29 17.20.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/2271f8cd-c7dd-bbad-8859-0d13e3ed3de4.png)

# フロントエンドの設定をします。
`amplify init`でAmplifyのバックエンドを設置しましたが、フロントエンドの環境構築もしましょう。

### `yarn init`で`package.json`を作成する
`yarn`で`package.json`を作るために以下のコマンドを実行します。
```
yarn init
```
すると、`package.json`は作成されます。

### webpackの設定ファイルを作る
次に、Webpackの必要なnpmパッケージをインストールします。

筆者はTypeScriptを必ず使う人なので、TypeScriptがビルドできるような筆者の推奨設定を共有します。
```
yarn add -D webpack webpack-cli webpack-dev-server webpack-manifest-plugin typescript　ts-loader　babel-loader　file-loader html-webpack-plugin mini-css-extract-plugin @babel/preset-env　@babel/core
```
そして、開発用と本番用の設定ファイルを作成します。
```javascript:webpack.prod.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const webpack = require("webpack");
const { WebpackManifestPlugin } = require("webpack-manifest-plugin");

module.exports = {
  entry: "./src/index.ts",
  mode: "production",
  optimization: {
    splitChunks: {
      chunks: "all",
    },
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-env"],
            },
          },
          "ts-loader",
        ],
        exclude: /node_modules/,
      },
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env"],
          },
        },
      },
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
      {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: "file-loader",
          },
        ],
      },
    ],
  },
  resolve: {
    alias: {
      "@web-components": path.resolve(__dirname, "src/web-components/"),
      "@firebase-logic": path.resolve(__dirname, "src/firebase.ts"),
    },
    extensions: [".tsx", ".ts", ".js"],
  },
  output: {
    filename: "[name].[fullhash].js",
    path: path.resolve(__dirname, "dist"),
    publicPath: "/",
    clean: true,
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "public", "index.html"),
    }),
    new WebpackManifestPlugin({ fileName: "public-manifest.json", filter: (file) => file.name.includes(".js") }),
    new MiniCssExtractPlugin({ filename: (data) => `${data.chunk.name}.${data.hash}.css` }),
    new webpack.EnvironmentPlugin({
      NODE_ENV: "production",
      FRONTEND_URI: "https://pace-coffee.web.app/",
    }),
  ],
};
```
そして、ローカルで開発用サーバーを動かすためのWebpack設定は以下のようです。
```javascript:webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const fs = require("fs");
const webpack = require("webpack");
const { WebpackManifestPlugin } = require("webpack-manifest-plugin");

const port = 9001;

module.exports = {
  entry: { main: "./src/index.ts" },
  mode: "development",
  devtool: "inline-source-map",
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: "ts-loader",
        exclude: /node_modules/,
      },
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env"],
          },
        },
      },
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: "file-loader",
          },
        ],
      },
    ],
  },
  resolve: {
    alias: {
      "@web-components": path.resolve(__dirname, "src/web-components/"),
      "@firebase-logic": path.resolve(__dirname, "src/firebase.ts"),
    },
    extensions: [".tsx", ".ts", ".js"],
  },
  devServer: {
    static: {
      directory: path.join(__dirname, "public"),
    },
    compress: true,
    port,
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist"),
    publicPath: "/",
  },
  plugins: [
    new WebpackManifestPlugin({ fileName: "public-manifest.json" }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "public", "index.html"),
      chunks: ["main"],
    }),
    new webpack.EnvironmentPlugin({
      NODE_ENV: "development",
      FRONTEND_URI: `https://localhost:${port}/`,
    }),
  ],
};
```
### TypeScriptの設定
`tsconfig`ファイルを設定して以下のような推奨設定を入れます。
```json:tsconfig.json
{
  "compilerOptions": {
    "target": "ES6",
    "allowJs": true,
    "strict": true,
    "sourceMap": true,
    "forceConsistentCasingInFileNames": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "useDefineForClassFields": false,
    "module": "esnext",
    "moduleResolution": "node",
    "jsx": "preserve",
    "incremental": true,
    "outDir": "./dist/",
    "baseUrl": "./",
    "paths": {
      "@web-components/*": ["src/web-components/*"],
      "@firebase-logic": ["src/firebase.ts"]
    },
    "allowSyntheticDefaultImports": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}
```
### `package.json`に`script`を追加する
次は、`amplify init`で設定したビルドコマンドとスタートコマンドを`package.json`に設定します。
```json:package.json
{
  "scripts": {
    "build": "webpack --config webpack.prod.config.js",
    "start": "webpack serve",
  },
  "name": "amplify-austin",
  "version": "1.0.0",
  "main": "src/index.ts",
  "author": "Austin Mayer",
  "license": "MIT",
  "devDependencies": {
    "@babel/core": "^7.18.9",
    "@babel/preset-env": "^7.18.9",
    "babel-loader": "^8.2.5",
    "css-loader": "^6.7.1",
    "file-loader": "^6.2.0",
    "html-webpack-plugin": "^5.5.0",
    "mini-css-extract-plugin": "^2.6.1",
    "ts-loader": "^9.3.1",
    "typescript": "^4.7.4",
    "webpack": "^5.74.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.9.3",
    "webpack-manifest-plugin": "^5.0.0"
  }
}
```

`src`に`index.ts`を作って、また`public`というフォルダを作成して、そこにHTMLテンプレートの`index.html`を入れれば、ビルドできます！
```typescript:src/index.ts
console.log("Hello Amplify!");
```
```html:public/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Amplify App</title>
</head>
<body>
 <your-element></your-element>
</body>
</html>
```

# プロジェクトをアップロードしてデプロイしてみる
ここまでで基本的な設定と立ち上げが終わっているので、ローカルで編集したフロントエンドとバックエンド（今はまだない）コードをAWS側にプッシュする方法を紹介します。
## バックエンドの変更のみをプッシュする`amplify push`
以下のコマンドでバックエンドの変更をプッシュすることができます。だだし、今は何も変更していませんので、何もしません。

API、Lambda関数などを追加すると、ローカルのソースコードをプッシュすることができて便利です。
```
amplify push
```
このような画面になるはずです。
![スクリーンショット 2022-07-29 17.39.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/a2b5ab40-3d57-6cde-78d1-249f4b79d730.png)
このコマンドはバックエンドのみをプッシュします。

## バックエンドとフロントエンドをプッシュする
フロントエンドをデプロイするためには、Hostingサービスを追加する必要があります。以下のコマンドを実行して追加します。
```
amplify add hosting
```
`Hosting with Amplify Console (Managed hosting with custom domains, Continuous deployment)`を選択します。
![スクリーンショット 2022-07-29 17.47.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/9b29f126-92dd-6b96-209c-3b4a2677c373.png)
GitHubにプッシュしたら、自動でデプロイされるにするなど、CIの設定もできますが、今回は手動でしますので、`Manual deployment`を選択します。
![スクリーンショット 2022-07-29 17.48.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/2fc2be4f-c459-4d49-8e5a-021644cf883e.png)
こうすると、`amplify publish`を実行することができます。これを実行すると、バックエンドの変更に加えて、フロントエンドをビルドしてデプロイしてくれます。
```
amplify publish
```
まずバックエンドの変更をプッシュしてくれます。
![スクリーンショット 2022-07-29 17.50.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/8f95bf09-b579-dd99-4850-34312be24fc9.png)
そしてフロントエンドの`yarn build`を実行してデプロイしてくれます。
![スクリーンショット 2022-07-29 17.52.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/658be854-5573-4a48-3c94-99e13a8d9b3a.png)
デプロイ先のURLも教えてくれますが、開いてみると、ブラウザのconsoleに`Hello`が出ています。
![スクリーンショット 2022-07-29 17.53.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/84fa6c19-4bff-0ca8-6c3d-8fd7d250fb31.png)

# `aws-amplify`のフロントエンドライブラリをインストールしておく
AmplifyのJavaScript開発にはnpmパッケージとして`aws-amplify`が提供されています。
この中には、Amplifyのサービスに簡単にアクセスするソフトが入っているのでほぼほぼ必要になってきます。
```
yarn add aws-amplify
```
なので、最初からこれをプロジェクトに追加しておいた方がいいです。

https://docs.amplify.aws/lib/q/platform/js/

上記のリンクは`aws-amplify`についての正式ドキュメントです。よく書けていてわかりやすいものもあれば、そうでないものもあります。脱線ですが、筆者にはFirebaseの方が圧倒的に整理されている感じがします。

# まとめ
これまで、Amplifyでプロジェクトを開設する方法を紹介してきましたが、いかがでしょうか？

筆者は全体像を掴むのにかなり時間がかかりました。Firebaseとどうしても比較したくなるのですが、FirebaseはCLIではなく、Webコンソールで完結して、使い勝手がいいとつくづく思いました。

いずれ、FirebaseとAmplifyの短所・長所について詳しく解説したいところですが、とりあえずこれで本記事を終わりにします。

次回は、REST APIを作り、AmplifyのLambda関数にTypeScriptとExpressを導入する方法を解説します。