前言
由react
客户端渲染的前端界面配合webpack-dev-server
, react-hot-loader
很容易实现前端开发过程中的局部刷新。然而配合node服务器的react-isomorphic
实现局部刷新,同时更新client
, server
端的代码并非易事。
如下介绍一种可行的实施方案:
适用于
koa2
,react-hot-loader3
,react-router
可有可无。Demo代码地址:https://github.com/lanjingling0510/blog/tree/master/react-isomorphic-hot-example
hot reload分析
react静态资源热加载分析
react静态资源的热加载配置并不复杂。webpack-dev-server
负责重新编译代码,react-hot-loader
负责热加载。
Note:
webpack-dev-server
也可以用开一个express
服务器配合webpack-dev-middleware
和webpack-hot-middleware
中间件实现
配置
webpack.client-dev.js
:
plugins: [
new webpack.HotModuleReplacementPlugin()
]
// ...
entry: [
'react-hot-loader/patch',
'webpack-dev-server/client?http://127.0.0.1:8080',
'webpack/hot/only-dev-server',
'./src/client/home', // 入口路径
]
修改
babel
配置文件
"plugins": [
"react-hot-loader/babel"
]
修改入口文件
import React from 'react';
import ReactDOM from 'react-dom';
// 共享的组件页面
import Home from '../shared/page/Home';
// 热加载组件
import ReactHotLoader from '../shared/component/ReactHotLoader';
const container = document.getElementById('react-container');
function renderApp(TheApp) {
ReactDOM.render(
<ReactHotLoader>
<TheApp />
</ReactHotLoader>,
container
);
}
renderApp(Home);
// 下面的代码用来支持我们热加载应用
if (__DEV__ && module.hot) {
// 接受这个文件的修改用来热加载
module.hot.accept('./home.js');
// 应用任何的改变将造成热加载,重新渲染。
module.hot.accept(
'../shared/page/Home',
() => renderApp(require('../shared/page/Home').default)
);
}
react服务器配置分析
开发模式下,server端的配置比较复杂,需要考虑的事情如下:
监听server代码的变动。
需要重新编译server代码
重新开启server服务器,并保证require最新的server代码
保证server端口按需开关,不冲突
监听server代码
// 监听server文件的变化,如果被修改则调用compileHotServer
const watcher = chokidar.watch([
path.resolve(__dirname, '../src'),
path.resolve(__dirname),
], {ignored: path.resolve(__dirname, '../src/client')});
watcher.on('ready', () => {
watcher
.on('add', compileHotServer)
.on('addDir', compileHotServer)
.on('change', compileHotServer)
.on('unlink', compileHotServer)
.on('unlinkDir', compileHotServer);
});
关闭所有与客户端的连接,关闭server服务器,重新编译server代码
// 关闭所有连接,关闭服务器,重新编译
function compileHotServer() {
compiling ++;
// listenerManager实例包含当前web服务器对象和客户端连接的socket集合
if (listenerManager) {
listenerManager.dispose(true).then(runCompiler);
} else {
runCompiler();
}
}
// webpack重新编译
function runCompiler() {
compiler.run(() => undefined);
}
重新开启server服务器
// server代码编译完成
// 开启server服务器
compiler.plugin('done', stats => {
compiling --;
if (compiling !== 0) return;
if (stats.hasErrors()) {
console.log(stats.toString());
return;
}
console.log('? ? Build server bundle done.');
// 确保新的server bundles 代码不在module cache当中
Object.keys(require.cache).forEach((modulePath) => {
if (modulePath.indexOf(compiler.options.output.path) !== -1) {
delete require.cache[modulePath];
}
});
try {
const listener = require(compiledOutputPath).default;
listenerManager = new ListenerManager(listener, 'server');
} catch (err) {
console.log(err);
}
});
待解决
. react-router
包含的页面组件更新后,提示[react-router] You cannot change <Router routes>; it will be ignored
,但不影响刷新
总结
通过以上配置,可以实现修改代码后,实现server和client代码的更新以及hot reload。
代码开发过程中,需要开启两个端口,分别用来提供client端静态资源的编译和后台的server。
如果在开发模式下,有更完善的react isomoriphic
服务器渲染热加载的解决方案,欢迎大家积极贡献 ?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。