一、DevServer和HMR
为什么要搭建本地服务器
目前我们开发的代码,为了运行需要有两个操作:
- 操作一:npm run build,编译相关的代码
- 操作二:通过live server或者直接通过浏览器,打开index.html代码,查看效果
这个过程经常操作会影响我们的开发效率
- 我们希望可以做到,当文件发生变化时,可以自动的完成编译和展示
为了完成自动编译,webpack提供了几种可选的方式:
- webpack watch mode
- webpack-dev-server
- webpack-dev-middleware
接下来,一个个来学习一下它们
Webpack watch
webpack给我们提供了watch模式:
- 在该模式下,webpack依赖图中的所有文件,只要有一个发生了更新,那么代码将被重新编译
- 我们不需要手动去运行 npm run build指令了
如何开启watch呢?两种方式:
- 方式一:在webpack.config.js配置文件中,添加 watch: true
watch: true,entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, 'dist'),},
- 方式二:在启动webpack的命令中,添加 —watch的标识脚本
"scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "webpack","watch": "webpack --watch"},
npm run watch 即可
webpack-dev-server
watch模式可以监听到文件的变化,但是有以下缺点
但是事实上它本身是没有自动刷新浏览器的功能的:
目前我们可以在VSCode中使用live-server来完成这样的功能
我们希望在不适用live-server的情况下,可以具备live reloading(实时重新加载)的功能
watch模式会对所有的源代码进行重新编译
编译成功后,都会生成新的文件(文件操作,效率不高)
live-server每次都会刷新整个页面,效率不高
如何解决? webpack-dev-server
安装:
- npm install —save-dev webpack-dev-server
配置:
//webpack.config.js文件 可以使用其他值mode: 'development',//package.json文件//webpack5之前是 webpack-dev-server"serve": "webpack serve"
编译:
- npm run serve
注意:
- webpack-dev-server 在编译之后不会写入到任何输出文件。而是将 bundle 文件保留在内存中
- 事实上webpack-dev-server使用了一个库叫memfs(之前是memory-fs webpack自己写的)
webpack-dev-middleware
默认情况下,webpack-dev-server已经帮助我们做好了一切:
- 比如通过express启动一个服务
- 比如HMR(热模块替换)
如果我们想要有更好的自由度,可以使用webpack-dev-middleware
什么是webpack-dev-middleware
- webpack-dev-middleware 是一个封装器(wrapper),它可以把 webpack 处理过的文件发送到一个 server
- webpack-dev-server 在内部使用了它,然而它也可以作为一个单独的 package 来使用,以便根据需求进行 更多自定义设置
webpack-dev-middleware的使用
安装,也可以用koa 主要是开启一个服务器
- npm install —save-dev express webpack-dev-middleware
编写文件src同级目录下编写server.js
const express = require('express');const webapck = require('webpack');const webpackDevMiddleware = require('webpack-dev-middleware');const app = express();//加载配置信息const config = require('./webpack.config');//将配置信息传递给webpack进行编译const compiler = webapck(config);//将编译后的结果传递给webpack-dev-middleware,返回的中间件供app使用const middleware = webpackDevMiddleware(compiler);app.use(middleware);app.listen(3000);

二、HMR
HMR的全称是Hot Module Replacement,翻译为模块热替换
模块热替换是指在应用程序运行过程中,替换、添加、删除模块,而无需重新刷新整个页面
HMR通过如下几种方式,来提高开发的速度:
- 不重新加载整个页面,这样可以保留某些应用程序的状态不丢失
- 只更新需要变化的内容,节省开发的时间
- 修改了css、js源代码,会立即在浏览器更新,相当于直接在浏览器的devtools中直接修改样式
使用HMR
- 默认情况下,webpack-dev-server已经支持HMR,我们只需要开启即可
- 在不开启HMR的情况下,当我们修改了源代码之后,整个页面会自动刷新,使用的是live reloading
webpack.config.js文件:
devServer: {hot: true,},
入口文件index.js:
import './math';console.log('Hello Webpack11');//监听math模块的更新if (module.hot) {module.hot.accept('./math.js', () => {console.log('模块热更新');});}
此时修改math模块内容

框架中的HMR
在开发其他项目时,我们是否需要经常手动去写入 module.hot.accpet相关的API呢?
比如开发Vue、React项目,我们修改了组件,希望进行热更新,这个时候应该如何去操作呢
事实上社区已经针对这些有很成熟的解决方案了:
- 比如vue开发中,我们使用vue-loader,此loader支持vue组件的HMR,提供开箱即用的体验
- 比如react开发中,有React Hot Loader,实时调整react组件(目前React官方已经弃用了,改成使用reactrefresh)
React中的HMR
在之前,React是借助于React Hot Loader来实现的HMR,目前已经改成使用react-refresh来实现了
安装实现HMR相关的依赖:
npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh
注意:这里安装@pmmmwh/react-refresh-webpack-plugin,最新的npm安装有bug(建议使用lts版本对应的npm版本)
修改webpack.config.js和babel.config.js文件:
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')plugins:[new ReactRefreshWebpackPlugin()]
module.exports = {presets:[["@babel/preset-env"],["@babel/preset-react"]],plugins:[['react-refresh/babel']]}
Vue中的HMR
Vue的加载我们需要使用vue-loader,而vue-loader加载的组件默认会帮助我们进行HMR的处理
安装加载vue所需要的依赖:
npm install vue-loader vue-template-compiler -D
配置webpack.config.js:
const VueLoaderPlugin = require('vue-loader/lib/plugin'){test:/\.vue$/use:'vue-loader'}plugins:[new VueLoaderPlugin()]
HMR原理
webpack-dev-server会创建两个服务:
- 提供静态资源的服务(express)
- Socket服务(net.Socket)
express server负责直接提供静态资源的服务(打包后的资源直接被浏览器请求和解析)
- HMR Socket Server,是一个socket的长连接: 长连接有一个最好的好处是建立连接后双方可以通信(服务器可以直接发送文件到客户端)
- 当服务器监听到对应的模块发生变化时,会生成两个文件.json(manifest文件)和.js文件(update chunk)
- 通过长连接,可以直接将这两个文件主动发送给客户端(浏览器)
- 浏览器拿到两个新的文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块进行更新

这说的有些简单,后续再深入吧。
