Webpack中文文档:
模块热替换 | webpack 中文文档

:::info webpack-dev-server隐藏的特性:
webpack-dev-server依然帮我们打包成一个dist目录只不过存在于电脑的内存当中,这样有效的提升了打包的速度。 :::

什么是HMRhot-module-replacement)热模块替换?
**HMR**就是在更改代码的时候页面内容发生变化但是不进行页面刷新。

CSS 热更新

  1. import "./style.css";
  2. var btn = document.createElement("button");
  3. btn.innerHTML = "新增";
  4. btn.addEventListener("click", function () {
  5. var div = document.createElement("div");
  6. div.innerHTML = "item";
  7. document.body.appendChild(div);
  8. })
  9. document.body.appendChild(btn);
  1. div:nth-of-type(odd) {
  2. background-color: antiquewhite;
  3. }

image.png
以上代码实现了当我点击页面的button按钮的时候就往页面进行一个divdiv的背景色为antiquewhite,但是加入我把div样式文件替换成pink后,页面就进行了刷新,我们新增的item也被丢失了,而热模块替换就是解决这个问题的。

  1. div:nth-of-type(odd) {
  2. background-color: pink;
  3. }

配置

方法一:直接配置devServer

  1. module.exports = {
  2. // ...
  3. devServer: {
  4. contentBase: "./dist",
  5. open: true,
  6. hot: true, // 让 webpack-dev-server 开启 HMR 的功能
  7. hotOnly: true, // 即便 css 样式没有生效也不让浏览器自动刷新页面
  8. },
  9. }


方法二:实例化webpack.HotModuleReplacementPlugin()构造函数

  1. const webpack = require("webpack");
  2. module.exports = {
  3. // ...
  4. devServer: {
  5. contentBase: "./dist",
  6. open: true,
  7. hot: true, // 让 webpack-dev-server 开启 HMR 的功能
  8. hotOnly: true, // 即便css样式没有生效也不让浏览器自动刷新页面
  9. },
  10. // ...
  11. plugins: [
  12. new webpack.HotModuleReplacementPlugin();
  13. ]
  14. }

然后我们进行样式修改后就会发现页面的样式进行了改变,页面也没有刷新,我新增的item也没有丢失,仅仅是item的背景颜色发生了改变,这样就极大了提示我们的开发效率。

  1. div:nth-of-type(odd) {
  2. background-color: aquamarine;
  3. }

image.png

JS 热更新

同样的效果也适用于JS文件:

  1. // import "./style.css";
  2. // var btn = document.createElement("button");
  3. // btn.innerHTML = "新增";
  4. // document.body.appendChild(btn);
  5. // btn.addEventListener("click", function () {
  6. // var div = document.createElement("div");
  7. // div.innerHTML = "item";
  8. // document.body.appendChild(div);
  9. // })
  10. import counter from './counter';
  11. import number from './number';
  12. counter();
  13. number();
  1. export default function () {
  2. let div = document.createElement("div");
  3. div.setAttribute("id", "counter");
  4. div.innerHTML = "1";
  5. div.onclick = function () {
  6. div.innerHTML = parseInt(div.innerHTML, 10) + 1
  7. }
  8. document.body.appendChild(div);
  9. }
  1. export default function () {
  2. let div = document.createElement("div");
  3. div.setAttribute("id", "number");
  4. div.innerHTML = "1000";
  5. document.body.appendChild(div);
  6. }

image.png
以上代码我们能实现在页面上显示 1 和 1000,假设现在点击 1 就会自加 1 到10,接着去修改number.js中的 1000 为 2000 的时候,页面没有进行刷新,依然是 10 和 1000(如果没有开启热更新,当修改为 2000 的时候,页面就会刷新为 1 和 1000)。
image.png

如果解决这个问题呢?

  1. import number from './number';
  2. import counter from './counter';
  3. counter();
  4. number();
  5. // 如果当前项目开启了热更新
  6. if (module.hot) {
  7. // 执行回调函数
  8. module.hot.accept("./number.js", () => {
  9. // 移除之前的 number,重新执行一下 number()
  10. document.body.removeChild(document.getElementById("number"));
  11. number();
  12. })
  13. }

现在点击 1 自加到任何数值,去代码里修改number.js中的 数字,页面就只会更新number.js ,不会影响counter元素。

:::warning 为什么js文件需要手动执行呢,而css文件就不需要呢?
这是因为css-loader已经帮我们做了这个操作,还有vue-loader也在内部帮我们做了这个操作。 :::