step1: 开启webpack4.0+ 热更替
- 安装npm webpack@4.39.1 webpack-cli@3.3.6 babel-loader @babel/core@7.5.5 @babel/preset-env@7.5.5 webpack-dev-server@3.8.0 html-webpack-plugin -D
说明
: @babel/core@7.5.5 @babel/preset-env@7.5.5, 解析js文件, babel/preset-env高级语法转化成低级语法;html-webpack-plugin 解析模板html文件;
- 安装react react-dom @babel/preset-react -D
说明
: 解析react 语法
- 配置webpack.config.js
说明:
最重要的是devServer: hot hotOnly(浏览器不自动刷新) 以及plugins中的
webpack插件NamedModulesPlugin、HotModuleReplacementPlugin;
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const webpack = require("webpack");
module.exports = {
devServer: {
port: 3000,
open: true, // 自动打开浏览器,
contentBase: path.resolve(__dirname, 'build'),
hot: true, // 开启热更替
hotOnly: true , // 即使HMR没有生效 浏览器也不会自动更新 必须设置
},
entry: './src/index.js',
mode: 'development',
output: {
filename: 'build.js',
path: path.resolve(__dirname, 'build')
},
devtool: 'eval-source-map',
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
include: path.resolve(__dirname, 'src'),
use: [{
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
]
}
}]
}]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html'
}),
new webpack.NamedModulesPlugin(), // 打印出那些变化文件的路径
new webpack.HotModuleReplacementPlugin(), // 热更替组件
]
}
step2: 使用HMR 替换根组件
- 使用HMR前, 代码like this:
// root.js
import React from 'react';
export default class Root extends React.Component{
render(){
return <div>Test</div>
}
}
import React from 'react';
import {render} from 'react-dom';
import RootContainer from './root.js';
render(<RootContainer></RootContainer>, document.getElementById('root'));
- 加入热更替, 代码like this
import React from 'react';
import ReactDOM from 'react-dom';
import RootContainer from './root.js';
const render = (App) => {
ReactDOM.render(<App />, document.getElementById('root'));
}
render(RootContainer)
if(module.hot){
module.hot.accept('./root.js', ()=>{
console.log('root 更新了...'); // 浏览器中显示
const NextRootContainer = require('./root.js').default;
render(NextRootContainer)
});
}
说明
: 红框内console的日志及webpack.NamedModulesPlugin() 打印出来的更新文
件的路径; 示图如下:
- 创建component Demo, 并在root.js 引入
// demo.js
import React from 'react';
export default class Demo extends React.Component{
render(){
return <div>Demo</div>
}
}
// root.js
import React from 'react';
import Demo from './demo.js';
export default class Root extends React.Component{
render(){
return <div>
<div>Test</div>
<Demo></Demo>
</div>
}
}
运行结果:
当更新root.js Test to Test1, 结果显示 root.js 改变了, Demo组件更新路径没有 显示, 如图:
改变Demo.js Demo to Demo1, 显示了root demo 更新了,因为demo 是root组件, root 的路径也显示出来了,如图:
note: 这似乎满足了我们要求, 需要在验证一点 state 能否保持不变, 在root 新增state, 代码地址, 点击Test text 变成 Test1, 相同操作 Demo to Demo1, 当我们把aa变成了aaa, Test1变成Test Demo1变成Demo;state没有保存;结果如下:
注意
: 没有进一步的步骤,这已经足够热重载更改来响应组件,但是它们的内部组件状态将不会被保留,因为组件的新副本已被挂载,并且其状态将被重新初始化。
保存在状态存储(例如Redux)外部的状态显然不会丢失。
step3: 新增React hot Loader 保存组件状态
-
安装react-hot-loader npm i react-hot-loader -D
-
修改webpack.config.js 相关配置
// old
{
test: /\.js$/,
exclude: /node_modules/,
include: path.resolve(__dirname, 'src'),
use: [{
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
]
}
}]
}
// new
{
test: /\.js$/,
exclude: /node_modules/,
include: path.resolve(__dirname, 'src'),
use: [{
loader: 'react-hot-loader/webpack'
},{
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
],
"plugins": [ "react-hot-loader/babel" ]
}
}]
}
- 更新entry, 并修改index.js
entry: './src/index.js',
to
entry: ['react-hot-loader/patch','./src/index.js']
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import RootContainer from './root.js';
const render = (App) => {
ReactDOM.render(
<AppContainer>
<App />
</AppContainer>,
document.getElementById('root'));
}
render(RootContainer)
if(module.hot){
module.hot.accept('./root.js', ()=>{
console.log('root 更新了...'); // 浏览器中显示
const NextRootContainer = require('./root.js').default;
render(NextRootContainer)
});
}
结果显示 Test1 Demo1没有变化, 热更替success