webpack的Hot Module Replacement运行机制
使用webpack打包,难免会使用Hot Module Replacement功能,该功能能够实现修改、添加或删除前端页面中的模块代码,而且是在页面不刷新的前提下。它究竟是怎么运作的呢?本文主要从调试工具、配置文件、官方文档三个方面进行解析。
调试工具
首先从chrome的调试工具network中看看,代码改变的时候,页面与后端之间发生了什么?
页面初始加载
我们看到除了加载页面所依赖的文件外,多了一个连接,这是一个Server-sent Events,相关的介绍可以参考这篇文章,而且每隔一段时间都会向发送一次数据。数据内容主要是
action:sync操作;
hash:f397e485c539fd7a10fb,是bundle的hash,因为和产出文件collections.f397e485c539fd7a10fbjs的内容hash值相同;
modules:产出bundle中的module id和对应的文件地址。

修改代码
然后修改一处代码,webpack自动编译后,发现network中发生了几处变化,首先是客户端收到后端发出的事件
action:built操作,通知浏览器webpack重新发起了编译;
hash:最新产出bundle的内容hash值为debc36315df6764f157c;
modules:bundle中的模块id和对应模块的文件地址。

另外前端对后端发起了两个请求,请求了f397e485c539fd7a10fb.hot-update.json和0.f397e485c539fd7a10fb.hot-update.js两个文件,文件的hash值正好是未发生修改之前后端发送前端的bundle hash值。
我们查看一下两个文件的内容。
json文件的内容:
h:debc36315df6764f157c,bundle内容的最新hash值;
c:"0": true, 表示bundle id为0的文件被修改了;

js文件的内容:
内容是一个函数,类似jsonp的返回形式,也就是页面收到请求后执行了webpackHotUpdate函数,对bundle id为0的文件中的moudle id为50的模块进行修改。

跟进到这里,我们可以推测出这个交互过程:
(0)webpack首次编译时将如何更新更新模块(update-method)和接收后端推动事件(event-source)的代码打包到bundle之中;
(1)webpack进入watch 模式,在项目代码发生变化的时候重新编译;
(2)将编译产出存放在dev-server,此处的编译只针对变动的模块,产出应该包含上文中提到的oldbundlehash.hot-update.json和oldbundlehash.hot-update.js文件;
(3)dev-server中使用hot-middleware中间件向前端发送built事件;
(4)前端收到通知后,向后端请求最新的变动文件,请求到的js文件通过script标签加载后执行,其实就是执行已经预埋到bundle中的函数(update-method),从而修改bundle文件。

配置文件
接下来我们从项目的配置文件来验证一下,配置文件主要参考vue-cli中的webapck项目。
webpack.dev.conf.js
涉及到Hot Module Replacement的地方主要有两处:
entry的配置:在每个入口bundle开头引入了event-source,即在页面中接收后端发送的事件
/*********./build/webpack.dev.conf.js********/
// 将event-source相关代码,添加到每个入口chunk中,作为HRM Runtime的一部分。
// 后端相应的配置见dev-server的hotMiddleware部分
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})
/*********./build/dev-client.js********/ // Event-Source对象用于接收服务器端推送事件
// eventsource-polyfill用于扩展Event-Source对象在IE浏览器下的兼容性
require('eventsource-polyfill')
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
// 主要用于接受后端hotMiddleware的通知,执行reload操作
hotClient.subscribe(function (event) {
if (event.action === 'reload') {
window.location.reload()
}
})
插件的配置:引入HotModuleReplacementPlugin插件,将update-method的代码打入bundle
plugins: [
...
// HMR插件将HMR Runtime代码嵌入到bundle中,能够操作APP代码,完成代码替换
new webpack.HotModuleReplacementPlugin(),
// 报错提示插件:报错不阻塞,但是编译后给出提示
new webpack.NoEmitOnErrorsPlugin(),
new FriendlyErrorsPlugin()
]
dev-server.js
涉及到Hot Module Replacement的地方主要有两处:
将compiler挂载在devMiddleware上:对编译产出提供静态文件服务
// 将compiler挂载在dev-server上,监听本地代码变化,变化则启动编译并将编译后的文件暂存到内存中
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: config.dev.assetsPublicPath === './' ? '' : config.dev.assetsPublicPath,
quiet: true
})
将compiler挂载在hotMiddleware上:通知前端event-source对象发生了rebuilt
// 编译后发送通知到HRM Runtime,HRM Runtime收到update通知后,下载更新的模块,通知APP更新,APP收到通知,然后要求HRM Runtime执行模块替换
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
log: () => {}
})
由配置文件可以基本验证之前通过network debug得到的推论,接下来去看一下官方文档验证一下。
官方文档
官方文档先是总体介绍了一下 Hot Module Replacement的基本原理,然后将原理中涉及到几个知识点进行了介绍。
基本原理
webapck在编译的过程中,将HMR Runtime嵌入到bundle中;编译结束后,webpack对项目代码文件进行监视,发现文件变动重新编译变动的模块,同时通知HMR Runtime,然后HMR Runtime加载变动的模块文件,尝试执行热更新操作。更新的逻辑是:先检查模块是否能支持accept方法,不支持的话,则冒泡查找模块树的父节点,直到入口模块,accept方法也就是模块hot-replace的handler。
知识点
(1)compiler
这里的compiler也就是指webapck,主要提供update的信息,也就是update menifest(json文件格式)和update chunks(js文件格式);
(2)app
app也就是指前端页面,app中的代码主要调用HMR Runtime下载最新的模块代码,然后调用HMR Runtime执行update操作;
(3)HMR Runtime
HMR Runtime是webapck内嵌到前端页面的代码,主要提供来能给个职能check和apply。check用来下载最新模块代码,runtime能够接收后端发送的事件和发送请求;apply用于更新模块,主要将要更新的模块打上tag,然后调用模块的(也有可能是父模块)的更新handler执行更新。
(4)module
HRM是一个可插拔的工具,只能影响包含HMR code的模块。通常情况下,没有必要为每个模块写入HMR code,更新的时候会进行冒泡检查HMR code的是否存在。
根据官方文档的介绍,基本和我们的推论吻合,区别在于官方文档引入了HMR Runtime的概念,这个可以看作是推论中的event-source和update-method的结合体。
现在大家应该清楚了 webpack的Hot Module Replacement的基本原理了,官方文档中提到了如何根据最新的模块替换旧模块的方法,这个会放到下一篇文章中进行介绍。
webpack的Hot Module Replacement运行机制的更多相关文章
- Webpack & The Hot Module Replacement热模块替换原理解析
Webpack & The Hot Module Replacement热模块替换原理解析 The Hot Module Replacement(HMR)俗称热模块替换.主要用来当代码产生变化 ...
- webpack——Modules && Hot Module Replacement
blog:JavaScript Module Systems Showdown: CommonJS vs AMD vs ES2015 官网链接: Modules 官网链接:Hot Module Rep ...
- Webpack 2 视频教程 020 - Webpack 2 中的 HMR ( Hot Module Replacement )
原文发表于我的技术博客 这是我免费发布的高质量超清「Webpack 2 视频教程」. Webpack 作为目前前端开发必备的框架,Webpack 发布了 2.0 版本,此视频就是基于 2.0 的版本讲 ...
- webpack学习之—— 模块热替换(Hot Module Replacement)
模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程中替换.添加或删除模块,而无需重新加载整个页面.主要是通过以下几种方式,来显著加快开发速度: 保留在完全重 ...
- Angular开发实践(二):HRM运行机制
引言 在angular-start项目中启用了模块热替换(HMR - Hot Module Replacement)功能,关于如何在angular-cli启用HRM,请查看HRM配置 那HMR是个什么 ...
- webpack-Hot Module Replacement(热更新)
模块热替换(Hot Module Replacement) 模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程中替换.添加或删除模块,而无需重新加载整个页面 ...
- Hot Module Replacement [热模块替换]
安装了webpack-dev-server后 , 配置 "start": "webpack-dev-server" 然后运行 npm start 会开起一个we ...
- ASP.NET的运行原理与运行机制 如何:为 IIS 7.0 配置 <system.webServer> 节
https://technet.microsoft.com/zh-cn/sysinternals/bb763179.aspx 当一个HTTP请求到服务器并被IIS接收到之后,IIS首先通过客户端请求的 ...
- 【图解ASP.NET MVC运行机制理解-简易版】
很多盆友咨询ASP.NET MVC的机制.网上也有好多.但是都是相当深奥.看的云里雾里的.我今天抽空,整理个简易版本.把处理流程走一遍. 当然,这个只是处理请求的一部分环节.百度的面试题“客户端从浏览 ...
随机推荐
- chrome的断点调试
DOM节点变化时触发断点具体触发条件可分3种情况:子节点有变化.节点的属性发生变化或这个节点被删除.可以快速找到对应的事件处理函数. 条件断点 写一个表达式,表达式为 true 时才触发该断点. 在D ...
- 求一个整数数组最大子数组之和,时间复杂度为N
#include<iostream.h> int main () { ]={-,-,-,-,-,-,-,-,-,-}; ],sum=; ;i<;i++) { ) { sum=b[i] ...
- 开涛spring3(2.2) - IoC 容器基本原理及其helloword
2.2.1 IoC容器的概念 IoC容器就是具有依赖注入功能的容器,IoC容器负责实例化.定位.配置应用程序中的对象及建立这些对象间的依赖.应用程序无需直接在代码中new相关的对象,应用程序由IoC ...
- C#访问ORALCE数据库
随着时间的推移知识也在更新,原来可用的技术也会被淘汰或更新. framework4.0开始不再支持System.Data.OracleClient了,但是令人欣慰的是ORACLE公司自己出了一个Ora ...
- 刨根究底字符编码之八——Unicode编码方案概述
Unicode编码方案概述 1. 前面讲过,随着计算机发展到世界各地,于是各个国家和地区各自为政,搞出了很多既兼容ASCII但又互相不兼容的各种编码方案.这样一来同一个二进制编码就有可能被解释成不 ...
- js实现省市区三级联动
电商平台或者一些网站的个人信息部分,通常会有填写地址的功能.该功能一般分为二级联动(省.市)和三级联动(省.市.区),只需要JavaScript就可以实现. 这里介绍一种很简洁易用的方法.参考地址:h ...
- MySQL开放远程登录
在服务器上部署MYSQL每次观看MYSQL记录或者修改的时候都需要登录服务器,又烦又占资源.所以使用另一种方法:对外开放接口. 注:如果某些服务器开启防火墙屏蔽了某些接口就有可能导致远程用户无法登录M ...
- #414 Div2 C
#414 Div2 C 题意 两个人每个人都有一串字母序列,他们要替换一个长度为 n 包含问号的新序列,他们每次可以使用自己序列中的字母代替新序列的问号(使用自己序列中的字母后那个字母就会消失),第一 ...
- 一天搞定CSS:文本text--05
1.文本体系 2.文本各属性取值 说明: 每一个属性后面的分支是属性值,以及对属性值的说明. 比如text-align- - - -有3个取值:left,center,right 3.空格大小 4.代 ...
- 从RGB色转为灰度色算法
一.基础 对于彩色转灰度,有一个很著名的心理学公式: Gray = R*0.299 + G*0.587 + B*0.114 二.整数算法 而实际应用时,希望避免低速的浮点运算,所以需要整数算法. 注 ...