Vue.jsで作ったSPAだけどアプリケーションの更新をお知らせしたい!
![Vue.jsで作ったSPAだけどアプリケーションの更新をお知らせしたい!](https://www.hands-lab.com/wp-content/uploads/2019/10/vue-2.png)
お疲れ様です。
MDグループの志村(@naokiur)です。
エンジニアブログ初投稿です。よろしくお願い致します。
入社して2年、私服OKな弊社ですが、
個人的な好みで、ほとんどスーツで出社しています。
フロントエンドにVue.js、
バックエンドにDjango REST Frameworkを利用し、
業務アプリケーション開発に従事しております。
この度、
リリース後、フロントエンド側のバージョンアップがあったとき、
ユーザーにどうやってお知らせするのか? の解決策を1つ、
構築したので、その話を記載させて頂きます。
前提
Angular, React, Vue.jsなど、様々なフレームワークを用いて作成される、
シングルページアプリケーション(SPA)。
そのSPAと、バックエンドにREST APIを用いたオーソドックスなシステムの動きとして、
以下のような流れがあると認識しております。
1. ブラウザがリクエストを送信し、SPAの情報をWebサーバーから取得する
![](https://s3-ap-northeast-1.amazonaws.com/www.hands-lab.com-458223574924/tech/wp-content/uploads/2019/09/スクリーンショット-2019-09-27-9.14.02.png)
2. SPAがリクエストを送信し、APIサーバーのAPIを実行する
![](https://s3-ap-northeast-1.amazonaws.com/www.hands-lab.com-458223574924/tech/wp-content/uploads/2019/09/スクリーンショット-2019-09-27-9.14.06-1024x539.png)
以降、情報のやりとりはAPIサーバーと行われます。
問題提起
月日が経ち、フロントエンド側の機能追加やバグ修正で、
バージョンがアップした場合、どのようになってしまうでしょうか?
ユーザーがブラウザを逐次閉じていて、
毎日必ず一度は、Webサーバーへアクセスしていてくれれば、
特に問題は発生しないかもしれません。
しかし、
業務アプリケーションにおいて、
ブラウザを開きっぱなしで、マシンもシャットダウンせず、
毎日の業務を行っている、ということもあるかもしれません。
その場合、以下のようになってしまう、
と考えております。
![](https://s3-ap-northeast-1.amazonaws.com/www.hands-lab.com-458223574924/tech/wp-content/uploads/2019/09/スクリーンショット-2019-09-28-14.09.32-1024x472.png)
調査
みなさん悩んでいると思うので、Google先生にお伺いをしたところ、
React.jsでこの問題について、コンポーネントを作成し、
対処している方がいらっしゃいました。
https://marmelab.com/blog/2016/08/29/auto-reload-spa-on-mobile-setinterval.html
ざっくりと概要をお話しすると、
・SPAのソースコードを変更して、トランスパイルすると、index.htmlの内容が変化する
・index.htmlの中身をハッシュ化した値を保持する
・定期的にindex.htmlへのリクエストを送信する
・取得したindex.htmlをハッシュ化した値と、保持した値を比較する
・比較結果が等しくなければ、ブラウザを更新するよう、ユーザーに促す
です。
![](https://s3-ap-northeast-1.amazonaws.com/www.hands-lab.com-458223574924/tech/wp-content/uploads/2019/09/スクリーンショット-2019-09-28-14.32.04-1024x499.png)
これの、Vue.jsバージョンを作成しました!
実装
このコンポーネントには、以下のロジックが必要となります。
・index.htmlを取得すること
・ハッシュを計算すること
・ハッシュ値を比較すること
・リロードすること
これらのロジックを、コンポーネントの methods()
に定義し、created()
で、 setInterval()
によって、定期的に実行する、
という寸法です。
created() {
setInterval(this.fetchServer, 1000 * 60 * this.normalizedFrequencyMinutes);
},
また、ユーザーに通知するためのHTMLも書いておきます。isChanged
がtrueになったら表示して、ユーザーに更新を促す、という内容です。
<template>
<div id="notification" v-if="isChanged>
<button class="cancelButton" @click="cancel">×</button>
<span class="notificationTitle">更新通知</span>
<span>アプリケーションの更新を確認しました。更新しますか?</span>
<button class="okButton" @click="reload">OK</button>
</div>
</template>
index.htmlを取得すること
fetchメソッドを用いて、index.htmlの内容を取得します。
Promiseが返ってくるので、成功したときにハッシュ値を比較するようにします。
fetchServer() {
fetch(this.normalizedUrl)
.then(res => {
if (res.status !== 200) {
throw Error('Cannot access server.');
}
return res.text();
})
.then(html => {
const hash = this.createHash(html);
this.judgeHash(hash);
})
.catch(err => console.log(err));
},
ハッシュを計算すること
与えられた文字列のハッシュ値を計算します。
このメソッドに、index.htmlの内容をすべて渡し、
ハッシュ値を計算してもらう、という寸法です。
StackOverFlowの記事を参考にさせて頂きました。
createHash(str) {
const len = str.length;
let hash = 0;
if (len === 0) return hash;
let i;
for (i = 0; i < len; i++) {
hash = ((hash << 5) - hash) + str.charCodeAt(i);
hash |= 0; // Convert to 32bit integer
}
return hash;
},
ハッシュ値を比較すること
data()
に 用意しておいた `previousHash` と、
計算したハッシュ値を比較します。
差分があれば、新たなハッシュ値として、
計算したハッシュ値を保持します。
isChangeをtrueにしたので、
前述の通知用HTMLが表示されます。
judgeHash(hash) {
if (!this.previousHash) {
this.previousHash = hash;
return;
}
if (this.previousHash !== hash) {
this.isChanged = true;
}
},
リロードすること
location.reloadメソッドをすることで、
ブラウザの更新を実行します。
trueを渡して、キャッシュを使用せず、Webサーバーから取得してもらいます。
reload() {
location.reload(true);
},
サンプル
おなじみかと思いますが、
Vue CLIでcreate projectした際に作成されるアプリケーションに、
上記のコンポーネントを追加しました。
buildして、S3のWebサイトホスティングで、
ホストしています。
![](https://s3-ap-northeast-1.amazonaws.com/www.hands-lab.com-458223574924/tech/wp-content/uploads/2019/09/スクリーンショット-2019-09-28-18.01.50-1024x816-copy-1024x816.jpg)
このときのindex.html(の一部)は、以下のようになっています。
![](https://s3-ap-northeast-1.amazonaws.com/www.hands-lab.com-458223574924/tech/wp-content/uploads/2019/09/スクリーンショット-2019-09-28-18.06.23-1024x24.png)
「Welcome to …」の部分を修正し、再buildします。
![](https://s3-ap-northeast-1.amazonaws.com/www.hands-lab.com-458223574924/tech/wp-content/uploads/2019/09/スクリーンショット-2019-09-28-18.06.29-1024x35.png)
index.htmlの内容が変わったことがわかります。
そして、S3に配置し、しばらくすると…
![](https://s3-ap-northeast-1.amazonaws.com/www.hands-lab.com-458223574924/tech/wp-content/uploads/2019/09/スクリーンショット-2019-09-28-18.09.43-1024x815-copy-1024x815.jpg)
でました!!
「OK」を押すと…
![](https://s3-ap-northeast-1.amazonaws.com/www.hands-lab.com-458223574924/tech/wp-content/uploads/2019/09/スクリーンショット-2019-09-28-18.09.58-1024x844-1024x844.jpg)
リロードされ、「Welcome to …」の部分が変わりました!!
結び
SPAにおける課題の1つを解決できたかなと思います。
フロントエンドエンジニアとして自分はまだまだぴよぴよですが、
より一層、課題の解決に取り組み、
成長していきたいと思っております。
そしてハンズラボ、Vue Fes Japan 2019でシルバースポンサーをさせていただきます!
ブースも出店させていただきますので、
ご来場の際はぜひお立ち寄り下さい!!