reactjs
webpack

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の起点
別に特別な設定なんか要らなかったんや

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

render(<Hello />, document.body);

コンポーネントも react-hot-loaderでラップするだけ

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

package.json
{
 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --hot --mode development --open"
  }
}

--hotでHMRの有効化とwebpack4から--modeのオプションが必要になるので追加するのはそれぐらい

.babelrc

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

react-hot-loader/babel 追加

webpack.config.json

一番つまづいたのがここ

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

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

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

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.jshot/update.jsonを読み込めていなかった

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

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として渡すのがいいのかも
誰か教えてくれると助かりやす