首页 > 建站教程 > 前端框架 >  webpack5学习笔记:模块热替换(HMR)、react-refresh-webpack-plugin、VueLoaderPlugin正文

webpack5学习笔记:模块热替换(HMR)、react-refresh-webpack-plugin、VueLoaderPlugin

HMR

解释

  1. HMR全称 Hot Module Replacement

  2. 模块热替换指应用程序运行过程中,替换、添加、删除模块,而无需刷新整个页面

HMR作用

  1. 不重新加载整个页面,可以保留应用程序一些状态不丢失

  2. 只更新需要变化的内容,效率高

  3. 修改了css、js源代码,会立即在浏览器更新,相当于在浏览器的 devtool 直接修改

使用

  1. 保证当前运行的是 webpack-dev-server,而不是webpack的watch,也不是 webpack-dev-middleware

  2. 在webpack.config.js中增加devServer选项配置 module.exports = { // 专门为 webpack-dev-server 配置的 devServer: { hot: true } }

  3. 此时启动服务,浏览器会提示: [webpack-dev-server] Hot Module Replacement enabled.

  4. 此时,在入口文件,还需要指定哪些模块需要使用 HMR:

import './math.js'
console.log('Hello WebPack')

// 如果希望 math.js 启用热更新:
if(module.hot){
    module.hot.accept('./math.js', () => { // 参数1 可以是数组,也可以写多个 module.hot.accept,参数2是回调函数,当模块热更新完毕执行
        console.log('模块更新完毕')
    })
}
问题来了:如果每次每个需要热更新的模块,都写一遍,非常麻烦,react-refresh、vue-loader 都支持 HMR

React 的 HMR

  1. 在 src 新建 App.jsx

import React, {Component} from 'react'

class App extends Component {
    constructor(props) {
        super(props)

        this.state = {
            message: 'hello react'
        }
    }

    render() {
        return (
            <div>
                <h2>{this.state.message}</h2>
            </div>
        )
    }
}

export default App;
  1. 安装react npm install react react-dom

  2. 在入口文件中引入刚写的模块,并渲染

import './math.js'
import React from 'react'
import ReactApp from './App.jsx'
React.render(<ReactApp/>, document.getElementById('app'))
  1. 安装 webpack相关的 react 解析器等 npm install @babel/core babel-loader @babel/preset-env @babel/preset-react -D

  2. 配置 webpack.config.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    mode: 'production',
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './build')
    },
    module: {
        rules: [
            {
                test: /\.jsx?$/i,
                use: 'babel-loader'
            }
        ],

    },
    plugins: [
        new HtmlWebpackPlugin({
            title: '页面标题',
            template: './public/index.html'
        })
    ]
}
  1. 配置 babel.config.js

module.exports = {
    presets: [
        ['@babel/preset-env'],
        ['@babel/preset-react']
    ]
}
  1. package.json 配置

"scripts": {
    "build": "webpack",
    "dev": "webpack serve"
},
  1. 执行 npm run dev

    注意:此时,react并不能实现热更新,还是刷新整个页面。

  2. 安装 react-refresh-webpack-plugin npm install @pmmmwh/react-refresh-webpack-plugin react-refresh -D

  3. 在 webpack.config.js 中使用 react-refresh-webpack-plugin 插件

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
module.exports = {
    mode: 'production',
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './build')
    },
    module: {
        rules: [
            {
                test: /\.jsx?$/i,
                use: 'babel-loader'
            }
        ],

    },
    plugins: [
        new HtmlWebpackPlugin({
            title: '页面标题',
            template: './public/index.html'
        }),
        new ReactRefreshWebpackPlugin()
    ]
}
  1. 配置 babel.config.js

module.exports = {
    presets: [
        ['@babel/preset-env'],
        ['@babel/preset-react']
    ],
    plugins: [
        ['react-refresh/babel']
    ]
}
  1. 此时,再次运行就可以实现react组件的 HMR

Vue 的 HMR

  1. 安装 Vue npm install vue

  2. 在根目录新建 App.vue

<template>
    <div id="app">
        <h2 class="title">{{message}}</h2>
    </div>
</template>

<script>
export default {
    data () {
        return {
            message: '111'
        }
    }
}
</script>

<style scoped>
.title{
    color: red;
}
</style>
  1. 在入口文件导入 App.vue 组件 import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app')

  2. 安装 vue-loader 处理 vue文件,安装 vue-template-compiler 处理template模板 npm install vue-loader vue-template-compiler -D

  3. 因为刚才的模块里有css,所以要安装 css-loader、style-loader npm install css-loader style-loader -D

  4. webpack.config.js 配置

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')

module.exports = {
    mode: 'production',
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './build')
    },
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: [
                    'style-loader',
                    'css-loader'
                ],
            },
            {
                test: /\.js$/i,
                use: 'babel-loader'
            },
            {
                test: /\.vue$/i,
                use: 'vue-loader'
            }
        ],

    },
    plugins: [
        new HtmlWebpackPlugin({
            title: '页面标题',
            template: './public/index.html'
        }),
        new VueLoaderPlugin()
    ]
}
  1. 执行 npm run dev

    此时,就实现了vue 的 HMR,因为 vue-loader 内部实现了 vue 的 HMR,不需要额外配置,也不需要额外安装插件。

HMR 实现的原理

  1. webpack-dev-server 会创建两个服务:提供静态资源的服务(express)和Socket服务(net.Socket)

  2. express server负责直接提供静态资源服务(打包后的资源直接被浏览器请求和解析)

  3. HMR Socket Server 是一个socket长连接: 长连接的好处是建立连接后双方可以通信(服务器可以直接发送文件到客户端) 当服务器监听到对应的模块发生变化时,会生成.json(manifest文件)和.js(update chunk) 通过长连接,可以直接将这两个文件主动发送给客户端(浏览器) 浏览器拿到两个新的文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块进行更新