介绍一下webpack hmr相关的API
webpack首先将模块变成对象的一个属性,该属性是一个方法,调用它就返回最新的模块。模块的变更就变成了更新这些方法的定义。其次,webpack对于我们代码的import,做了拦截,会变成从它的模块对象里面去读取模块,同时它做了缓存。最后,当模块变化的时候,它会依次查询导入该模块的其他模块,查找调用hmr的相关API.直到这个递归的过程被终结。更事件的冒泡原理类似。
module.hot.accept(dependencies,callback,errorHandler)
意思是当依赖项有变化,webpack会自动执行我们提供的callback逻辑进行更新。这个函数只会检测依赖模块的变更,它本身的变更不归这个函数管理。而且它处理完了,变更的冒泡就终止了。
- dependencies,是当前模块的依赖项。也是我们监听的依赖项,如果有些依赖项模块没有被包含到这个数组里面,即使它变化了,也不会触发callback的执行。
- 文档中说,dependeicies 一定要与我们在import里面的写法完全一致。因为这个有点类似与模块的名字。
- 文档里还说,如果我们的模块是ESM,则这些依赖的模块以及自动更新了。问题是谁帮我更新了这些依赖模块,怎么更新的。
- 首先,模块通过webpack的打包,模块已经变成了对象,
__webpack_modules={'./moduleA.js':(module,module.exports,__webpack_require__)=>{moduleAContent}}
。所以模块的逻辑变更就变成了对象的变更 - 其次,如果我们查看hmr bundle里面的源码,我们会发现下面的代码。也就是说webpack hmr在我们的callback 函数前面加上了
__wepack_require('./moduleA.js')
,这样就强制拿到了最新的模块代码。
- 首先,模块通过webpack的打包,模块已经变成了对象,
module.hot.accept("./moduleA.js",
__WEBPACK_OUTDATED_DEPENDENCIES__ => {
// 下面这个代码就是webpack 添加的执行依赖模块的方法
_moduleB_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./moduleA.js"); // 这段代码就是webpack添加的,我们在第一个参数里面定义的依赖模块的函数,在这里被执行了。
// bellow is wrap of callback 我们自己提供了的。
(()=>{
xxxxxxfunc();
})(__WEBPACK_OUTDATED_DEPENDENCIES__);
})
- callback, 我们提供的更新的函数,就是,当模块更新了,我们该做什么更新逻辑。
module.hot.accept()
当这个模块有变更或者它的依赖项有变更,变更冒泡到它这一层,就无脑的将当前模块重新执行一遍。然后变更的冒泡就终止了。
module.hot.decline(dependencies)
当依赖项的变更信息传递到当前模块,则标记hmr失败。意味着,我们需要做full-reload.也就是说,不支持hmr。
module.hot.declien()
当前模块如果有变更信息,则标记hmr失败。
module.hot.dispose((data)=>{})
当前的模块被删除掉,然后新的模块会被加载的时候。它发生在当前模块被卸载的时候,我们可以传递一些状态到data对象中。当我们被加载的时候,我们可以从module.hot.data
里面读取一些状态。这个主要用于卸载模块的时候进行清理用的。
module.hot.invalidate()
标记当前的模块有改动,让hmr 对它进行卸载再加载的操作。
介绍一下hmr工作过程中的状态变迁
- 它的状态可以通过
module.hot.status()
获取到。- idle 空闲状态
- check 检查更新,它会将当前的hash code 发送到后端。它会发送一个
[chunkname].[hashcode].hot-update.json
这样一个请求从而获得需要更新的模块名 - prepare 准备,包括下载更新代码。它会请求脚本
[chunkname].[hashcode].hot-update.js
。脚本的内容是调用webpackHotUpdatewpselfhmr(chunkname,obj,updatehashcodeFunc)
,这个obj就算需要更新的代码。第三个函数就是更新最新的代码hash. - ready 一切准备工作都好了。
- dispose hmr对于那些需要被替换的模块,调用他们的dispose注册的方法
- apply 对于更新的模块,会去调用他们的accept方法以及不带参数的accept方法,达到自更新
- abort 更新被中断了
- fail 更新失败