流程图镇楼~

image
这里将图中的
EventSource换成websocket。HMR(# hot module replacement)简单的来说就是监听文件变换替换相应的模块而不用刷新整个页面,区别于live reload(监听文件刷新整个页面),是提高开发体验和效率的一种方式。
大致原理:
2部分组成,一端是sever端,一端是client端。
- server端通过websocket将文件变化告知client端,并告知对应模块的hash值。
- client端收到消息后,对比模块的hash做出是否需要变更模块的决定,并再次请求完整的模块变化部分并替换client相应的模块(webpack-dev-middleware所做的事)。
- webpack暴露HMR接口,中间做多大规模的更新通过各个loader自己决定,否则冒泡替换整个模块。
下面自己基于wepack写个简单的HMR的例子
4个文件
- webpack-base-conf.js
- index.html
- main.js
- print.js(一个模块)
目录结构:

image
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); //生成html文件
const CleanWebpackPlugin = require('clean-webpack-plugin'); //每次build的时候清空之前的目录
const webpack = require('webpack')
//path.resolve(...[args])
//从右往左添加路径,最低路径其实拼接取决右边的参数,即使左边写了,也会被忽略,..会忽略左边第一个/后面的路径值,../../会忽略2个,以此类推
//把所有路径定位到项目工程根目录下
function resolve(dir) {
return path.resolve(__dirname, '..', dir);
}
module.exports = {
devtool: 'source-map',
mode: 'none',
entry: {
main: resolve('./src/main.js')
},
output: {
path: resolve('dist'),
filename: '[hash].[name].js'
},
devServer: {
contentBase: resolve('dist'), //本地服务器所加载的页面所在的目录
historyApiFallback: true, //不跳转
// inline: true, //实时刷新
hot: true
},
plugins: [
new CleanWebpackPlugin(),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
title: 'Development',
template: resolve('src/index.html')
})
]
}
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="root">根元素</div>
</body>
</html>
//main.js
import printNode from './print.js'
//这里能捕获监听到文件变化
if(module.hot) {
module.hot.accept('./print.js', ()=> {
document.querySelector("#root").appendChild(printNode);
})
}
//print.js
function printMe() {
console.log('updatessssssss')
}
var printNode = document.createElement('div');
printNode.innerHTML = '12';
// document.querySelector("#root").appendChild(printNode);
// module.exports = printMe;
module.exports = printNode;
//package.json
{
"name": "test",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"webpack": "webpack --config ./build/webpack.base.conf.js",
"server": "webpack-dev-server --config ./build/webpack.base.conf.js"
},
"license": "MIT",
"dependencies": {
"clean-webpack-plugin": "^2.0.1",
"html-webpack-plugin": "^3.2.0",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.3.1"
}
}
运行
npm run server
改变printNode.innerHTML = '12'里的内容,可以看到页面会发生HMR!.
PS:
这里对比下Webpack 的HMR和 Vue这些MVVM框架的响应式变化的区别,前者是通过监听文件的变化和hash进行模块替换,后者是通过数据劫持来改变页面内容,原理不同,效果也有差异。关于Vue的响应式原理可以看我的另一篇文章