webpack4 HMR rect-hot-loaderの設定

#webpack4 HMR rect-hot-loaderの設定

react-hot-loaderのドキュメントなどは公式やネットなどで沢山あるが、全てを参考にしてむしろ失敗した
最新のreact-hot-loaderだと複雑な設定は要らないっぽい

## インストール

```
yarn add -D react react-dom webpack webpack-cli webpack-dev-server @babel/core babel-loader @babel/preset-env @babel/preset-react clean-webpack-plugin html-webpack-plugin react-hot-loader babel-plugin-transform-class-properties
```

## コンポーネント


entryの起点
別に特別な設定なんか要らなかったんや

```javascript:App.js

import React from 'react';
import { render } from 'react-dom';
import Hello from 'components/Hello';

render(<Hello />, document.body);
```
-----
コンポーネントも `react-hot-loader`でラップするだけ

```jsx:Hello.jsx

import React from 'react';
import { hot } from 'react-hot-loader';


class Hello extends React.Component {
  state = {
    count: 0,
  };
  increment = () => this.setState({ count: this.state.count + 1 });
  render() {
    return (
          <button onClick={this.increment}>
            CLICKED {this.state.count} TIMES
          </button>
      )
  }
}
export default hot(module)(Hello);
```



## package.json

```json:package.json
{
 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --hot --mode development --open"
  }
}
```
`--hot`でHMRの有効化とwebpack4から`--mode`のオプションが必要になるので追加するのはそれぐらい

##.babelrc

```json:.babelrc
{
  "plugins": [
    "transform-class-properties",
    "react-hot-loader/babel"
  ]
}
```
`react-hot-loader/babel` 追加

## webpack.config.json

**一番つまづいたのがここ**


今まで`devserver`オプションをつけてサーバーを起動していた

```javascript
devServer: {
  contentBase: path.join(__dirname, 'dist'),
  publicPath: "/js/"
}
```

index.htmlをdistフォルダに置いてwebpack-dev-server上のbundle.jsを読み込んでいた

```html:index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Page Title</title>
</head>
<body>
    <script src="/js/bundle.js"></script>
</body>
</html>
```

このやり方だと、ファイルを変更時に`hot/hot-update.js`と`hot/update.json`を読み込めていなかった

なので静的ファイルを置かず、`HtmlWebpackPlugin`を使ってサーバーからhtmlファイルを作成するように修正


```javascript:webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const path = require('path');
module.exports = {
    entry: [
        './src/App'
    ],
    module: {
        rules:[
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: [{
                    loader: 'babel-loader',
                    options:  {
                        presets: [
                            ['@babel/react'],
                            ['@babel/env', {
                                "useBuiltIns": "usage",
                                "modules": false
                            }]
                        ],
                        cacheDirectory: true,
                    }
                }]
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin(),
    ],
    resolve: {
        extensions: ['.js', '.jsx'],
        alias: {
            components: path.resolve(__dirname, 'src/components'),
            images: path.resolve(__dirname, 'src/images'),
            constant: path.resolve(__dirname, 'src/constant')
        }
    }
};
```

あとは `yarn start` で実行するだけ
なんか色々な記事に迷わされたけど、蓋を開けてみると必要なのはたったこれだけだった

※ 静的なindex.htmlを置いてHMRする方法もその後、調べたけど`hot-update.js`を読み込ませるやり方がいまいち分かんなかった
多分、HtmlWebpackPluginにtemplate用のhtmlとして渡すのがいいのかも
誰か教えてくれると助かりやす