Express结合Webpack的全栈自动刷新(2)

参考webpack-hot-middleware的文档示例,我们把这2个middleware添加到Express中。

webpack配置文件部分

首先,修改webpack的配置文件(为了方便查看,这里贴出了webpack.config.js的全部代码):

var webpack = require('webpack'); var path = require('path'); var publicPath = 'http://localhost:3000/'; var hotMiddlewareScript = 'webpack-hot-middleware/client?reload=true'; var devConfig = { entry: { page1: ['./client/page1', hotMiddlewareScript], page2: ['./client/page2', hotMiddlewareScript] }, output: { filename: './[name]/bundle.js', path: path.resolve('./public'), publicPath: publicPath }, devtool: 'source-map', module: { loaders: [{ test: /\.(png|jpg)$/, loader: 'url?limit=8192&context=client&name=[path][name].[ext]' }, { test: /\.scss$/, loader: 'style!css?sourceMap!resolve-url!sass?sourceMap' }] }, plugins: [ new webpack.optimize.OccurenceOrderPlugin(), new webpack.HotModuleReplacementPlugin(), new webpack.NoErrorsPlugin() ] }; module.exports = devConfig;

这是一个包含多个entry的较复杂的例子。其中和webpack-hot-middleware有关的有两处。一是plugins的位置,增加3个插件,二是entry的位置,每一个entry后都增加一个hotMiddlewareScript。

hotMiddlewareScript的值是webpack-hot-middleware/client?reload=true,其中?后的内容相当于为webpack-hot-middleware设置参数,这里reload=true的意思是,如果碰到不能hot reload的情况,就整页刷新。

在这个配置文件中,还有一个要点是publicPath不是/这样的值,而是:3000/这样的绝对地址。这是因为,在使用?sourceMap的时候,style-loader会把css的引入做成这样:

Express结合Webpack的全栈自动刷新

这种blob的形式可能会使得css里的url()引用的图片失效,因此建议用带http的绝对地址(这也只有开发环境会用到)。有关这个问题的详情,你可以查看github上的issue。

Express启动文件部分

接下来是Express启动文件内添加以下代码:

var webpack = require('webpack'), webpackDevMiddleware = require('webpack-dev-middleware'), webpackHotMiddleware = require('webpack-hot-middleware'), webpackDevConfig = require('./webpack.config.js'); var compiler = webpack(webpackDevConfig); // attach to the compiler & the server app.use(webpackDevMiddleware(compiler, { // public path should be the same with webpack config publicPath: webpackDevConfig.output.publicPath, noInfo: true, stats: { colors: true } })); app.use(webpackHotMiddleware(compiler));

以上这段代码应该位于Express的routes代码之前。其中,webpack-dev-middleware配置的publicPath应该和webpack配置文件里的一致。

webpack-dev-middleware和webpack-hot-middleware的静态资源服务只用于开发环境。到了线上环境,应该使用express.static()。

到此,client部分的目标就完成了。现在到网页里打开控制台,应该可以看到[HMR] connected的提示。这个项目中我只要求css使用HMR,如果你希望javascript也使用HMR,一个简单的做法是在entry文件内添加以下代码:

if(module.hot) { module.hot.accept(); }

这样,与这个entry相关的所有.js文件都会使用hot reload的形式。关于这一点的更多详情,请参考hot module replacement

接下来是server部分。

reload和supervisor

server部分的自动刷新,会面临一个问题:自动刷新的消息通知依靠的是浏览器和服务器之间的web socket连接,但在server部分修改代码的话,一般都要重启服务器来使变更生效(比如修改routes),这就会断开web socket连接。

所以,这需要一个变通的策略:浏览器这边增加一个对web socket断开的处理,如果web socket断开,则开启一个稍长于服务器重启时间的定时任务(setTimeout),相当于等到服务器重启完毕后,再进行一次整页刷新。

reload是一个应用此策略的组件,它可以帮我们处理服务器重启时的浏览器刷新。

现在,还差一个监听server文件,如果有变更就重启服务器的组件。参考reload的推荐,我们选用supervisor

下面将reload和supervisor引入到Express项目内。

监听文件以重启服务器

通过以下代码安装supervisor(是的,必须-g):

npm install supervisor -g

然后,在package.json里设置新的scripts:

"scripts": { "start": "cross-env NODE_ENV=dev supervisor -i client app" }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/782b4cdf7741b3a5d86f7ce9e4ab46cb.html