在express中HMR(合并express和webpack-dev-server)
在学习react的时候,经常用create-react-app来创建web应用,然而写到后面总有连自己服务器和数据库的需求,create-react-app创建的是一个webpack-dev-server,主要用来进行webpack的编译和热加载(HMR),所以想要把这两个东西融合,就是既能监听修改实现热加载,然后用的又是自己的express服务器。网上有两种解决方案:1.设置代理,同时启动express和webpack-dev-server,然后将webpack-dev-server代理到过来。2.利用webpack-hot-middleware和webpack-dev-middleware这两个插件处理编译和热加载。
在这里我选择第二种,因为觉得既然webpack-dev-server本身就是个express服务器,为什么不能把编译和HMR的功能直接用到express上呢。
但是参照https://github.com/webpack-contrib/webpack-hot-middleware/blob/master/example/server.js出现了问题。
var http = require('http');
var express = require('express');
require('console-stamp')(console, "HH:MM:ss.l");
var app = express();
app.use(require('morgan')('short'));
// ************************************
// This is the real meat of the example
// ************************************
(function() {
// Step 1: Create & configure a webpack compiler
var webpack = require('webpack');
var webpackConfig = require(process.env.WEBPACK_CONFIG ? process.env.WEBPACK_CONFIG : './webpack.config');//我这里改成了create-react-app中的webpack.config.dev(需要npm run eject看到)
var compiler = webpack(webpackConfig);
// Step 2: Attach the dev middleware to the compiler & the server
app.use(require("webpack-dev-middleware")(compiler, {
logLevel: 'warn', publicPath: webpackConfig.output.publicPath
}));
// Step 3: Attach the hot middleware to the compiler & the server
app.use(require("webpack-hot-middleware")(compiler, {
log: console.log, path: '/__webpack_hmr', heartbeat: 10 * 1000
}));
})();
// Do anything you like with the rest of your express application.
app.get("/", function(req, res) {
res.sendFile(__dirname + '/index.html');
});
app.get("/multientry", function(req, res) {
res.sendFile(__dirname + '/index-multientry.html');
});
if (require.main === module) {
var server = http.createServer(app);
server.listen(process.env.PORT || 1616, function() {
console.log("Listening on %j", server.address());
});
简单的把config文件替换成webpack.config.dev并不奏效,发现修改js文件时,确实会重新编译但是网页不会刷新,也就是HMR失败
看了webpack-hot-middleware的issue之后找到了问题

通过作者的回答可以看出,html的插件和热加载的api是不兼容的,而create-react-app中的config中用了html-webpack-plugin这个插件,所以要用别的方法来解决这个问题。
在issue里也找到了答案,原理就是用node的chokidar模块来监听index.html的改变,然后主动发送一个reload请求给浏览器,让它刷新
demo地址:https://github.com/thesimpledesigners/webpack-hot-reload-client
首先给webpackHotMiddlewareClient添加监听事件,其中subscribe方法是注册监听事件,之后会用public方法来发布信息,就是js中的观察者模式。payload.action === 'reload'时刷新浏览器
// client.js
(function() {
'use strict';
const webpackHotMiddlewareClient = require('webpack-hot-middleware/client?reload=true'); webpackHotMiddlewareClient.subscribe(function(payload) {
if (payload.action === 'reload' || payload.reload === true) {
window.location.reload();
}
}); module.exports = webpackHotMiddlewareClient;
}());
然后利用chokidar来监听index.html文件,使得其一修改就能让服务器发送一个reload请求
//./devScripts/hotReloader.js
(function() {
'use strict';
const path = require('path');
const chokidar = require('chokidar'); function activate(server) {
/**
* Here, we use Chokidar to force page reloading for some other file types
* like html changes or php if you want
*/
const watcher = chokidar.watch([
path.resolve(__dirname, '../index.html'),// index.html is on the root folder
]);
watcher.on('ready', function() {
console.log('Initial scan complete. Ready for changes');
});
watcher.on('change', function(path) {
console.log('File [' + path + '] changed !');
// reload the client on file changes
server.reloadClient();//这个方法要在服务器实现,就是public一个消息给hotMiddleware
}); } // here we export an activate function to activate the watcher module.exports = { activate: activate, }; }());
服务器代码:
const path = require('path');
// import express
const express = require('express');
// import webpack and the dev & hot middlewares
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
function createServer() {
// Step 1: create the express instance
const app = express();
// Step 2: Create & configure a webpack compiler
const webpackConf = require('../webpack.config.dev.js');
const webpackCompiller = webpack(webpackConf);
const hotMiddleware = webpackHotMiddleware(webpackCompiller);
const devMiddleWare = webpackDevMiddleware(
webpackCompiller,
{
publicPath: webpackConf.output.publicPath,
});
// Step 3: Attach the dev middleware and hot middleware to the server
app.use(devMiddleWare);
app.use(hotMiddleware);
function startServer() {
app.listen(3000, function(err) {
if (err) {
console.error(err);
return;
}
// log server running
console.log('Listening at http://localhost:3000/');
});
}// end function start server
/**
*
*/
function reloadClient() {
hotMiddleware.publish({action: 'reload'});
}// end function RelaodClient
return {
start: startServer,
reloadClient: reloadClient,
};
}
module.exports = createServer();
华丽的分割线--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
总之,你如果想在express中用HMR,并且用create-react-app中webpack.config.dev的配置,只要两步:1.将服务器代码改成下方的app.js这样,2.修改webpack.config.dev中entry的配置
1:我将上面代码精炼了一下,贴一下我的服务端代码app.js
var http = require('http');
var path = require('path');
var session = require('express-session') ;
var express = require('express');
const chokidar = require('chokidar');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const app = express();
app.use(require('morgan')('short'));
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
const webpackConf = require('./config/webpack.config.dev.js');
const webpackCompiller = webpack(webpackConf);
const hotMiddleware = webpackHotMiddleware(webpackCompiller);
const devMiddleWare = webpackDevMiddleware(
webpackCompiller,
{
publicPath: webpackConf.output.publicPath,
});
// Step 3: Attach the dev middleware and hot middleware to the server
app.use(devMiddleWare);
app.use(hotMiddleware);
app.active = ()=>{
const watcher = chokidar.watch([
path.resolve(__dirname, '/public/index.html'),// index.html is on the root folder
]);
watcher.on('ready', function() {
console.log('Initial scan complete. Ready for changes');
});
watcher.on('change', function(path) {
console.log('File [' + path + '] changed !');
// reload the client on file changes
hotMiddleware.publish({action: 'reload'});
});
}
app.active()
// Do anything you like with the rest of your express application.
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(express.static(path.join(__dirname, 'public')));
app.get("/", function(req, res) {
res.sendFile(__dirname + '/public/index.html');
});
app.listen(3000, function(err) {
if (err) {
console.error(err);
return;
}
// log server running
console.log('Listening at http://localhost:3000/');
});
2:然后在webpack.config.dev的entry中这样修改
//require.resolve('react-dev-utils/webpackHotDevClient'),
'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true',
就是把原来它自己写的webpackHotDevClient注释掉,加上后面那句话。
我的demo:https://github.com/jokermask/HMRwithExpress
至此大工告成!
在express中HMR(合并express和webpack-dev-server)的更多相关文章
- 配置Webpack Dev Server 实战操作方法步骤
本文摘要:配置 Webpack Dev Server 可以解决本地开发前端应用时,手动执行 webpack 命令或 yarn build 命令,再去浏览器中访问 dist/index.html 的麻烦 ...
- 笔记:配置 webpack dev server
笔记:配置 webpack dev server 安装 webpack-dev-server 组件 配置 webpack.config.js 配置 增加 html-webpack-plugin 组件 ...
- [Webpack] Access Webpack Dev Server from Mobile Safari on an iPhone
Testing your sites on mobile devices is a critical part of the development process. Webpack dev serv ...
- webpack dev server 和 sublime text 配合时需要注意的地方
参考:https://webpack.js.org/guides/development/ Adjusting Your Text Editor Some text editors have a &q ...
- webpack dev server 配置 启动项目报错Error: listen EADDRINUSE
Error: listen EADDRINUSE 0.0.0.0:5601 它的意思是,端口5601被其他进程占用. 切换端口即可解决问题
- express 中文文档
express() 创建一个express应用程序 var express = require('express'); var app = express(); app.get('/', functi ...
- express中的路由
一.读取静态文件 基本代码: "use strict"; const express = require("express"); let app = expre ...
- 精华 对express中next函数的一些理解
关于next主要从三点来进行说明: next的作用是什么? 我们应该在何时使用next? next的内部实现机制是什么? Next的作用 我们在定义express中间件函数的时候都会将第三个参 ...
- Nodejs express中创建ejs项目,解决express下默认创建jade,无法创建ejs问题
最近在看<Node.js开发指南>,看到使用nodejs进行web开发的时候,准备创建ejs项目遇到问题了, 书上命令为: express -t ejs microblog 可是执行后,仍 ...
随机推荐
- ArcGIS 地类净面积计算工具
地类净面积计算工具可以自己定义图层.字段.地类代码计算任意图层的椭球面积.线状地物扣除.零星扣除和其他扣除,计算地类净面积计算:可以用于二调数据图斑地类.规划地块和基本农田等等需要计算净面积的都可以. ...
- java中方法调用在内存中的体现
在java中,方法以及局部变量(即在方法中声明的变量)是放在栈内存上的.当你调用一个方法时,该方法会放在调用栈的栈顶.栈顶的方法是目前正在执行的方法,直到执行完毕才会从栈顶释放.我们知道,栈是一种执行 ...
- 基于Vue的WebApp项目开发(五)
实现图片分享列表 步骤一:新增图片列表文件photolist.vue <template> <div id="tml"> 图片分享页面 </div&g ...
- centos虚拟机下安装nginx
通过yum安装 yum install epel-release -y(企业级的镜像源) yum install nginx-y 启动.停止.重启 service nginx start servic ...
- 如何安装window7 语言包
很多下载的语言包都是.exe文件,双击后生成lp.cab文件. 这时马上把文件复制到另外一个文件夹中,直接拖最快. 这是 window7 sp1 的很多语言包下载地址(企业版和旗舰版通用):http: ...
- Linux下通过samba进行文件共享与挂载
1.在共享服务端安装samba:# yum install samba samba-client.x86_64 samba-common -y 2.在共享服务端需要防火墙开通139.445端口: # ...
- December 17th 2016 Week 51st Saturday
Great minds have purpose, others only have wishes. 杰出的人有着目标,其他人只拥有愿望. Are you clear about the differ ...
- Io性能分析
一.iostat使用说明 1.命令使用方法 使用ixstat –x 1 可以每隔1秒钟采集所有设备的io信息.其中的1类似于使用“vmstat 1”后面的1. 2.命令格式说明 ―――――――――― ...
- [USACO09MAR]Look Up
嘟嘟嘟 题面说的有点问题,应该是向后看齐. 于是我们维护一个单调递减栈,如果当前a[i]比栈顶元素大,就执行pop操作,然后把pop出来的元素的答案都用 i 更新即可. #include<cst ...
- TensorFlow函数(三)tf.variable_scope() 和 tf.name_scope()
tf.name_scope() 此函数作用是共享变量.在一个作用域scope内共享一些变量,简单来说,就是给变量名前面加个变量空间名,只限于tf.Variable()的变量 tf.variable_s ...