GAE+Nuxt.js+Firebaseでネココさんを喋らせるだけのサービス作成
Tags: nuxt, firebase, gae, vue
Published: 2018-10-17 12:10:58

---
title: GAE+Nuxt.js+Firebaseでネココさんを喋らせるだけのサービス作成
published: true
description: 
tags: nuxt,firebase,gae,vue
canonical_url: https://crieit.net/posts/GAE-Nuxt-js-Firebase
---

昔mixiアプリでネココレースというアプリを作ったのですが、その素材が放置状態でもったいない事に気づいたので、ネココさんを着替えさせて喋らせてTwitter上に投稿できる簡易なWebアプリを作ってみました。

![yf4qcSgR8rZR0fmmSwS7.png](https://thepracticaldev.s3.amazonaws.com/i/vz03rmrp0k5ohnhl02e2.png)

[ネココさんトーク](https://nekoko.alphabrend.com/)

ログインなど不要ですぐ使えます。

## 構成

### Google App Engine

この手のWebサービスにはあまり意味がないのですが、SSR（サーバーサイドレンダリング）で一応全部ページクロールできるようにして多少SEO的な効果も期待し、静的ホスティングサービスではなくGoogle App Engineにしてみました。

### Nuxt.js

最近は簡単なアプリケーションはNuxt.jsだととにかく簡単に色々作れるのでよく使っています。前述と同様、SSR目的でもあります。

### Firebase

今回はデータを登録して表示するだけというシンプルなデータ構成のため、わざわざサーバーを用意しなくてもよいFirebaseを使ったサーバーレス構成にしました。

データの保存にFirestore、画像の保存にStorageを使っています。

### Buefy

Bulmaというやわらかい感じのデザインを実装できるフレームワークを使っています。ただ、Bulma自体はほんとにCSSだけで、動きなどは自分で付けなければなりませんので、動き部分も実装されているBuefyを使っています。これを入れるだけでBulma自体のCSSもそのまま使うことができ汎用的で非常に便利です。

## 仕組み

### プロジェクトの作成

プロジェクトはcreate-nuxt-appを使って作成し、TypeScriptを追加しました。以前下記でまとめていた方法になります。

[Nuxt.js+ExpressのプロジェクトをTypeScript化する](https://crieit.net/posts/Nuxt-js-Express-TypeScript)

### Storeの利用

動物や着せ替えの選択は、選択したコンポーネントだけでなく、画像のダウンロードやシェアする画像を作成する等、他の場所でも使うためにStoreのStateとして保持しておきます。

StoreはNuxt.jsのマニュアルを見ると非常に理解しやすく、下記の記事でも以前まとめています。

[VuexのStoreはNuxt.jsのマニュアルを見るとすぐ理解できる](https://crieit.net/posts/Vuex-Store-Nuxt)

### 画像の作成

画像は html2canvas で作成しました。今回はサーバーが無いためこれを使ってブラウザ上で画像を作成する形です。`left: -2000px` とかにしたdiv上にあれこれ配置し、それをhtml2canvasで変換しているだけです。

一点注意点として、デフォルトの挙動では端末のサイズによってcanvasのスケールが変わってしまうようですので、下記のように等倍で作成します。

```javascript
    const canvas = await html2canvas(this.$refs.canvas, { scale: 1 })
```

Blobに変換する方法は下記等、色々情報があります。

[Canvasで描画した画像を送信してサーバに保存する - Qiita](https://qiita.com/0829/items/a8c98c8f53b2e821ac94)

canvas.toBlob もあるみたいですね。早く全てのブラウザで実装されてほしいものです。

あとはStorageへの登録はマニュアル通りです。ファイル名は登録したメッセージデータのID名にしています。

```javascript
    const ref = firebase.storage().ref()
    const imageRef = ref.child(`images/${messageId}.png`)
    const imageSnapshot = await imageRef.put(blob)
```

画像のURLも取っておきます。調べた情報によると、上記のimageRefでなく、再度Storage側から取ってきたものを使わないとダメなようです。

```javascript
    const ref = firebase.storage().ref()
    const imageRef = ref.child(`images/${messageId}.png`)
    const url = imageRef.getDownloadURL()
```

このURLもメッセージデータに保存しておけば完成です。

あとは表示画面で入力されたメッセージや画像のURLをメタタグに入れておけば、その詳細ページのURLをシェアしてもらうことでツイートでシェアすることができます。

Nuxt.jsの場合メタタグの設定はページコンポーネント内で下記のように行います。

```javascript
  head() {
    const title = this.getTitle() + ' - ネココさんトーク'
    const description = `${this.categoryExplanation}:${this.message.message}`
    return {
      title,
      meta: [
        {
          name: 'description',
          content: description
        },
        { name: 'og:title', content: title },
        {
          property: 'og:image',
          content: this.message.imageUrl
        },
        {
          property: 'og:description',
          content: description
        },
        {
          name: 'twitter:card',
          content: 'summary_large_image'
        },
        {
          name: 'twitter:image',
          content: this.message.imageUrl
        }
      ]
    }
  }
```

SSRのためデータはasyncDataで取っておきましょう。

```javascript
  async asyncData({ params }) {
    const messageRef = messagesCollection.doc(params.id)
    const message = await messageRef.get()
    const messageData: any = message.data()
    messageData.id = message.id
    return {
      message: messageData
    }
  }
```

シェアする画面へのURLの作成は下記のような感じです。

```javascript
  tweetUrl() {
    const url = encodeURIComponent(
      process.env.URL + `/messages/${this.message.id}`
    )
    const text = encodeURIComponent(this.categoryExplanation)
    const hashtags = encodeURIComponent('ネココさんトーク')
    return `https://twitter.com/share?url=${url}&text=${text}&hashtags=${hashtags}`
  }
```

### デプロイ

Google App Engineへのデプロイは下記で以前解説しています。

[App Engineの標準環境でNuxtを使って無料SSR](https://crieit.net/posts/App-Engine-Nuxt-SSR)

ZeitのNowでも良いと思います。GAEはFirebaseのプランが変わってしまう（無料枠は利用可能です）、Zeitは無料でのデプロイ回数制限がある、という違いがあるので適宜良い方を選択してください。

### おまけでGA

Google Analyticsの導入は下記をインストールして設定するだけでした。めちゃくちゃ簡単。

[nuxt-community/analytics-module: Google Analytics Module](https://github.com/nuxt-community/analytics-module)

## まとめ

大雑把になりますが作り方をざっと紹介しました。興味のある方は是非試してなにか作ってみてください！

不明点があればTwitter等で聞いてもらえれば可能な範囲で答えます。