webpack中提供了热模块更新的功能,在不刷新整个页面的情况下来替换某些更变的组件,而这样做的最大的好处就在于状态的保存。比如我们前面在输入框中输入的内容,就不会在我们热模块替换以后被刷新掉,让我们要重新再输入一次了。
而react的构建现在一般还是基于webpack的,webpack也提供了对应的插件。react-hot-loader
https://github.com/gaearon/react-hot-loader
跟着github上面的例子我们就可以很快进行搭建了。
这里要注意几点。
我们创建项目的时候是类似creat-react-app的方式创建项目的。
creat-react-app的创建方式是有两个js文件,一个是index.js,一个是App.js
App.js是根组件,而index.js才是来执行初始化以及渲染这些工作的。而我们有的时候是把这两个合二为一了。这样就跟官网的对不上会有点。
下面给出一个demo来进行配置
目录结构
App.jsx
import React from 'react';
import { hot } from 'react-hot-loader';
import { Hello } from './components/hello.jsx';
require('./font.js');
class App extends React.Component {
constructor(){
super();
console.log("App");
}
render() {
return (
Hello
)
}
}
export default hot(module)(App)
这里的svg可以进行删除
index.jsx
import React from 'react'
import { render } from 'react-dom'
import App from './App.jsx'
import './scss/index.scss';
const root = document.createElement('div')
document.body.appendChild(root)
render( , root)
这里我们可以发现,在index.jsx中是自行创建了一个div所以我们在模版文件中其实可以不用哪个我们经常使用的
了
子组件
hello.jsx
import React from 'react';
import { hot } from 'react-hot-loader';
export class Hello extends React.Component{
render(){
return (
hello
)
}
}
可以发现,我们的子组件并没有使用hot这个东西,代表只要我们给根组件设置hot就好了。
官网上给出的例子是使用--hot进行启动,如果我们只想在webpack中进行配置而不是使用npm script
我们可以这样配置webpack的config文件。
webpack.config.dev.js
console.log("dev");
const path = require('path');
const webpack = require('webpack');
const htmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
const HotModuleReplacePlgun = require('webpack/lib/HotModuleReplacementPlugin');
module.exports = {
entry: ['react-hot-loader/patch', './src/index.jsx'],
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/dist/',
filename: 'js/[name].js'
},
module: {
rules: [
{
test: /\.jsx$/,
exclude: /(node_modules)/,
include: path.resolve(__dirname, 'src'),
use: {
loader: "babel-loader",
options: {
presets: ['env', 'react'],
plugins: ['react-hot-loader/babel'],
}
}
},
{
test: /\.css$/,
include: path.resolve(__dirname, 'src'),
use:[
"style-loader",
"css-loader"
]
},
{
test: /\.scss$/,
include: path.resolve(__dirname, 'src'),
use:[
"style-loader",
"css-loader",
"sass-loader"
]
},
{
test: /\.(gif|png|jpg)$/,
include: path.resolve(__dirname, 'src'),
use: [{
loader: "url-loader",
options: {
limit: 8192,
name: "assets/img/[name].[ext]"
}
}],
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
include: path.resolve(__dirname, 'src'),
use: [{
loader: "url-loader",
options: {
limit: 8192,
name: "assets/[name].[ext]"
}
}],
},
]
},
plugins: [
new htmlWebpackPlugin({
template: "./src/index.html"
}),
// new ExtractTextWebpackPlugin("css/[name].css"),
// new ExtractTextWebpackPlugin("scss/[name].scss"),使用这个就无法开启热模块替换了
// 提取公共模块
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
filename: "js/base.js",
}),
// 设置热更新
new HotModuleReplacePlgun(),
new webpack.NamedModulesPlugin(),
],
devServer: {
port: 8888,
// 使用热模块更新,必须安装插件
hot:true,
// 自动在启动后打开浏览器
open : true,
openPage:'dist/',
},
resolve: {
// 配置寻找第三方库的时候的位置
modules: [path.resolve(__dirname, 'node_modules')],
// extensions:['jsx','js','json']
},
watchOptions: {
// 不监听这些文件
ignored: /node_modules/
},
devtool: 'source-map'
};
这里最关键的是
jsx的配置以及入口文件的配置
然后设置hot为true
这里要注意的一点是,我们没有使用单独提取文件的功能把css进行单独抽出
这个原因是因为他不支持热模块更新的原型,一旦单独提取了css文件,那么我们修改了scss跟css都不会立即生效。
所以我们需要两个webpack.config.js文件来实现开发跟生产的区分。
最后是npm的执行文件
问题得以解决。
因为技术的更新其实很快。可能当你看到这篇博文的时候,里面的方法已经跟最新版的对不上了,这个时候我还是建议你去github上面把这个项目clone下来。然后执行一下里面的例子看看,这个样子应该会好一点。