あいつの日誌β

働きながら旅しています。

Using Hot Module Replacement with React

Browsersync と webpack でやってみます。

Goal

少しわかりづらいのですが Live Reload を React Component 単位で行います。

f:id:okamuuu:20161125211944g:plain

準備

mkdir practice-react-hmr && cd $_
mkdir -p src/components www
npm init -y
npm install --save-dev browser-sync webpack webpack-dev-middleware webpack-hot-middleware
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-stage-0 babel-preset-react react-hot-loader
npm install --save react react-dom

create webpack.config.js

const path = require('path')
const webpack = require('webpack')

module.exports = {
  debug: true,
  devtool: 'inline-source-map',
  entry: [
    'webpack/hot/dev-server',
    'webpack-hot-middleware/client',
    './src/index.js'
  ],
  output: {
    publicPath: "/",
    path: path.resolve('www'),
    filename: "bundle.js",
  },
  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  resolve: {
    extensions: ['', '.js'],
  },
  module: {
    loaders:[
      { test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel'] }
    ]
  }
}

create devServer.js

var webpack = require('webpack')
var browserSync = require('browser-sync')
var webpackDevMiddleware = require('webpack-dev-middleware')
var webpackHotMiddleware = require('webpack-hot-middleware')

var config = require('./webpack.config')
var bundler = webpack(config)

browserSync({
  server: {
    baseDir: config.output.path,
    middleware: [
      webpackDevMiddleware(bundler, {
        publicPath: config.output.publicPath,
        stats: { colors: true }
      }), 
      webpackHotMiddleware(bundler)
    ]   
  },  
  files: [
    'www/*.html'
  ]
})

create .babelrc

{
  "presets": ["es2015", "stage-0", "react"],
  "plugins": ["react-hot-loader/babel"]
 }

create www/index.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  </head>
  <body>
    <div id="root"></div>
    <script src="/bundle.js"></script>
  </body>
</html>

create src/index.js

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

render(
  <App />, 
  document.getElementById('root')
)

if (module.hot) {
  module.hot.accept('./components/App.js', function() {
    const NextApp = require('./components/App').default;
    render(<NextApp/>, document.getElementById('root'));
  }); 
}

create scr/components/App.js

import React from 'react'

export default (props) => (
  <h1>HMR test</h1>
)

run server

node devServer.js

ブラウザを確認しながら scr/components/App.js を編集するとブラウザを reoload せずに component だけ refresh することができます。