从很早时候就对 Webpack 的工作方式有所了解,甚至通过 vue-cli 脚手架等工具有过一些 Webpack 的使用经验。但没有 TypeScript 和 babel-polyfile 需求的我却从来没有试过从零开始配置它。
需求归需求,掌握 Webpack 的基本使用对于前端开发者而言是极为重要的。而且在 Webpack 的众多功能中,Hot Module Replacement, aka HMR(热模块更新)更是一个可以在任何 Web 开发场景下都可以极大提升开发效率与开发体验的重要功能。当你保存文件时页面内容自动更新的效果,就算是写一个不包含任何脚本文件的简单页面都可以从中受益。
于是本文将简单概述 HMR 的配置过程和工作原理,希望前端入门的你可以认识到这瓶万金油,并了解到它的局限性。
配置
首先,确保已经安装了 Node.js 和 npm。可以在终端中输入以下命令来检查它们是否已经安装:
node -v
npm -v
创建一个新项目目录,并在该目录中初始化 npm:
mkdir project
cd project
npm init -y
安装 Webpack 及其CLI:
npm install webpack webpack-cli --sava-dev
创建一个名为 src
的子目录,并在其中创建一个名为 index.js
的文件,这将是我们的入口文件。
在 package.json
文件中添加一个 build
脚本,以便最后的最后运行 Webpack 打包项目:
"scripts": {
"build": "webpack"
}
现在,Webpack 已经安装并准备好使用了。
接下来,要配置 HMR,需要进行以下更改:
- 在 Webpack 配置文件中添加以下代码
devServer: {
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
- 安装
webpack-dev-server
和html-webpack-plugin
:
npm install webpack-dev-server html-webpack-plugin --save-dev
- 在
package.json
文件中添加一个start
脚本:
"scripts":{
"start": "webpack-dev-server --open"
}
现在,使用 npm start
命令将启动开发服务器,并启用 HMR 功能,现在可以开始享用了。
原理
从安装的依赖包和配置大致就能看出来,HMR 的原理本质就是运行了一个会监听源代码文件变化的 Web 服务器。当开发人员修改了一个模块的代码时,HMR 会通过 WebSocket 将更新发送到客户端。
详细来看,分为以下几个步骤:
- 在启动 Webpack 时,会生成一个运行时环境(runtime environment),其中包含了用于管理模块热替换的逻辑代码。
- 当某个模块发生变化时,Webpack 会通过相应的插件(如 webpack-dev-server)监听到这个变化,并将变化的模块打包成一个更新包(update chunk)。
- 运行时环境会接收到更新包,并根据更新包中的信息,找到需要替换的旧模块。
- 运行时环境会使用新模块替换旧模块,并尝试重新渲染页面。如果渲染成功,则更新完成;否则会回退到整页刷新的方式。
另外需要知道的有:
只有被标记为“可热替换”的模块才能进行热替换。可以通过在模块代码中添加特定的 API 或使用相应的 Loader 来实现。
对于某些类型的模块(如 CSS、图片等),Webpack 会使用不同的更新策略。例如,对于 CSS 模块,Webpack 会将新样式插入到页面中,而不是直接替换旧样式。
如果多个模块之间存在依赖关系,Webpack 会自动处理它们之间的热替换顺序,确保不会出现错误或不一致的情况。
HMR 不仅可以应用于 Web 应用程序开发,还可以用于 Node.js 服务端开发,以及其他一些场景下的模块热替换。
技术缺陷
HMR 虽然可以实现代码修改后无需刷新页面即可更新页面程序,但仍存在一些局限性:
- 不能处理所有类型的模块:HMR 只能处理支持 HMR 的模块类型,如 JavaScript、CSS 等。对于不支持 HMR 的模块类型,需要手动刷新页面才能看到更新。
- 对于某些场景可能需要手动处理:在某些情况下,如新增或删除模块时,HMR 可能无法自动更新应用程序,需要手动刷新页面才能生效。
- 可能会出现一些问题:在某些情况下,如多个模块之间存在依赖关系时,HMR 可能会出现一些问题,如模块状态不一致等。
- 需要特定的配置:使用 HMR 需要在 Webpack 配置文件中进行特定的配置,如果配置不正确可能会导致 HMR 失效。