Webpack 中的热module替换到底是什么?
首先,我想指出,热module更换 (HMR) 仍然是一项实验性功能。
HMR 是一种在正在运行的应用程序中交换module的方式(以及添加/删除module)。您基本上可以在不重新加载整页的情况下更新更改的module。
文档
先决条件:
- 使用插件:https : //webpack.js.org/concepts/plugins/
- 代码拆分:https : //webpack.js.org/guides/code-splitting/
- webpack-dev-server: https://webpack.js.org/configuration/dev-server/
对于 HMR 来说,这不是很多,但这里是链接:
- 示例:https : //webpack.js.org/guides/hot-module-replacement/
- API:https : //webpack.js.org/concepts/hot-module-replacement/
我会将这些答案添加到文档中。
它是如何工作的?
从应用程序视图
应用程序代码要求 HMR 运行时检查更新。HMR 运行时下载更新(异步)并告诉应用程序代码有可用更新。应用程序代码要求 HMR 运行时应用更新。HMR 运行时应用更新(同步)。应用程序代码在此过程中可能需要也可能不需要用户交互(由您决定)。
从编译器(webpack)来看
除了正常的资产,编译器需要发出“更新”以允许从以前的版本更新到这个版本。“更新”包含两部分:
- 更新清单 (json)
- 一个或多个更新块(js)
清单包含新的编译哈希和所有更新块的列表 (2)。
更新块包含此块中所有更新module的代码(如果module被删除,则包含一个标志)。
编译器还确保这些构建之间的module和块 ID 是一致的。它使用“记录”json 文件在构建之间存储它们(或将它们存储在内存中)。
从module来看
HMR 是一项可选功能,因此它仅影响包含 HMR 代码的module。该文档描述了module中可用的 API。通常,module开发人员编写在更新此module的依赖项时调用的处理程序。他们还可以编写一个在此module更新时调用的处理程序。
在大多数情况下,并不是必须在每个module中编写 HMR 代码。如果module没有 HMR 处理程序,则更新会冒泡。这意味着单个处理程序可以处理完整module树的更新。如果此树中的单个module被更新,则重新加载整个module树(仅重新加载,不传输)。
从 HMR 运行时视图(技术)
为module系统运行时发出附加代码以跟踪moduleparents
和children
.
在管理方面,运行时支持两种方法:check
和apply
。
Acheck
向更新清单发出 HTTP 请求。当此请求失败时,没有可用的更新。否则,将更新块的列表与当前加载的块列表进行比较。对于每个加载的块,下载相应的更新块。所有module更新都作为更新存储在运行时中。运行时切换到ready
状态,这意味着更新已下载并准备好应用。
对于处于就绪状态的每个新块请求,也会下载更新块。
该apply
方法将所有更新的module标记为无效。对于每个无效module,module中都需要有一个更新处理程序,或者每个父module中都需要有更新处理程序。否则无效的冒泡并将所有父母也标记为无效。这个过程一直持续到不再出现“冒泡”为止。如果它冒泡到入口点,则该过程失败。
现在所有无效module都被处理(处理处理程序)并卸载。然后更新当前散列并调用所有“接受”处理程序。运行时切换回idle
状态,一切照常进行。
我可以用它做什么?
您可以在开发中使用它作为 LiveReload 的替代品。实际上 webpack-dev-server 支持热模式,它会在尝试重新加载整个页面之前尝试使用 HMR 进行更新。您只需要添加webpack/hot/dev-server
入口点并使用--hot
.
您还可以在生产中将其用作更新机制。在这里,您需要编写自己的管理代码,将 HMR 与您的应用程序集成。
一些加载器已经生成了可热更新的module。egstyle-loader
可以交换样式表。你不需要做任何特别的事情。
假设我想在将 CSS(一个样式表)和 JS module保存到磁盘时更新它们,而无需重新加载页面,也无需使用 LiveReload 等插件。这是热module更换可以帮助我的东西吗?
是的
我需要做什么样的工作,HMR 已经提供了什么?
这是一个小例子:https : //webpack.js.org/guides/hot-module-replacement/
一个module只有在你“接受”它的情况下才能被更新。所以你需要module.hot.accept
在父母或父母的父母中的module......例如路由器是一个好地方,或子视图。
如果您只想将它与 webpack-dev-server 一起使用,只需添加webpack/hot/dev-server
为入口点。否则,您需要一些 HMR 管理代码,调用check
和apply
.
意见:是什么让它如此酷?
- 它是 LiveReload,但适用于每种module类型。
- 您可以在生产中使用它。
- 更新尊重您的代码拆分,并且只下载应用程序使用部分的更新。
- 您可以将其用于应用程序的一部分,并且不会影响其他module
- 如果 HMR 被禁用,编译器会删除所有 HMR 代码(将其包装在 中
if(module.hot)
)。
注意事项
- 它是实验性的,没有经过很好的测试。
- 期待一些错误。
- 理论上可用于生产,但将其用于严肃的事情可能还为时过早。
- 需要在编译之间跟踪module ID,因此您需要存储它们 (
records
)。 - 优化器在第一次编译后不能再优化module ID。对包大小有一点影响。
- HMR 运行时代码增加了包的大小。
- 对于生产用途,需要额外的测试来测试 HMR 处理程序。这可能非常困难。
尽管接受的答案正确地解释了一切,但以下描述应该有助于更快地了解 HMR 是什么。
本质上(简而言之!) -它通过在运行时用更改替换module来减少页面刷新次数来帮助开发。
在搜索 HMR 时,我发现了一篇解释概念错误的文章,它很长,所以这里有一个 GIF 图像,无需太多文字就可以解释这个概念。
在这里它起作用了——请注意计时器不会像页面重新加载后那样重置为 0,并且 css 也会更改自动刷新。
Webpack 有助于实现 HMR。你可以在这里找到文档
它有助于实现以下目标:
在重新加载期间保留应用程序状态(没有 HMR 总是丢失)
通过仅更新更改的内容来节省宝贵的开发时间。
更快地调整样式——几乎可以与在浏览器调试器中更改样式相媲美。
这是实现 HMR 的 webpack 指南