Webpack中的热模块替换到底是什么?

2022-08-30 00:06:51

我已经阅读了几关于Webpack中的热模块替换。
甚至还有一个使用它的示例应用程序

我已经阅读了所有这些内容,但仍然不明白这个想法。

我能用它做什么?

  1. 它是否应该只在开发中使用,而不是在生产中使用?
  2. 它像LiveReload一样,但你必须自己管理它吗?
  3. WebpackDevServer是否以某种方式与LiveReload集成?

假设我想在将CSS(一个样式表)和JS模块保存到磁盘时更新它们,而无需重新加载页面,也无需使用LiveReload等插件。这是热模块更换可以帮助我的事情吗?我需要做什么样的工作,HMR已经提供了什么?


答案 1

首先,我想指出,热模块更换(HMR)仍然是一个实验性功能。

HMR 是一种在正在运行的应用程序中交换模块(以及添加/删除模块)的方法。您基本上可以更新更改的模块,而无需重新加载整个页面。

文档

先决条件:

对于HMR来说,这并不是那么多,但这里有一些链接:

我会将这些答案添加到文档中。

它是如何工作的?

从应用程序视图

应用代码要求 HMR 运行时检查更新。HMR 运行时下载更新(异步),并告知应用代码有可用的更新。应用代码要求 HMR 运行时应用更新。HMR 运行时应用更新(同步)。在此过程中,应用代码可能需要也可能不需要用户交互(由您决定)。

从编译器(webpack)视图

除了普通资产之外,编译器还需要发出“更新”以允许从以前的版本更新到此版本。“更新”包含两部分:

  1. 更新清单 (json)
  2. 一个或多个更新块 (js)

清单包含新的编译哈希和所有更新块的列表 (2)。

更新块包含此块中所有已更新模块的代码(如果模块已被删除,则包含一个标志)。

编译器还确保这些生成之间的模块和块 ID 是一致的。它使用“记录”json文件在构建之间存储它们(或将它们存储在内存中)。

从模块视图

HMR 是一项选择加入功能,因此它仅影响包含 HMR 代码的模块。本文档介绍了模块中可用的 API。通常,模块开发人员编写在更新此模块的依赖项时调用的处理程序。他们还可以编写一个处理程序,该处理程序在更新此模块时调用。

在大多数情况下,在每个模块中编写HMR代码不是强制性的。如果模块没有 HMR 处理程序,则更新会冒泡。这意味着单个处理程序可以处理完整模块树的更新。如果更新此树中的单个模块,则重新加载整个模块树(仅重新加载,而不传输)。

从 HMR 运行时视图(技术)

为模块系统运行时发出其他代码以跟踪模块 和 。parentschildren

在管理端,运行时支持两种方法:和 。checkapply

A 对更新清单执行 HTTP 请求。当此请求失败时,没有可用的更新。此外,将更新的块列表与当前加载的块的列表进行比较。对于每个加载的块,将下载相应的更新块。所有模块更新都作为更新存储在运行时中。运行时将切换到状态,这意味着更新已下载并已准备好应用。checkready

对于处于就绪状态的每个新块请求,还会下载更新块。

该方法将所有更新的模块标记为无效。对于每个无效模块,模块中需要有一个更新处理程序,或者每个父级中都需要有一个更新处理程序。否则,无效的气泡也会冒出来,并将所有父母标记为无效。这个过程一直持续到不再发生“泡沫”。如果它冒泡到入口点,则该过程将失败。apply

现在,所有无效模块都将被释放(释放处理程序)并卸载。然后更新当前哈希并调用所有“接受”处理程序。运行时将切换回状态,一切照常进行。idle

generated update chunks

我能用它做什么?

您可以在开发中将其用作 LiveReload 的替代品。实际上,webpack-dev-server支持一种热模式,该模式在尝试重新加载整个页面之前尝试使用HMR进行更新。您只需添加入口点并使用 调用开发服务器。webpack/hot/dev-server--hot

您还可以在生产中将其用作更新机制。在这里,您需要编写自己的管理代码,将HMR与您的应用程序集成。

一些加载程序已经生成了可热更新的模块。例如,可以交换样式表。您无需执行任何特殊操作。style-loader

假设我想在将CSS(一个样式表)和JS模块保存到磁盘时更新它们,而无需重新加载页面,也无需使用LiveReload等插件。这是热模块更换可以帮助我的事情吗?

是的

我需要做什么样的工作,HMR已经提供了什么?

下面是一个小例子:https://webpack.js.org/guides/hot-module-replacement/

只有“接受”模块,才能更新它。所以你需要模块在父母或父母的父母...例如,路由器是一个好地方,或者是一个子视图。module.hot.accept

如果您只想将其与webpack-dev-server一起使用,只需添加为入口点即可。否则,您需要一些调用 和 的 HMR 管理代码。webpack/hot/dev-servercheckapply

评论:是什么让它如此酷?

  • 它是LiveReload,但适用于每种模块类型。
  • 您可以在生产环境中使用它。
  • 这些更新遵循你的代码拆分,并且仅下载应用的已用部分的更新。
  • 您可以将其用于应用程序的一部分,并且不会影响其他模块
  • 如果禁用 HMR,编译器将删除所有 HMR 代码(将其包装在 中)。if(module.hot)

警告

  • 这是实验性的,没有经过很好的测试。
  • 期待一些错误。
  • 理论上可以在生产中使用,但现在将其用于严肃的事情可能还为时过早。
  • 需要在编译之间跟踪模块 ID,因此您需要存储它们 ()。records
  • 在第一次编译后,优化程序无法再优化模块 ID。对捆绑包大小有一点影响。
  • HMR 运行时代码会增加捆绑包大小。
  • 对于生产用途,需要进行其他测试来测试 HMR 处理程序。这可能非常困难。

答案 2

尽管接受的答案正确解释了所有内容,但以下描述应该有助于更快地理解HMR是什么。

从本质上讲(简而言之!) - 它通过在运行时用更改替换模块来减少页面刷新次数来帮助开发。

在搜索HMR时,我发现了一解释该概念的文章,但它很长,所以这里有一个GIF图像,可以不用很多词来解释这个概念。

在这里,它正在工作 - 请注意,计时器不会像页面重新加载后那样重置为0,并且CSS也会更改自动刷新。Hot Module Replacement GIF

Webpack有助于实现HMR。您可以在此处找到文档

它有助于实现以下目标:

  • 在重新加载期间保留应用程序状态(如果没有 HMR,应用程序状态始终会丢失)

  • 通过仅更新更改的内容来节省宝贵的开发时间。

  • 更快地调整样式 - 几乎与在浏览器调试器中更改样式相当。

这是实现HMR的网络包指南