什么是webpack热更新?

历史问题

不知道大家以前开发是否遇到下面的问题

  1. 每次修改代码后需要手动刷新浏览器
  2. 修改一点代码后,需要重新编译所有代码 ,在大型项目中,运行速度感人
  3. 修改代码后,需要手动执行打包脚本,完成编译后再刷新浏览器

你期待的热更新是怎么样的

  1. 保存修改的代码后自动编译?
  2. 自动刷新浏览器?
  3. 页面是整体刷新还是局部刷新?

webpack中热更新配置

通过webpack运行一个项目

// 新建项目
mkdir webpack-demo
cd webpack-demo
yarn init -y
yarn add webpack webpack-cli --dev
yarn add webpack-dev-server --dev
  • webpack4中安装webpack同时也需要安装webpack-cli
// index0.js
function render() {
  let div = document.createElement(\'div\')
  div.innerHTML = \'Hello World 1111\'
  document.body.appendChild(div)
}

render()

// webpack.config.basic.js
module.exports = {
  entry: \'./src/index0.js\',
  mode: \'development\'
}

// package.json
{
        "scripts": {
        "build:basic": "webpack --config webpack.config.basic.js"
  }
}
  • 执行npm run build:basic,会打包生成dist文件夹,并且退出打包任务

Watch模式

  • 会监听文件的修改
// index0.js
function render() {
  let div = document.createElement(\'div\')
  div.innerHTML = \'Hello World 1111\'
  document.body.appendChild(div)
}

render()

// webpack.config.watch.js
module.exports = {
  watch: true,
  entry: \'./src/index0.js\',
  mode: \'development\'
}

// package.json
{
        "scripts": {
        "build:watch": "webpack --config webpack.config.watch.js"
  }
}
  • 运行npm run build:watch,会打包生成dist文件,并且进程不会退出
  • 问题:修改代码中文件,浏览器端内容不会更改,需要刷新浏览器才会更新

Live Relaod

  • 目的:每次代码变更后浏览器中的预览页面能自动显示最新效果而无须手动点击刷新
// index0.js
function render() {
  let div = document.createElement(\'div\')
  div.innerHTML = \'Hello World 1111\'
  document.body.appendChild(div)
}

render()

// webpack.config.reload.js
module.exports = {
  entry: \'./src/index0.js\',
  mode: \'development\',
  devServer: {
    contentBase: \'./dist\',
    open: true
  }
}

// package.json
{
        "scripts": {
        "dev:reload": "webpack-dev-server --config webpack.config.reload.js"
  }
}
  • 运行npm run dev:reload,会发现打包生成dist文件,在dist目录新建html文件,引入main.js文件,并且打包进程不会退出,修改代码后浏览器端会自动刷新(全部刷新)
  • 浏览器network面板中,会发现有websocket请求存在,用于本地服务与浏览器端的通信
  • 问题:当我已经在浏览器端填写了很多内容,当修改了本地代码后,浏览器刷新会清空之前填写的内容和数据

Hot Module Replacement

  • 解决页面刷新导致的状态丢失问题
  • 更新指定的位置信息,即局部更新内容
// index1.js
import \'./style.css\'

function render() {
  let div = document.createElement(\'div\')
  div.innerHTML = \'Hello World 1111\'
  document.body.appendChild(div)
}

render()

// style.css
div {
  color: blue;
}

// webpack.config.hmr.js
module.exports = {
  entry: \'./src/index1.js\',
  mode: \'development\',
  devServer: {
    contentBase: \'./dist\',
    open: true,
    hot: true
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [\'style-loader\', \'css-loader\']
      }
    ]
  }
}

// package.json
{
        "scripts": {
        "dev:hmr": "webpack-dev-server --config webpack.config.hmr.js"
  }
}
  • 安装css相关loader来解析css相关资源
  • 运行npm run dev:hmr,生成dist文件,打包进程开启,修改css文件,页面不会整体刷新,其他内容不会发生改变
  • 浏览器network面板中,会出现hot-update开头的资源请求信息
  • 问题:修改js资源文件,会发现页面还是全部重新刷新了

webpack中的热更新原理

  1. watch中体现的,是对本地文件内容的变更和监控
  2. reload中体现的,是浏览器端和本地服务器端的websocket通信
  3. hmr中体现的,是模块解析和替换功能

webpack中的打包流程

  • 一切源代码文件均可通过各种loader转换为JS模块,模块之间可以互相引用
  • webpack通过入口(enter)文件递归处理各模块引用关系,最后输出为一个或多个产物(bundle)文件
  • 每一个入口文件都是一个块组(chunk group),在不考虑分包的情况下,一个chunk group中只有一个chunk,这个chunk包含递归分析后的所有模块。每一个chunk都有对应的一个打包后的输出文件(asset/bundle)

模块热替换插件(HotModuleReplacementPlugin)

  • 通过HotModuleReplacementPlugin插件中的module.hot方法来实现资源的热替换
./text.js 
export const text = \'Hello World\' 
./index2.js 
import {text} from \'./text.js\' 
const div = document.createElement(\'div\') 
document.body.appendChild(div) 
function render() { 
  div.innerHTML = text; 
} 
render() 
if (module.hot) { 
  module.hot.accept(\'./text.js\', function() { 
    render() 
  }) 
}

github查看更多好文:https://github.com/xccjk/x-blog

来源

拉钩教育课程 - 前端工程精讲

  • 写的很好,非常推荐购买

前端工程精讲