webpack实现HMR热加载

“热模块替换”(HMR)是在某个功能活动运行时注入更新的模块。

就像对每一个模块进行LiveReload

也就是说,在开发过程中,我们不用刷新页面,就能实现局部的更新,无论是css代码,还是js代码。

webpack实现HMR热加载

实现webpack HMR需要通过webpack的两个中间件,即webpack-dev-middlewarewebpack-hot-middleware

webpack-dev-middleware是什么:

The webpack-dev-middleware is a small middleware for a connect-based middleware stack. It uses webpack to compile assets in-memory and serve them. When a compilation is running every request to the served webpack assets is blocked until we have a stable bundle.

可以看出webpack-dev-middleware是一个中间件,负责把webpack打包的bundle生成在内存中,而不在磁盘里,而且在其生成稳定的包之前,编译将被阻塞(使网页更新有貌似网络延迟的效果),如此一来我们就不需要去关心编译是否完成了。

webpack-hot-middleware是什么:

This module is only concerned with the mechanisms to connect a browser client to a webpack server & receive updates. It will subscribe to changes from the server and execute those changes using webpack’s HMR API. Actually making your application capable of using hot reloading to make seamless changes is out of scope, and usually handled by another library.

webpack-dev-middleware用来在浏览器客户端和webpack服务端进行连接,监听服务端改变的文件,然后
实现浏览器客户端的热加载。


我写了个 例子 简单实现了HMR。

首先,先安装npm模块(这里我们用express作为服务器):

npm i express webpack webpack-dev-middleware webpack-hot-middleware --save-dev

然后,编写webpack.config.js:

//增加三个插件,并在入口文件后增加一段代码
var path = require('path'),
    webpack =require('webpack');
var config = {
    entry: 
    ["./src/a.js",
    'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000',
    ],
    output: {
        path: path.resolve(__dirname, './output/'),
        filename:'bundle.js',
    },
    plugins: [
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin()
    ]
}

module.exports = config;

然后给express配置中间件:

var express = require('express'),
    app = express(),
    webpack = require('webpack'),
    config = require('./webpack.config.js'),
    webpackDevMiddleware = require('webpack-dev-middleware'),
    webpackHotMiddleware = require('webpack-hot-middleware');


//如果有回调函数并且没有中间件插件则直接运行webpack。如果没有回调函数或没有中间件插件则不直接执行webpack。
var compiler = webpack(config, function() {
    console.log('done')
}); 

/*这里设置bundle生成位置,注意是生成在内存中,由于我们设置了静态目录'output',
所以这里实际上的网络位置是localhost:8080/,文件位置是 根目录/output */
var options = {
    publicPath: "/",
}

app.use(webpackDevMiddleware(compiler, options));
app.use(webpackHotMiddleware(compiler));
app.use(express.static('output'))
app.listen(8080, function() {
    console.log('Example app listening on!')
})

最后在需要热加载的文件下加入(案例中是a.js):

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

准备就绪,运行:

npm start

浏览器打开localhost:8080 ,会看到控制台输出

[HMR] connected

代表热加载连接成了!

我们点击按钮,弹出1。此时我们尝试修改b.js,把alert(1)改为alert(2),回到浏览器,发现浏览器并没有刷新,再次点击按钮,弹出了2!浏览器在不刷新的情况下,更新了js文件!