nocas配置中心热更新原理_轻松理解webpack热更新原理

(2)webpack/hot/dev-server.js

这个文件主要是用于检查更新逻辑的,这里大家知道就好,代码后面会在合适的时机(第5步)细讲。

3. 监听webpack编译结束

修改好入口配置后,又调用了setupHooks方法。这个方法是用来注册监听事件的,监听每次webpack编译完成。

//node_modules/webpack-dev-server/lib/Server.js//绑定监听事件

setupHooks() {

const {done}=compiler.hooks;//监听webpack的done钩子,tapable提供的监听方法

done.tap('webpack-dev-server', (stats) =>{this._sendStats(this.sockets, this.getStats(stats));this._stats =stats;

});

};

当监听到一次webpack编译结束,就会调用_sendStats方法通过websocket给浏览器发送通知,ok和hash事件,这样浏览器就可以拿到最新的hash值了,做检查更新逻辑。

//通过websoket给客户端发消息

_sendStats() {this.sockWrite(sockets, 'hash', stats.hash);this.sockWrite(sockets, 'ok');

}

4. webpack监听文件变化

每次修改代码,就会触发编译。说明我们还需要监听本地代码的变化,主要是通过setupDevMiddleware方法实现的。

这个方法主要执行了webpack-dev-middleware库。很多人分不清webpack-dev-middleware和webpack-dev-server的区别。其实就是因为webpack-dev-server只负责启动服务和前置准备工作,所有文件相关的操作都抽离到webpack-dev-middleware库了,主要是本地文件的编译和输出以及监听,无非就是职责的划分更清晰了。

那我们来看下webpack-dev-middleware源码里做了什么事:

//node_modules/webpack-dev-middleware/index.js

compiler.watch(options.watchOptions, (err) =>{if (err) { /*错误处理*/}

});//通过“memory-fs”库将打包后的文件写入内存

setFs(context, compiler);

(1)调用了compiler.watch方法,在第 1 步中也提到过,compiler的强大。这个方法主要就做了 2 件事:

首先对本地文件代码进行编译打包,也就是webpack的一系列编译流程。

其次编译结束后,开启对本地文件的监听,当文件发生变化,重新编译,编译完成之后继续监听。

为什么代码的改动保存会自动编译,重新打包?这一系列的重新检测编译就归功于compiler.watch这个方法了。监听本地文件的变化主要是通过文件的生成时间是否有变化,这里就不细讲了。

(2)执行setFs方法,这个方法主要目的就是将编译后的文件打包到内存。这就是为什么在开发的过程中,你会发现dist目录没有打包后的代码,因为都在内存中。原因就在于访问内存中的代码比访问文件系统中的文件更快,而且也减少了代码写入文件的开销,这一切都归功于memory-fs。

5. 浏览器接收到热更新的通知

我们已经可以监听到文件的变化了,当文件发生变化,就触发重新编译。同时还监听了每次编译结束的事件。当监听到一次webpack编译结束,_sendStats方法就通过websoket给浏览器发送通知,检查下是否需要热更新。下面重点讲的就是_sendStats方法中的ok和hash事件都做了什么。

那浏览器是如何接收到websocket的消息呢?回忆下第 2 步骤增加的入口文件,也就是websocket客户端代码。

'xxx/node_modules/webpack-dev-server/client/index.js?http://localhost:8080'

这个文件的代码会被打包到bundle.js中,运行在浏览器中。来看下这个文件的核心代码吧。

//webpack-dev-server/client/index.js

var socket = require('./socket');var onSocketMessage ={

hash:functionhash(_hash) {//更新currentHash值

status.currentHash =_hash;

},

ok:functionok() {

sendMessage('Ok');//进行更新检查等操作

reloadApp(options, status);

},

};//连接服务地址socketUrl,?http://localhost:8080,本地服务地址

socket(socketUrl, onSocketMessage);functionreloadApp() {if(hot) {

log.info('[WDS] App hot update...');//hotEmitter其实就是EventEmitter的实例

var hotEmitter = require('webpack/hot/emitter');

hotEmitter.emit('webpackHotUpdate', currentHash);

}

}

socket方法建立了websocket和服务端的连接,并注册了 2 个监听事件。

hash事件,更新最新一次打包后的hash值。

ok事件,进行热更新检查。

热更新检查事件是调用reloadApp方法。比较奇怪的是,这个方法又利用node.js的EventEmitter,发出webpackHotUpdate消息。这是为什么?为什么不直接进行检查更新呢?

个人理解就是为了更好的维护代码,以及职责划分的更明确。websocket仅仅用于客户端(浏览器)和服务端进行通信。而真正做事情的活还是交回给了webpack。

那webpack怎么做的呢?再来回忆下第 2 步。入口文件还有一个文件没有讲到,就是:

'xxx/node_modules/webpack/hot/dev-server.js'

这个文件的代码同样会被打包到bundle.js中,运行在浏览器中。这个文件做了什么就显而易见了吧!先瞄一眼代码:

//node_modules/webpack/hot/dev-server.js

var check = functioncheck() {

module.hot.check(true)

.then(function(updatedModules) {//容错,直接刷新页面

if (!updatedModules) {

window.location.reload();return;

}//热更新结束,打印信息

if(upToDate()) {

log("info", "[HMR] App is up to date.");

}

})

.catch(function(err) {

window.location.reload();

});

};var hotEmitter = require("./emitter");

hotEmitter.on("webpackHotUpdate", function(currentHash) {

lastHash=currentHash;

check();

});

这里webpack监听到了webpackHotUpdate事件,并获取最新了最新的hash值,然后终于进行检查更新了。检查更新呢调用的是module.hot.check方法。那么问题又来了,module.hot.check又是哪里冒出来了的!答案是HotModuleReplacementPlugin搞得鬼。这里留个疑问,继续往下看。

6. HotModuleReplacementPlugin

前面好像一直是webpack-dev-server做的事,那HotModuleReplacementPlugin在热更新过程中又做了什么伟大的事业呢?

首先你可以对比下,配置热更新和不配置时bundle.js的区别。内存中看不到?直接执行webpack命令就可以看到生成的bundle.js文件啦。不要用webpack-dev-server启动就好了。

(1)没有配置的。

(2)配置了HotModuleReplacementPlugin或--hot的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值