Vue初心者が「Clubhouseやってるぜ」マウント取れるアプリ作った


注意
内容はないです
何かを期待して読むと必要以上に落胆してしまうのでご注意ください

はじめに

2月に入ってから急激に流行りだしたClubhouse。
何か裏で働いているのかというくらいにユーザー数の伸びがハンパないようです。

Clubhouseとは

完全招待制の音声SNSです。モデレーターがするお話を自由に視聴できます。また、モデレーターが指定した人は配信する側として一時的に加わることもできます。ラジオの視聴者参加みたいな感じですね。

Clubhouseが引き起こす問題

完全招待制ということで、一部の人からは「私、Clubhouse招待されていますよ🥴」とマウントに見えてしまうようです。

これは精神衛生上よくない。

そんな悔しい気持ちを抱える多くの人のために
   Clubhouseっぽいプロフィールメーカー
を作りました。

何ができるのか

こんな感じで

  • 画像
  • 姓名
  • ID

を入力すると

Clubhouseそっくりのプロフィールができちゃいます!
これなら本当はClubhouse誘われていなくても「私、やってます」マウントが取れますね

こちらからサクッと試せます。

どうやって作ったか

Qiitaは技術情報共有サービスですので、クソアプリの宣伝のためだけに使うのはよくありませんね。

使用技術

  • Vue.js
  • AWS
    • S3
    • Lambda
    • API Gateway
    • Route53
    • CloudFront

筆者の技術レベル

Pythonなら問題なく書ける。Flaskを使って簡単なWebアプリを作った経験あり。
最近モダンなフレームワークに興味を持ち始めた。
JavaScriptもVue.jsも最近勉強し始めたので見よう見まねでやっているが、あまりVue.jsの良さを生かせた開発はできない。

全体図

このように
1. ユーザーが画像・姓名・IDを入力
2. Base64でエンコードした画像・姓名・IDをAWS API Gatewayに送信
3. PillowでClubhouseっぽい画像に加工
4. API Gatewayを返して送信

という流れで処理をしています。

Canvas使えばいいんじゃない?

と、多くの人が思ったのではないでしょうか?
私も最初はCanvasで色々処理して、それをPNG変換しようかと思いましたが
「WebフォントがCanvasに反映されない」
という問題が発生しました。

(この辺詳しい方いらっしゃいましたらコメントください

そのため、Lambdaを介してプロフィール画像生成を行っています。

Vue.jsを使うにあたって

はじめてVue.jsを使って開発をした筆者がぶち当たった課題がいくつかありました。

vue-routerのhistoryモードの弊害

ルーティング制御のためにvue-routerを使ったのですが、https://example.com/example に直接アクセスすると404 Not Foundになるということを知りました。
SSR(サーバーサイドレンダリング)も可能なようですが、今回はそこまで時間をかけたくなかったためプリレンダリングを用いました。
Vue.jsのプリレンダリングについてはこちらのサイトが大変参考になりました。

API Gatewayから返されたデータを表示できない

事前にdataの中にimage: nullを定義しておき、axiosでAPI GatewayのURLにPOSTする形で画像処理を行っていましたが、なぜか処理後の画像がHTMLに反映されない問題
デバッグコンソールにはUncaught (in promise) TypeError: Cannot set property 'image' of undefinedの文字が…。
そのときに書いていたコードがこちら。


axios.post('https://example.execute-api.ap-example.amazonaws.com/example', {
          name: this.mei + ' ' + this.sei,
          userId: '@' + this.id,
          image: imgData
        }, {
          headers: {
            "Content-Type": "application/json"
          }
        })
        .then(function(response) {
          this.image = 'data:image/png;base64,' + response.data.image
        })

Vue.js上級者ならすぐわかるのかもしれませんが、初心者の私は1時間くらい溶かしました。

解決策

結果、こちらの記事に助けられました。

Vue.jsのdataオブジェクトを参照する際に Uncaught (in promise) TypeError: Cannot set property 'foo' of undefined

thisへのreference用変数(self)が必要なようです。
というわけで、正解はこうですね。


+ let self = this
axios.post('https://example.execute-api.ap-example.amazonaws.com/example', {
          name: this.mei + ' ' + this.sei,
          userId: '@' + this.id,
          image: imgData
        }, {
          headers: {
            "Content-Type": "application/json"
          }
        })
        .then(function(response) {
-           this.image = 'data:image/png;base64,' + response.data.image
+           self.image = 'data:image/png;base64,' + response.data.image
        })

また一つ賢くなりました。

編集後記

初めてのVue.jsとLambdaということでちょいちょい詰まりながらも大体2日(徹夜含む )で完成しました。

Vue.jsはまだまだ初心者なので、「こうしたらいいよ!」などありましたら温かいコメントをくださいますと幸いです。

以上、最後までありがとうございました!

※筆者は2月2日にはClubhouse招待されています