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

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

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


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

介绍

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

准备工做

它是怎样工做的?

从 App 的角度

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

从编译器(Webpack)角度

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

  1. 更对内容的 manifest (JSON)app

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

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

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

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

从模块角度

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

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

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

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

管理层面, 运行时支持两个方法: checkapply

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 更新的流程

generated update chunks

用这个能作到什么?

你能够在开发环境中用做 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 管理代码去调用 checkapply

你须要在编译器里开启 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-path, recordsPath: ...)

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

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

  • 在你的代码中插入热替换代码 module.hot.check, module.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 中间有修改)

相关文章
相关标签/搜索