1.作用

用于在开发过程中,实时预览修改后的页面,无需重新加载整个页面。
其主要通过一下几种方式来加快开发速度:

保留在完全重新加载页面时丢失的应用程序状态。
只更新变更内容,以节省宝贵的开发时间。
调整样式更加快速 - 几乎相当于在浏览器调试器中更改样式。

2.更新流程

核心概念:

entry: 入口文件
module:模块,webpack里一切皆模块,一个模块对应一个文件
chunk:代码块,对应多个module。
loader:模块转换器,用于模块内容的转换。
plugin:插件,在构建流程中监听特定的事件来做一些处理。

流程:

  • 修改了一个或多个文件。
  • 文件系统接收更改并通知Webpack。
  • Webpack重新编译构建一个或多个模块,并通知HMR服务器进行了更新。
  • HMR Server使用websockets通知HMR Runtime需要更新。(HMR运行时通过HTTP请求这些更新。)
  • HMR运行时再替换更新中的模块。

其中:
在热更新开启后,当webpack打包时,会向client端注入一段HMR runtime代码,同时server端会启动了一个HMR服务器,然后通过websocket和注入的runtime进行通信。
在webpack检测到文件修改后,会重新构建,并通过ws向client端发送更新消息,浏览器通过jsonp拉取更新过的模块,回调触发模块热更新逻辑。

主要更新流程如下图:

compile: 是webpack进行编译过程。
hmr-server: 建立连接并完成模块热更新的推送。
hmr-runtime: 运行时注入到bundle.js中的代码。

当模块启用了HMR时,其流程如下图:


文字描述:

  • webpack 监听到文件的修改
  • 根据配置信息,打包编译,且依赖webpack-dev-middleware实现打包结果在内存中。
  • webpack-dev-server初始化sockjs(一种模拟webScoket的技术),监听”webpack-dev-server”;webpack-hot-middleware初始化eventSource(与服务器发起连接的对象),监听”webpack-hot-middleware”
  • 监听到修改后,发送消息给客户端
  • 对应的client监听到修改后执行modul.hot.check
  • HotModuleReplacement.runtime执行check事件,请求manifest文件,获取需要更新的模块
  • 执行module.hot.apply来进行更新

其中:

  1. webpack-dev-middleware:是一个容器,它的作用是将webpack处理后的文件传递给server(webpack-dev-middleware 依赖于memory-fs,它将 webpack 原本的 outputFileSystem 替换成了MemoryFileSystem 实例,这样webpack编译的结果是放置在内存中而不是直接生成文件)。webpack-dev-server也是通过webpack-dev-middleware实现,同时,webpack-dev-middleware本身可以作为一个单独的包来使用。
  2. webpack-hot-middleware:实现热更新必须使用webpack-hot-middleware插件,该插件通过webpack的HMR API,浏览器和服务器之间建立连接并接收更新。它只专注于webpack和浏览器之间的通信机制。

  3. accept函数:接受指定依赖项的代码更新,依赖的模块更新后回调函数被调用,如下表示接受特定moduleID的更新。
    语法:

module.hot.accept(dependencies,  //表示依赖项,可以是一个字符串或字符串数组callback  //回调函数,用于在模块更新后触发的函数
);

具体例子:

if(module.hot){module.hot.accept("./print.js",function(){//使用更新过的print模块来执行某些操作·····});
}

当accept的参数为errHandler时,表示此模块的代码在不通知父级扽情况下更新。当模块不导出任何内容时会应使用此选项。

4.check函数:检查所有当前加载的模块是否有更新,如果找到则应用更新如果未找到更新,则调用回调null
例如:

module.hot.check(autoApply).then(outdatedModules => {//超时的模块
}).catch(error => {//捕获错误
});

如果autoApply为true,将使用所有已处理的模块调用回调。
如果autoApply未设置,则将调用所有将被处置的模块。
autoApply 参数可以是布尔值,也可以是 options,当被调用时可以传递给 apply 方法。

5.apply函数:只要 module.hot.status() === ‘ready’就会继续更新过程,其中options 的ignoreUnaccepted为true,表示某些模块未被接受(并且会冒泡到入口点),但更新过程仍会继续。

例如:

module.hot.apply(options).then(outdatedModules => {//超时的模块
}).catch(error => {//捕获错误
});

6.status函数:表示当前hmr的状态:module.hot.status(); // 返回以下字符串之一

  • idle:HMR正等着你的电话check()。当您调用它时,状态将更改为check。
  • check:HMR正在检查更新。如果找不到更新,它将更改回idle,如果发现更新,它将完成这些步骤prepare,dispose并且apply。比回来idle。
  • watch:HMR处于监视模式,将自动收到有关更改的通知。第一次更改后,它将更改为watch-delay并等待指定的时间来启动更新过程。任何更改都将重置超时,以累积更多更改。更新过程开始后,它将完成这些步骤prepare,dispose并且apply。
  • prepare:HMR正在为更新做准备。这可能意味着它正在下载一些东西。
  • ready:可以获得更新并准备好。打电话apply()继续。
  • dispose:HMR正在调用将被替换的模块的dispose处理程序。
  • apply:HMR正在调用被替换模块的父母的接受处理程序,而不是需要自己接受的模块。
  • abort:更新无法应用,但系统仍处于(旧)一致状态。
  • fail:更新在进程中间抛出异常,系统(可能)处于不一致状态。

最终完整细节流程图如下:

3.具体实现方式

  1. 通过插件HotModuleReplacementPlugin()来实现hmr
  2. 通过node.js的API来实现。

(1)通过插件实现:
下载安装插件:

npm install –save-dev webpack-hot-middleware

因为它是webpack内置的HMR插件所以不用引用,直接在配置文件的plugins中创建插件对象即可:

new webpack.HotModuleReplacementPlugin()  //热替换模块插件

创建一个print.js作为子,将index.js作为父,具体代码如下:

//print.js
export default function printMe() {//console.log('I get called from print.js!');console.log('hello vue!');
}
//index.js
import _ from 'lodash'
import printMe from './print.js'
import Vue from 'vue'Vue.config.productionTip = falsefunction component() {var element = document.createElement('div');var btn = document.createElement('button');element.innerHTML ='Hello webpack!';btn.innerHTML = 'Click me!';btn.onclick = printMe;element.appendChild(btn);return element;}let element = component(); //当 print.js 改变导致页面重新渲染时,重新获取渲染的元素document.body.appendChild(element);if (module.hot) {module.hot.accept('./print.js', function() {//表示接受更新console.log('Accepting the updated printMe module!');document.body.removeChild(element);element = component(); // 重新渲染component到点击事件上document.body.appendChild(element);})}
export default {name:'component'
};

这里在index.js中创建一个点击按钮,当点击按钮的时候控制台会输出print.js中的内容。
首先,当print.js内容未改变时,运行项目,其显示效果如下:

当改变其内容,但是不运行项目时,浏览器控制台显示如下:

过一会后:

通过插件可以实现浏览器的无刷新更新。

(2)通过node.js的API来实现:

原理:

在使用webpack-dev-server和node.js API时,将dev服务器作为第二参数进行传递而不是webpack的配置对象。

首先:创建一个server.js,index.js与print.js不变:

const webpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');const config = require('./webpack.config.js');
const options = {contentBase: './dist',hot: true, host: 'localhost'
};webpackDevServer.addDevServerEntrypoints(config, options);
//webpack-dev-server中具自带方法,他能添加 HMR的入口点
const compiler = webpack(config);
const server = new WebpackDevServer(compiler, options),
//将dev服务器选项放在webpack配置对象,作为第二个参数传递
server.listen(3000, 'localhost', () => {console.log('dev server listening on port 3000');//监听3000端口
});

其次创建一个style.css,并在index.js中引用:

import './style.css'

并下载相应加载css的loader:

npm install –save-dev npm install –save-dev style-loader css-loader 加载css文件的loader
npm install –save postcss-loader PostCSS用于处理CSS的webpack的加载器

在moudle中规定好其匹配规则:

{test: /\.css$/,use: ['style-loader', 'css-loader']
},
{test:/\.vue$/,   //匹配所有的.vue文件loader:'vue-loader',//依赖的loader包名options: {loaders:{css: ExtractTextPlugin.extract({use: 'css-loader',fallback: 'vue-style-loader'})//用来提取vue中的css样式}}
}

style.css如下:

body{background: red;/* background: blue;*/
}

效果同上,浏览器无需刷新而模块进行更新。

参考:
webpack热更新流程
热模块更换
webpack官方文档

热模块替换实现与原理相关推荐

  1. 【Webpack 性能优化系列(1) - HMR 热模块替换】

    webpack系列文章: [Webpack 性能优化系列(9) - 多进程打包]极大的提升项目打包构建速度!!! [Webpack 性能优化系列(8) - PWA]使用渐进式网络应用程序为我们的项目添 ...

  2. 热模块替换html,热模块替换启用,但不能正常工作http:// localhost:3000/__ webpack_hmr...

    好只是所以它很容易让人们看到我做了什么得到它在这里工作是: 我认为这是我更容易彻底清除SCSS并开箱即用的CSS模块.这似乎有很大帮助. 我用[email protected]:christianal ...

  3. webpack4.0核心概念(十)—— HMR(热模块替换-局部刷新)

    HMR:当修改一个js或者css的时候,只刷新修改的内容,不进行整个页面的刷新. css的HMR--只支持开发环境 不能使用mini-css-extract-plugin需要使用style-loade ...

  4. HMR(热模块代替)原理和react实践

    手动更新: 在以前,当我们一个大型的应用程序在开发过程中,每一次的修改每改动一次就要经历以下步骤: 资源重载 网络请求 浏览器渲染 页面刷新 这个过程对应工作量很大的应用来说是很难以接受的.想一想,即 ...

  5. SimScape热模块学习笔记

    SimScape热模块学习笔记 前言 近期着手做关于BMS相关的工作,准备使用Simulink建模方式完成BMS算法,传统的BMS算法大多基于电流积分+OCV查表修正的方法,现在比较新的方式是建立电池 ...

  6. 切披萨n块需要几刀原理c语言,LeetCode 1444. 切披萨的方案数(DP)

    1. 题目 给你一个 rows x cols 大小的矩形披萨和一个整数 k ,矩形包含两种字符: 'A' (表示苹果)和 '.' (表示空白格子). 你需要切披萨 k-1 次,得到 k 块披萨并送给别 ...

  7. [vue-cli]在使用vue-cli开发vue项目时,自动刷新页面的原理你了解吗?

    [vue-cli]在使用vue-cli开发vue项目时,自动刷新页面的原理你了解吗? 自动刷新页面并不是vue-cli的功能,而是webpack的hot-module-replacement-plug ...

  8. 前端三大构建工具 Webpack、Vite、Rollup 优劣势及原理分析

    在刚刚结束的 VueConf2021 中,除了 Vue 3.0 以外,另外一个亮点就是下一代构建工具 Vite 了. 在尤雨溪分享的[ Vue 3 生态进展和计划]的演讲中,尤大神还特意提到 Vite ...

  9. webpack热更新原理-连阿珍都看懂了

    前言 在旧开发的时代,前端项目在开发的过程中修改代码,很有可能是手动切到浏览器刷新页面来看到改动效果.操作不方便且页面之前的编辑记录也都丢失,体验可以说为0.想象一下一个表达你努力填满了所有输入项,结 ...

最新文章

  1. 《快速搞垮一个技术团队的20个“必杀技”》
  2. 监听端口的非阻塞性不具有继承性
  3. 【星云测试】开发者测试-采用精准测试工具对Spring Boot应用进行测试
  4. iOS APP提交上架流程
  5. 深入浅出的理解框架(Struts2、Hibernate、Spring)与 MVC 设计模式
  6. python元类简述
  7. CentOS 安装及使用 terraform 最新教程
  8. 动态规划经典题之年终奖
  9. 动态规划算法实验报告_搞懂这几点,动态规划算法就是那么简单
  10. Spring系统学习:180615--通过外部属性文件导入对数据库的连接
  11. 解决nginx访问php文件变成下载
  12. win10计算机记录,Win10新版计算器用法介绍
  13. 服务器cpu开启虚拟化的好处,开启硬件虚拟化有什么好处和坏处?
  14. 竞业限制是什么意思?
  15. xge_mac学习(4)--TX_DeQ
  16. java Math类的常用方法介绍
  17. Android视频编辑器(二)预览、录制视频加上水印和美白磨皮效果
  18. 22计算机考研上岸个人经验近万字分享(11408初试360分)
  19. python中的str()函数
  20. 【BZOJ3872】Ant colony(二分,动态规划)

热门文章

  1. PLL(锁相环)电路原理
  2. 歌词显示(随着播放进度)
  3. 海波龙 11.1.2.4安装指南// hyperion install
  4. 条码标签打印软件CodeSoft 6.0培训教程
  5. Markdown编写表格模板
  6. 机器学习中的特征缩放(feature scaling)浅谈
  7. GF4的Radiometric Calibration(高分4号的辐射定标)
  8. idea web 导包
  9. COMSOL光学模块/FDTD时域有限差分/ RSoft光电器件设计
  10. 一个披着 Windows 外壳的轻量级 Linux 系统