webpack dev server自动刷新问题:自动刷新导致页面状态丢失
每次修改完代码,webpack监视到变化,自动打包,并通过浏览器自动刷新,一旦页面整体刷新,页面中的任何操作状态都会丢失
HMR(Hot Module Replacement模块热替换)
”热拔插“ 计算机正在运行,插上去的设备可以立即工作,“热"指在运行过程中的即时变化
webpack模块热替换,实时的替换掉应用中某个模块,整体运行状态不会因此改变 例如上面的问题,使用HMR 就可以实现将修改的模块实时替换到应用中,不整体刷新
HMR是Webpack中最强大的功能之一,极大程度提高了开发者的工作效率
开启HMR
两种方式
-
运行命令webpack-dev-server --hot 开启
-
将devServer对象的hot属性设置未true,然后需导入插件HotModuleReplacementPlugin
const webpack = require('webpack') module.exports = { ... plugins: [ ... new webpack.HotModuleReplacementPlugin() ] }
css文件热更新正常 js文件热更新页面自动刷新,状态丢失
HMR疑问
HMR并不像webpack其他特性一样开箱即用,需要额外操作(手动通过代码处理 当模块更新过后 如何把更新后模块替换到页面中)
-
为什么样式文件热更新?
样式文件经过loader处理,在style-loader中已经自动处理了样式文件的热更新 不需要额外手动处理
-
为什么脚本需要自己手动处理?
样式文件更新后,只需把更新后的CSS及时替换到页面中,覆盖之前样式,实现更新
而JavaScript模块没有规律,可能导出对象、字符串或函数,webpack面对毫无规律的JS模块,不知道怎么处理更新后的模块,也就无法直接实现一个可以通用所有情况的模块替换方案
-
为什么vue-cli、create-react-app脚手架javaScript代码会热更新?
框架中每个文件都有规律,例如react要求每个模块导出必须是一个函数或类,这样就有了通用的替换方法
HMR APIs
HotModuleReplacementPlugin提供一套处理HMR的API,使用这些API将更新后的模块替换到正在运行的页面源代码
// HMR 手动处理模块热更新
// 不用担心这些代码在生产环境冗余的问题,因为通过 webpack 打包后,
// 这些代码全部会被移除,这些只是开发阶段用到
if (module.hot) {
// HMR失败后自动回退到自动刷新 页面自动刷新 控制台的错误信息会被清除
let hotEditor = editor
// 第一个参数接收的就是所监视的依赖模块路径 第二个参数就是依赖模块更新后的处理函数
// editor.js更新被手动处理后 就不会触发自动刷新
module.hot.accept('./editor.js', () => {
// 当 editor.js 更新,自动执行此函数
// 临时记录编辑器内容
const value = hotEditor.innerHTML
// 移除更新前的元素
document.body.removeChild(hotEditor)
// 创建新的编辑器
// 此时 createEditor 已经是更新过后的函数了
hotEditor = createEditor()
// 还原编辑器内容
hotEditor.innerHTML = value
// 追加到页面
document.body.appendChild(hotEditor)
})
module.hot.accept('./better.png', () => {
// 当 better.png 更新后执行
// 重写设置 src 会触发图片元素重新加载,从而局部更新图片
img.src = background
})
// style-loader 内部自动处理更新样式,所以不需要手动处理样式模块
}
注意
-
处理HMR的代码报错会导致自动刷新
devServer: { // hot: true热替换失败就会自动回退使用自动刷新 hotOnly: true hotOnly 的情况下并不会使用自动刷新 } |
-
使用HMR提供的API,但启动webpsck-dev-serve时未开启HMR
// HMR 手动处理模块热更新 // 不用担心这些代码在生产环境冗余的问题,因为通过 webpack 打包后, // 这些代码全部会被移除,这些只是开发阶段用到 if (module.hot) { ... }
网友评论