热模块替换概念
热模块替换概念
热模块替换(HMR)会在应用程序运行过程中交换、添加或删除 模块,而无需重新加载整个页面。这可以通过以下几种方式显著加快开发速度:
- 保留在完整重新加载时会丢失的应用程序状态。
- 仅更新已更改的内容,从而节省宝贵的开发时间。
- 当源代码中的 CSS/JS 发生修改时立即更新浏览器,这几乎等同于直接在浏览器开发工具中更改样式。
工作原理
让我们从几个不同的视角来准确理解 HMR 是如何工作的……
在应用程序中
以下步骤允许模块在应用程序中被交换和移除:
- 应用程序请求 HMR 运行时检查更新。
- 运行时异步下载更新并通知应用程序。
- 应用程序随后请求运行时应用更新。
- 运行时同步应用更新。
你可以将 HMR 设置为自动执行此过程,也可以选择需要用户交互才进行更新。
在编译器中
除了正常资源外,编译器还需要输出一个“更新”,以允许从上一个版本更新到新版本。“更新”由两部分组成:
- 更新后的 manifest(JSON)
- 一个或多个更新后的 chunk(JavaScript)
manifest 包含新的编译哈希值以及所有已更新 chunk 的列表。每个 chunk 都包含所有已更新模块的新代码(或指示该模块已被移除的标记)。
编译器确保这些构建之间的模块 ID 和 chunk ID 保持一致。它通常将这些 ID 存储在内存中(例如使用 webpack-dev-server),但也可以将它们存储在 JSON 文件中。
在模块中
HMR 是一个可选功能,仅影响包含 HMR 代码的模块。一个例子是通过 style-loader 修补样式。为了使修补正常工作,style-loader 实现了 HMR 接口;当它通过 HMR 收到更新时,会用新样式替换旧样式。
同样,在模块中实现 HMR 接口时,你可以描述模块更新时应该发生什么。然而,在大多数情况下,并不是每个模块都必须编写 HMR 代码。如果模块没有 HMR 处理程序,更新就会冒泡。这意味着一个单独的处理程序可以更新整个模块树。如果树中的单个模块被更新,则整个依赖集合都会重新加载。
有关 module.hot 接口的详细信息,请参阅 HMR API 页面。
在运行时中
这里的内容会更偏技术一些……如果你对内部机制不感兴趣,可以直接跳到 HMR API 页面 或 HMR 指南。
对于模块系统运行时,会输出额外的代码来跟踪模块的 parents 和 children。在管理方面,运行时支持两种方法:check 和 apply。
check 会向更新 manifest 发起 HTTP 请求。如果请求失败,则没有可用更新。如果成功,会将已更新的 chunk 列表与当前已加载的 chunk 列表进行比较。对于每个已加载的 chunk,会下载相应的更新 chunk。所有模块更新都存储在运行时中。当所有更新 chunk 都已下载并准备好应用时,运行时切换到 ready 状态。
apply 方法将所有已更新的模块标记为无效。对于每个无效模块,该模块或其父模块中必须存在更新处理程序。否则,无效标记会向上冒泡,并使父模块也无效。每次冒泡都会继续进行,直到到达应用的入口点或具有更新处理程序的模块(以先到者为准)。如果它从入口点冒泡,则过程失败。
之后,所有无效模块都会被销毁(通过 dispose 处理程序)并卸载。然后更新当前哈希值并调用所有 accept 处理程序。运行时切换回 idle 状态,一切照常继续。
开始使用
HMR 可以在开发中用作 LiveReload 的替代方案。webpack-dev-server 支持 hot 模式,在该模式下,它会先尝试使用 HMR 进行更新,然后再尝试重新加载整个页面。有关详细信息,请参阅 Hot Module Replacement 指南。
与许多其他功能一样,webpack 的强大之处在于其可定制性。根据特定项目的需求,有 多种 配置 HMR 的方式。然而,对于大多数用途,
webpack-dev-server是一个很好的选择,可以让您快速开始使用 HMR。
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
