[译] Webpack 用来做模块热替换(hot module replacement)

转载 2015年11月20日 10:39:53

翻译地粗糙, 英文好请直接看原文

原文 https://github.com/webpack/docs/wiki/hot-module-replacement-with-webpack


注意模块热替换(HMR)依然是试验性的功能

介绍

模块热替换(HMR)交换, 添加, 或者删除模块, 同时应用持续运行, 不需要页面刷新.

准备工作

它是怎样工作的?

从 App 的角度

App 代码请求 HMR 运行时检查更新.
HMR 运行时会下载(异步)更新的代码, 通知 App 代码运行已经可用.
App 代码请求 HMR 运行时应用更新.
HMR 运行时应用更新(同步).
这个过程, App 代码可以也可以不依赖用户操作(看需要).

从编译器(Webpack)角度

除了普通的静态文件, 编译器触发 "Update" 进行版本更新.
"Update" 包含两个部分:

  1. 更对内容的 manifest (JSON)

  2. 一个或者多个关于更新的 chunks (js)

manifest 包含新的编译结果的 Hash 和列表储存的 chunks (2.).

更新的 chunks 包含 chunk 当中所有更新掉的模块的代码
(或者模块已经被移除的标记)

编译器额外会保证模块和 chunk 的 id 在多个建构当中一致
它使用 "records" JSON 文件在建构之间保存它们(或者存储在内存里)

从模块角度

HMR 是个可选功能, 它只影响包含 HMR 代码的模块
文件里描述了模块中可用的 API
通常模块开发者写的处理器代码会在这个模块的依赖更新时被调用
他也可以写个处理器, 在当前模块更新时被调用

大多数情况不会强制在每个模块里写上 HMR 代码
如果一个模块不包含 HMR 处理器, 更新事件就会向上冒泡
意味着单个处理器可以处理整个模块树的更新
如果树当中单个模块被更新, 整个模块树就会重新(刷新而不是 transferred(转移?))

从 HMR运行时角度(技术的)

对模块系统而言, 运行时意味着插入额外的代码来追踪模块的父节点子节点

管理层面, 运行时支持两个方法: check 和 apply

check 发起 HTTP 请求去获取更新的 manifest
请求失败时, 意味着没有可用的更新
否则将能返回更新的 chunks 的列表, 和当前已加载的 chunks 列表做对比
每个被更新的 chunk 对应的更新后的 chunk 都会被下载
所有存储在运行时当中的代码模块随着代码进行更新
运行时会切换到 ready 状态, 表明更新已经被下载并准备好应用

对于每个 ready 状态的新的 chunk 请求来说, 更新的 chunk 也已经被下载好了

apply 方法标记所有更新过的模块为 invalid
每个 invalid 模块需要有个 update 处理器, 在模块中或者在每个父节点
不然 invalid 向上冒泡, 多有的父节点也被标记为 invalid
这个步骤持续知道不再有"冒泡"出现
如果冒泡到了 entry point 就说明过程失败了

现在所有 invalid 模块会被处置(dispose 处理器)和卸载
随后当前的 hash 被更新, 所有的 "accept" 处理器被调用
运行时切换回到 "idle" 状态, 一切继续正常运行

生成的文件(技术的)

左侧表示初始的编译器流程
右侧表示当模块 4 和 9 更新的流程

用这个能做到什么?

你可以在开发环境中用作 LiveReload 的替代
实际上 webpack-dev-server 支持一个 hot 状态,
会尝试先去通过 HMR 更新然后可能尝试刷新整个页面
你只需要加上一个 webpack/hot/dev-server entry point,
并且在 dev-server 调用时加上参数 --hot

webpack/hot/dev-server 在 HMR 更新失败之后会刷新整个页面
如果你想自己刷新页面, 可以改用 webpack/hot/only-dev-server 这个 entry point.

你也可以将其用作生产环境的更新机制
这里你需要写你自己的管理代码集成 HMR 到你的应用当中

一些模块已经可以生成可以完成热替换的模块
比如 style-loader 可以替换样式. 你不需要特别做事情

使用它需要怎么做?

模块只有在你的 "accept" 他的时候才能被更新
所以你需要在父节点或者父节点的父节点... module.hot.accept 调用模块
比如 router 是个不错的地方, 或者一个 subview 当中

如果你只是要和 webpack-dev-server 一起用,
就加上 webpack/hot/dev-server 这个 entry point
不然你会需要一些 HMR 管理代码去调用 check 和 apply

你需要在编译器里开启 records 用来记录不同过程的模块 id
(watch 模块和 webpack-dev-server 在内存里追踪 records
所以在开发当中你不需要做)

你需要开启编译器的 HMR 让它加上 HMR 运行时

什么让它很酷?

  • 它是对于每个模块而言的 LiveReload

  • 你可以在生产环境使用

  • 它依据你的代码分割来更新, 只下载应用中需要更新的部分

  • 你可以用在应用的布局, 不会影响到其他的模块

  • 如果 HMR 被禁用, 所有的 HMR 代码会被编译器移除(包括在 if(module.hot) 中)

警告

  • 它属于试验性功能, 测试不够

  • 预计有一些 bug

  • 理论上可用在生成环境, 然而在严肃的场合或许太早

  • 模块 id 需要在多个编译过程被追踪, 你需要存储(records)

  • 优化器在第一次优化之后不再能够优化模块 id. 对 bundle 体积有影响

  • HMR 运行时增加了 bundle 的体积

  • 生成环境需要额外的测试代码检验 HMR 处理器. 挺难做的.

教程

使用 Webpack 代码热替换需要做 4 件事:

  • records (--records-pathrecordsPath: ...)

  • 全局开启代码热替换 (HotModuleReplacementPlugin)

  • 在你的代码中插入热替换代码 module.hot.accept

  • 在你的代码中插入热替换代码 module.hot.checkmodule.hot.apply

一个小测试:

/* style.css */
body {
    background: red;
}
/* entry.js */
require("./style.css");
document.write("<input type='text' />");

这已经足够在 dev-server 中使用代码热替换

npm install webpack webpack-dev-server -g
npm install webpack css-loader style-loader
webpack-dev-server ./entry --hot --inline --module-bind "css=style!css"

dev-server 提供内存里的 records, 对开发来说很好

--hot 选项开启了代码热替换.

这能够加上 HotModuleReplacementPlugin. 如果使用命令行就不用写到 webpack.config.js

在 webpack/hot/dev-server 有 dev-server 特殊的管理代码,
它会通过 --inline 自动加入.
(你不一定要在 webpack.config.js 里加上)

style-loader 已经包含了热替换相关代码.

随后访问 http://localhost:8080/bundle
的你应该能看到红色背景和 input 框, 输入些文字, 编辑下 style.css 改颜色

Voilà... 不需要刷新整个页面, 背景更新了. 输入框的文字和选区应该还在

阅读更多关于怎样写自己的热替换(管理)代码 hot module replacement

访问 example-app 直接查看 demo. (注意: 过时了, 也不要看源码, 因为 HMR API 中间有修改)

WEB前端使用 webpack + reack 搭建框架 02 本地服务 与 热替换(react-hot-loader)

前面我们搭建了一个基础的框架(WEB前端使用 webpack + reack 搭建框架 01 基础框架),但是更新代码后需要手动刷新比较麻烦,我们想实现自动更新。这就用到了webpack-dev-se...

在webpack应用的入口代码中,实现react相关组件的热重载(hot reload)

以下为应用的入口文件(main.jsx)的内容,主要是监控react组件和reducer的代码更新。import React from 'react'; import ReactDOM from 'r...
  • wzp1986
  • wzp1986
  • 2017年04月02日 00:36
  • 963

react-webpack2-热模块替换[HMR]

webpack2 - 模块热替换[HMR] 模块热替换功能会在应用程序运行过程中替换、添加或删除模块,而无需重新加载页面。这使得你可以在独立模块变更后,无需刷新整个页面,就可以更新这些模块,极大地...

webpack-- 模块热替换

全称是Hot Module ReplaceMent(HMR),理解成热模块替换或者模块热替换都可以吧,和.net中的热插拔一个意思,就是在运行中对程序的模块进行更新。这个功能主要是用于开发过程中,对生...

webpack热模块替换(HMR)/热更新

这是一篇关于webpack热模块替换的最简单的配置(不需要react),也称作热更新。...

SIM hot swap EINT module configuration for MT6589

[Description] Smart phone SIM hot swap EINT module configuration for MT6589 platform. On MT6589 th...

[SIM] SIM hot swap EINT module configuration for MT6572/MT6582/MT6592/MT6571

[SIM] SIM hot swap EINT module configuration for MT6572/MT6582/MT6592/MT6571 [SIM] SIM hot swap E...

webpack-hot-middleware热加载相关错误的解决办法

错误1:找不到__webpack_hmrGET http://127.0.0.1/__webpack_hmr 404 (Not Found)在webpack的entry配置添加引用路径’webpack...
  • yiifaa
  • yiifaa
  • 2017年05月10日 16:51
  • 6189

webpack配置react-hot-loader热加载局部更新

有人会问 webpack-dev-server 已经是热加载了,能做到只要代码修改了页面也自动更新了,为什么在 react 项目还要安装 react-hot-loader 呢?其实这两者的更新是有区别...

OSGi规范中文版(第5版 core R5.0.0)-第3章模块层(Module Layer)4[译]

3.9运行期类加载(runtime class loading) 每个安装到Framework的Bundle在resolve之后才会关联classloader。Bundle在resolve之后,...
  • wzumath
  • wzumath
  • 2014年07月14日 19:13
  • 1624
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[译] Webpack 用来做模块热替换(hot module replacement)
举报原因:
原因补充:

(最多只允许输入30个字)