【爆速】Vite+Vuejs+Amplify+AppSync(GraphQL)でリアルタイム掲示板作成+つまづいたところ

## Viteが凄すぎて感動した

[Vite](https://ja.vitejs.dev/)
あまりの速さに感動しました。なので何か作ってみようと思います。

# 掲示板アプリを爆速で作る

参考

https://qiita.com/G-awa/items/a5b2cc7017b1eceeb002

https://qiita.com/jre233kei/items/6521f9059edb045cfc1e

https://aws.amazon.com/jp/builders-flash/202008/amplify-crud-app/?awsf.filter-name=*all


## やること

- Vite + Vuejs + Vuetifyでシンプルなアプリを作る
- Appsyncでバックエンドを作る
- 結合する
- Amplifyでデプロイする

## できたもの
![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65643/22745403-89e4-bd0f-55e0-0571b044ee3f.gif)


## Vueのインストール

まずはyarnでViteアプリを作成

```
yarn create vite my-vue-app --template vue
```

フォルダを開いて`yarn dev`で動くか確認

```
cd my-vue-app
yarn
yarn dev
```
localhost:3000で動いたのが見れたと思います。


## AmplifyとAppsyncの準備

要 [Amplify CLI](https://docs.amplify.aws/cli/start/install/)

```
amplify init
? Enter a name for the project myvueapp
The following configuration will be applied:

Project information
| Name: myvueapp
| Environment: dev
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: vue
| Source Directory Path: src
| Distribution Directory Path: dist
| Build Command: npm run-script build
| Start Command: npm run-script serve
```

あらかじめVueのプロジェクトがあると、全て設定された状態で引き込まれました。すごい。
続いてAPIの登録

```
amplify add api
? Select from one of the below mentioned services: GraphQL
? Here is the GraphQL API that we will create. Select a setting to edit or continue Continue
? Choose a schema template: Blank Schema
✔ Do you want to edit the schema now? (Y/n) · yes
? Choose your default editor: Visual Studio Code
```

ブランクスキーマを選んで適当に追加します。

```amplify/backend/api/myvueapp/schema.graphql
type Post @model {
  id: ID!
  name: String!
  content: String!
}
```

終わったらデプロイ

```
amplify push  
```

無事デプロイできたら、Appsyncにアプリが追加されていると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65643/322c096b-1b1d-6793-3bc3-d53d739c3540.png)

試しにクエリを動かしたりして動作チェック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65643/ae34cd6c-e94d-0bf2-a054-c86c18d5655d.png)


## Vuejsに組み込む

CSSフレームワークに[Vuetify](https://next.vuetifyjs.com/en)
日付を表示したかったのでdayjsも追加しています。

```
vue add vuetify
yarn add aws-amplify aws-amplify-vue
yarn add dayjs
```

main.jsでインポート
Appsyncをデプロイしたときに作成されるエンドポイントなどや認証情報などがsrc/aws-exports.jsにまとめて入っているので、そちらもインポートします。

```src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify'
import { loadFonts } from './plugins/webfontloader'
import Amplify, * as AmplifyModules from "aws-amplify";
import { AmplifyPlugin } from "aws-amplify-vue";
import aws_exports from "./aws-exports";
Amplify.configure(aws_exports);

loadFonts()

createApp(App).use(vuetify, AmplifyPlugin, AmplifyModules).mount("#app");

```

実際に動く画面がわの実装。１ファイルに全部詰め込む形にしました。

```src/App.vue
<template>
  <v-app>
    <v-main>
      <v-container>
        <form>
          <v-text-field
            v-model="name"
            :counter="10"
            label="Name"
            required
          ></v-text-field>
          <v-textarea solo v-model="content" name="content" label="content"></v-textarea>
          <v-btn class="mr-4" @click="submit"> submit </v-btn>
          <v-btn @click="clear"> clear </v-btn>
        </form>
        <hr class="my-3">
        <h1>Comments</h1>
        <v-list three-line>
          <template v-for="(item, index) in items"  :key="index">
            <v-list-item>
              <v-list-item-content>
                <v-list-item-title>{{item.name}} <small class="text-grey"> {{item.date}}</small></v-list-item-title>
                <div class="pl-3 mt-2" v-html="item.content"></div>
              </v-list-item-content>
            </v-list-item>
            <v-divider />
          </template>
        </v-list>
      </v-container>
    </v-main>
  </v-app>
</template>

<script>
import dayjs from 'dayjs'
import { API, graphqlOperation } from "aws-amplify";
import { createPost } from "./graphql/mutations";
import { listPosts } from "./graphql/queries";
import { onCreatePost } from "./graphql/subscriptions";
dayjs.locale("ja");

export default {
  name: "App",

  data: () => ({
    name: "",
    content: "",
    items: undefined,
  }),
  mounted() {
    this.getData();
    this.registerSubscription();
  },
  methods: {
    submit() {
      this.postData();
    },
    clear() {
      this.name = ""
      this.content = ""
    },
    getData: async function () {
      // データ取得
      await API.graphql(graphqlOperation(listPosts))
        .then((response) => {
          // 改行をタグに変換
          const items = response.data.listPosts.items.map( val => {
            val.content = val.content.replace(/\r?\n/g, '<br>')
            val.date = dayjs(val.createdAt).format('YYYY/MM/DD')
            return val
          })
          // テーブル表示
          this.items = response.data.listPosts.items.sort((a,b)=> a.createdAt < b.createdAt ? 1 : -1)
        })
        .catch((error) => {
          // テーブルリセット
          this.items = []
        })
    },
    registerSubscription: async function (){
      // サブスクリプション登録
      await API.graphql(
        graphqlOperation(onCreatePost)
      ).subscribe({
        next: (eventData) => {
          const res = eventData.value.data.onCreatePost
          const onCreatePost = {
            ...res,
            content:res.content.replace(/\r?\n/g, '<br>'),
            date: dayjs(res.createdAt).format('YYYY/MM/DD')
          }
          this.items.unshift(onCreatePost)
        }
      })
    },
    postData: async function () {
      // オプション
      const myInit = {
        name: String(this.name),
        content: String(this.content),
      };
      // データ登録
      await API.graphql(graphqlOperation(createPost, { input: myInit }))
        .then((response) => {
          console.log(response);
          this.clear();
        })
        .catch((error) => {
          console.log(error)![Something went wrong]()
;
        });
    },
  },
};
</script>
```

## GithubからAmplifyへCDする

Githubに適当なリポジトリを作って、AWSのチュートリアルを見ながらAmplifyを設定。
ビルドコマンドやディレクトリなどは、あらかじめVuejsアプリを使ってからAmplify CLIを使うとほぼ全自動で設定されます。
うまくできたら、Githubのmasterブランチをコミットします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65643/df3edb22-4ce2-afc6-08ef-4f3d1fe93ee0.png)

完了まで行ったらデプロイアドレスから動作検証できます。
ものの1時間もかからずに出来ましたが、下記のようなつまづきポイントもありました。

## つまづいたところ

### Viteが邪魔してBuildが通らない

`yarn dev`は通るのに`yarn build`だとなぜかエラーが出るのでvite.config.jsを編集しました。

```vite.config.js
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "src"),
      "./runtimeConfig": "./runtimeConfig.browser", // 追加
    },
  },
```

### コンソールでエラーが出る

ブラウザのコンソールでglobal周りのエラーが出るのでindex.htmlのheaderに下記を追加しました。

```index.html

    <script>
        var global = global || window;
        var Buffer = Buffer || [];
        var process = process || {
            env: { DEBUG: undefined },
            version: []
        };
    </script>

```

# Viteの体感は0秒

編集から反映してページリロードまで本当に早くて素晴らしいです。
GraphQLのサブスクリプションならわざわざAPIをfetchしなくても、動作検証が続けられるので、相性も抜群ですね。
Appsyncもかなり簡単に使えました。Firebaseも簡単ですが、スキーマを設計してより強固なバックエンドに出来ると思います。