2019/04/21
Vue.jsとNode.jsを使って簡単なwebサービスを半日ほどで作ったので環境構築からデプロイまでざっと書きます。
https://github-janken.herokuapp.com
GitHub Usernameを入力してContribution数が多い人が勝ち。ただそれだけです。本田にも(多分)勝てます。リーナスは強すぎます・・・。
元ネタはB: AtCoderでじゃんけんを - AtCoder Regular Contest 048 | AtCoderとそれから生まれたwebサービスであるAtCoderじゃんけんです。
ツイートにもあるように、ケイスケホンダがあまりにもじゃんけん強者らしいので、じゃあ彼にGitHubのContribution数で勝ってやろうという意図から生まれました。
【4/23 追記】相手に勝負を挑めるようになりました。自分のGitHub Usernameを入力して「勝負を申し込む」を押すとリンクが発行されます。相手にそのURLを送りつけると、受け取った側は自分の名前を埋めるだけでその人と勝負できます。これにより、エンジニア同士のいさかいや宗教戦争はじゃんけんで公平かつ公正に勝敗を決めることができます。
最初にvue-cli
やnpm
やheroku
などは使えるようにしておきます。その後、フロントエンドとバックエンドそれぞれにプロジェクトを作成します。vue create
やnpm init
を実行した際に色々聞かれるのはデフォルトでOKです。
$ mkdir github_janken
$ cd github_janken
$ vue create frontend
$ mkdir backend
$ cd backend
$ npm init
ここまで行くと以下のようなディレクトリ構造になってます。
.
├── backend
│ └── package.json
└── frontend
├── README.md
├── babel.config.js
├── node_modules
├── package-lock.json
├── package.json
├── public
└── src
もくもく開発します。
axios
でAPIを叩くようにしましたが、ローカルの開発環境と本番の環境でエンドポイントのベースとなるURLが異なるので、その辺りを考慮する必要があります。vue-cli-service
の引数によって読み込まれる環境ファイルが変わるので、それによって環境変数を切り替えます。
Axios
のbaseURL
はこのように環境変数を用いて指定します。
axios.create({
baseURL: process.env.VUE_APP_API_URL
})
開発用の環境変数は.envや.env.developmentに記述します。
VUE_APP_API_URL=http://localhost:3000/
本番用の環境変数は.env.productionに記述します。こちらはバックエンドをデプロイするURLになります。
VUE_APP_API_URL=https://github-janken-backend.herokuapp.com/
重要なポイントは、VUE_APP_
から始まる変数だけがVueのコンパイル時にセットされるという点です。https://cli.vuejs.org/guide/mode-and-env.html#using-env-variables-in-client-side-code に書いていますが、知らないとハマりそうになります。(僕です。)
シェアボタン自体は、https://publish.twitter.com/?buttonType=TweetButton&widget=Button から取得して貼り付けるだけなのですが、今回は動的に生成されたじゃんけん結果をツイートする必要があるため、:data-text
の内容をcomputed property
などで指定します。
<a
href="https://twitter.com/share?ref_src=twsrc%5Etfw"
class="twitter-share-button"
:data-text="tweet_msg"
data-url="https://github-janken.herokuapp.com/"
data-show-count="false"
>Tweet</a>
そしてhtmlのどこかに以下の<scirpt>
を設置します。
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
しかしこれではうまく動作しません。<scirpt>
がロードされるタイミングでツイートする文章を確定してしまうので、後からtweet_msg
を変更しても反映されないようです。
そこでじゃんけん結果が出るたびにこの<script>
タグを動的に生成します。
// Twitterボタンの動的生成
const script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://platform.twitter.com/widgets.js";
script.charset = "utf-8";
const first_script = document.getElementsByTagName("script")[0];
first_script.parentNode.insertBefore(script, first_script);
Vue.js使っているのにinsertBefore
とかは流石にダメが気がしますね(いい方法あればコメントお待ちしています。)
バックエンドはスクレイピングのために利用しています。GitHub APIにはContribution数を簡単に取得できるAPIが無いらしいので、仕方なくhttps://github.com/users/teru01/contributions などのページから数字の部分を取り出しています。フロントエンドから直接スクレイピングしようかとも思ったのですが、CORSの制約のため不可能だったので、バックエンドのNode.jsでスクレイピングしています。
フロントとバックエンドでそれぞれ別のherokuアプリとしてデプロイします。package.json
のscripts.start
に書いてあるコマンドを実行してくれるので、そこにnode
コマンドを記述します。
"scripts": {
"start": "node index.js"
},
フロントエンドのプロジェクトにもそれを配信するサーバが必要なのでexpress
を用意します。
$ npm install express serve-static
プロジェクトルートにserver.js
などの名前でサーバープログラムを作成し、package.json
を変更します。
const express = require('express');
const serve_static = require("serve-static")
const path = require('path');
const app = express();
app.use(serve_static(path.join(__dirname, 'dist')));
const port = process.env.PORT || 80;
app.listen(port);
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"postinstall": "npm run build",
"start": "node server.js"
},
postinstall
はherokuがdependenciesを解決した後で実行するコマンドです。npm run build
が指定されているため、Vueがプロダクションモードでコンパイルされて、そのあとにstart
に指定したコマンドが実行されます。
https://medium.com/binarcode/deploying-vue-apps-to-heroku-the-right-way-26b11c1ae5cd
https://atcoder-janken.appspot.com
https://qiita.com/y4u0t2a1r0/items/a6aea444efc8e8e65293
https://qiita.com/pure-adachi/items/c2c5730560650c80a5e0
https://github.com/teru01/github_janken_backend
https://github.com/teru01/github_janken_frontend