webpackでhtmlにjsonを埋め込む

[react-rails](https://github.com/reactjs/react-rails)の動きをフロントエンドの開発環境で再現するという要件があり、
reactで描画するためにjsonをhtmlに埋め込む方法を探していました。
webpackのプラグインで実現できましたので記事として残しておきます。

#環境
webpack ^4.28.2
node 8.9.3

#使用するパッケージ
html-webpack-plugin
https://github.com/jantimon/html-webpack-plugin

##インストール
`npm i --save-dev html-webpack-plugin`
`yarn add --dev html-webpack-plugin`
導入しているパッケージマネージャーに応じてインストールコマンドを実行します。

#基本の使用方法
[README](https://github.com/jantimon/html-webpack-plugin)に記載されている基本の導入方法です。

```js:webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: 'index.js',
  output: {
    path: __dirname + '/dist',
    filename: 'index_bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin()
  ]
}
```
コンパイルするとdist/に下記のindex.htmlが生成されます。

```html:dist/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Webpack App</title>
  </head>
  <body>
    <script src="index_bundle.js"></script>
  </body>
</html>
```

#jsonデータを用意する
読み込むデータをjson形式にします。
以下は例です。

```json:ads.json
{
  "common": [
    {
      "id": "id_01",
      "label": "代替文1",
      "url": "http://someurl.com",
      "img": "/assets/img/img_01.jpg"
    },
    {
      "id": "id_02",
      "label": "代替文2",
      "url": "http://someurl.com",
      "img": "/assets/img/img_02.jpg"
    },
    {
      "id": "id_03",
      "label": "代替文3",
      "url": "http://someurl.com",
      "img": "/assets/img/img_03.jpg"
    },
    {
      "id": "id_04",
      "label": "代替文4",
      "url": "http://someurl.com",
      "img": "/assets/img/img_04.jpg"
    },
    {
      "id": "id_05",
      "label": "代替文5",
      "url": "http://someurl.com",
      "img": "/assets/img/img_05.jpg"
    }
  ]
}
```
##jsonデータ内の特殊文字
コンパイル時にエラーが発生した特殊文字とエラーを回避した実体参照です。

|特殊文字|実体参照|補足|
|:--|:--|:--|
| （半角スペース）|`&nbsp;`|半角スペースがそのまま入っているとコンパイルエラーが発生する|
|-|`&#8209;`|実体参照を使用することで-のあとに発生する改行を防ぐ|


#pluginの設定を追加する
```js:webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: 'index.js',
  output: {
    path: __dirname + '/dist',
    filename: 'index_bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      json_ads: require('./src/assets/json/ads.json'),//読み込むjsonに任意のキーをつけconfigファイルからの相対パスを対応させる
      json_nav: require('./src/assets/json/nav.json'),//複数のjsonを読み込める
    }),
    //jsonを埋め込むhtmlが複数ある場合htmlごとにプラグインの設定が必要
    new HtmlWebpackPlugin({
      //index.html以外はtemplateとfilenameパラメータが必要
      template: './detail.html',//入力ファイルのentryからの相対パス
      filename: './detail.html',//出力するファイルのoutputからの相対パス
      json_ads: require('./src/assets/json/ads.json'),
      json_nav: require('./src/assets/json/nav.json')
    }),
  ]
}
```
#htmlでjsonを読み込む
```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
<main>
  <div data-react-class="SomeComponent" data-react-props=<%= JSON.stringify(htmlWebpackPlugin.options.json_ads) %>></div>
</main>
</body>
</html>
```
今回は記事のはじめに書いている通り、
react-railsの動きを再現したいためdivのdata属性にjsonデータを入れています。
`htmlWebpackPlugin.options`のあとはwebpack.configで設定した
jsonデータのキーを記載します。

`htmlWebpackPlugin.options.json_ads.common`のようにして
jsonデータの階層を取得することも可能です。

#おわりに
直後に改行しない`-`の表示方法を調べるのに思ったより時間がかかりました。
webpack.configはwebpackの[Configuration](https://webpack.js.org/concepts/configuration)ぺージを参考に
できるだけ少ない設定項目で書いてみましたがおかしい点があればお知らせください。