新型コロナウイルス対策サイトの data.json を外部から読み込めるよう疎結合化してみた

# 開発した動機

[新型コロナウイルス対策サイトを１からブラウザだけで更新データを編集してプレビューまでできるようにしてみた](https://qiita.com/wakasamasao/items/f2f7f68a9f7dc7a355e6)

この作者さんの思いを感じ、

「たしかに、データとプログラム部分は分離されているほうが便利なことも多いよなぁ」

とおもったので、疎結合にしてみました。

※ 完全自動化されて、データの取り込みなんて、１日１回のバッチ処理だぜぃ！ な東京都やオープンデータ完備な自治体対応の場合は、現状の静的サイト生成も大正解だと思います。

# 結論

[data.json の一部を長野県専用のレポジトリから動的に読み込み](https://github.com/hisayan/covid19/commit/6ec2fbd250dcbca59e0a3835bc1cefc1f4213233)

GitHub にて、この commit 差分を眺めてもらうだけでも、分かる人にはわかるかなと思いますが、すこし解説を Qiita に残そうと思いました。

ちょっと Bad Hack 感ものこるので、もしそのあたりで、もっとベストプラクティスあれば、コメント欄などで教えてやってくださいませ。

# 手順解説

## Store をつかおう

新型コロナウウイルス対策サイトは、NuxtJS というフレームワークを用いてつくられています。

いくつかやりかたはあるのですが、NuxtJS (Vuex) が機能として持っている、Store にデータを取り込むことにしました。

Store は、Reactive なデータ更新を前提とした機能ですが、今回はそのような使い方はしないで、Webアプリ起動時の一回きりの読み込みとしています。

*... Qiita に、Github の diff とか、かんたんに埋め込む方法、ないのかしら*

/store/data.js をつくりましょう。

https://github.com/hisayan/covid19/commit/6ec2fbd250dcbca59e0a3835bc1cefc1f4213233#diff-fdf908395f5da41831db2f0cc5a19c3f

ここでしていることは簡単で、Store のデータ領域を用意し、そこに axios で、外部サイトから data.json を読み込んでくる Action をつくっています。

なお、わたしが携わっている長野県版の場合は、まだ完全な外部JSON処理が固まっていないため、初期値は、/data/data.json を読み込み、外部サイトからの data.json 読み込みは、その一部を上書きするような処理となっています。

## Middleware をつくろう

Store に、データを読み込まなければいけません。

ここがすこし Bad Hack 感あるので、もっといい方法をご存じの方がいれば教えていただきたいのですが、今回は、NuxtJS の Middleware という機能をつかって、Webアプリ起動時に、一度だけ data.json を読み込むようにしました。

/middleware/getData.js をつくりましょう。

https://github.com/hisayan/covid19/commit/6ec2fbd250dcbca59e0a3835bc1cefc1f4213233#diff-1af28169d27ead689db09e8faffd1f9b

store.state.data.data が空の場合に、先程作った、Store の Action をキックする処理です。

Middleware は、NuxtJS のアプリ内でページ遷移が発生するたびにキックされるような仕組みです。

このように記述することで、アプリ起動時のみ、Store の Action がキックされるようになります。


そうそう、つくった middleware を有効にするように、nuxt.config.js にも追記が必要です。

https://github.com/hisayan/covid19/commit/6ec2fbd250dcbca59e0a3835bc1cefc1f4213233#diff-a216f5c067bcf89f670f6d5d950695b8R199-R204

## URLを環境変数に

nuxt.config.js をさわるついでに、data.json を取得してくる外部URLを、環境変数化してしまいましょう。 

https://github.com/hisayan/covid19/commit/6ec2fbd250dcbca59e0a3835bc1cefc1f4213233#diff-a216f5c067bcf89f670f6d5d950695b8R7-R14

※ このURLにアクセスする際には、access-control-allow-origin が適切に返される必要があります。それについて、わからないかたは、別途ググってくださいね。

## data.json が使われているところを store に置き換える

とにかく

```
import Data from '@/data/data.json'
```

となっているソースコードを検索して、置き換えました。

基本的に、

```
// import Data from '@/data/data.json'
```

この行を削除するなりコメントアウトするなりし、vue のクラス内の data() 直後に、一行いれるだけで対応するはずです。

```
  data() {
    const Data = this.$store.state.data.data
```


# ちょっとまった！！

ここまでの方法だと、spa モードでしたうまくうごいてませんでした。
Bad Hack 感があったの場所が、やはり考慮不足でした。反省。。。再度対応しました。

お手数かけますが、こちらの Branch も参照ください。

[data.json の読み込みが universal モードではうまく動いてなかったので修正](https://github.com/hisayan/covid19/commit/0b796afdbbeaa1f46662147692868ccb6dc7c172)

middleware で、「Webアプリ起動時のみ一回だけ axios で json 読み込み」は、

* Universal モードでは、SSRで読み込まれ、クライアントサイドでルートが変更されるときに読み込まれる

* spa モードでは、毎回読み込まれる

という挙動で、今回のように netlify などに静的HTMLとして公開しているときは悪手でした。

なので、

[nuxt-client-init-module](https://github.com/potato4d/nuxt-client-init-module)

のお力を借りることにしました。


```bash
$ yarn add nuxt-client-init-module
```

[nuxt.config.json に、そのモジュールを利用するよう追記](https://github.com/hisayan/covid19/commit/0b796afdbbeaa1f46662147692868ccb6dc7c172#diff-a216f5c067bcf89f670f6d5d950695b8R133)


先に追加した middleware 関係を削除します。

```bash
$ rm -f ./middleware
```

[nuxt.config.js からも middlewareを削除](https://github.com/hisayan/covid19/commit/0b796afdbbeaa1f46662147692868ccb6dc7c172#diff-a216f5c067bcf89f670f6d5d950695b8L199-L204)

[/store/index.js をつくります](https://github.com/hisayan/covid19/commit/0b796afdbbeaa1f46662147692868ccb6dc7c172#diff-a216f5c067bcf89f670f6d5d950695b8L199-L204)

```js
export const actions = {
  async nuxtClientInit({ dispatch }) {
    // code
    await dispatch('data/getDataAction')
  }
}
```

ややこしくしちゃって、ごめんなさい。

# 最後に

ほかにも、news.json や metro.json など、外部読み込み化したい JSON もありますが、同じようなやりかたで実装できると思います。

長野県版でも、そのあたりのデータ更新について、オープンデータからバッチ処理で自動化できたり、人間手作業担当やその手順が決まったりしたら、実装すると思います。