Vite 和 Webpack 在热更新(HMR - Hot Module Replacement)机制上的主要区别
#webpack
#vite
目录
1. 基本原理对比
1.1. Webpack HMR:
// Webpack HMR 基本流程
1. 文件更改
↓
2. Webpack 重新编译变更模块
↓
3. 生成新的模块 hash
↓
4. 通过 WebSocket 推送更新
↓
5. 客户端收到更新,加载新模块
↓
6. 执行模块热替换
1.2. Vite HMR:
// Vite HMR 基本流程
1. 文件更改
↓
2. 直接发送变更文件给浏览器
↓
3. 浏览器使用原生 ESM 重新加载变更模块
↓
4. 执行模块热替换
2. 构建方式:
2.1. Webpack: Webpack 需要对整个应用进行打包
// Webpack 需要对整个应用进行打包
const webpack = require('webpack');
const compiler = webpack({
// ... webpack 配置
entry: './src/index.js',
output: {
// ... 输出配置
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
});
2.2. Vite:Vite 开发环境下不需要打包,直接使用 ESM
// Vite 开发环境下不需要打包,直接使用 ESM
import { createServer } from 'vite';
const server = await createServer({
// Vite 配置
server: {
hmr: true // 默认开启
}
});
3. 更新粒度:
3.1. Webpack HMR:Webpack 中需要手动处理模块热替换逻辑
// Webpack 中需要手动处理模块热替换逻辑
if (module.hot) {
module.hot.accept('./someModule.js', function() {
// 处理更新逻辑
console.log('Module updated');
});
}
3.2. Vite HMR:Vite 中的 HMR API 更简洁
// Vite 中的 HMR API 更简洁
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
// 更新逻辑
console.log('Module updated');
});
}
4. 性能表现:
// Webpack 开发服务器启动时间示例
// 需要先打包整个应用
const startWebpackServer = async () => {
const compiler = webpack({...});
const server = new WebpackDevServer(compiler, {
hot: true
// 其他配置
});
await server.start();
// 可能需要几秒到几十秒
};
// Vite 开发服务器启动时间示例
// 无需打包,直接启动
const startViteServer = async () => {
const server = await createServer({
server: { hmr: true }
});
await server.listen();
// 通常只需要几百毫秒
};
5. 更新速度:
5.1. Vite:
- 更快,因为只需要精确更新变化的模块
- 利用浏览器原生 ESM 能力
- 不需要打包过程
// Vite 的更新过程
// 1. 检测文件变化
watcher.on('change', async (file) => {
// 2. 直接发送更新的模块
ws.send({
type: 'update',
path: file,
content: await fs.readFile(file, 'utf-8')
});
});
5.2. Webpack:
- 需要重新编译构建变更模块
- 生成新的 chunk
- 可能触发关联模块的更新
// Webpack 的更新过程
// 1. 检测文件变化
// 2. 重新编译模块
compilation.buildModule(module, (err) => {
// 3. 生成新的 chunk
compilation.processModuleDependencies(module, (err) => {
// 4. 发送更新
hotMiddleware.publish({ action: 'built' });
});
});
6. 内存占用:
6.1. Vite:
- 开发环境下几乎不占用额外内存
- 按需加载模块
6.2. Webpack:
- 需要在内存中维护打包后的模块
- 占用更多内存
7. 源码映射:
// Vite 源码映射
// 直接使用浏览器原生 sourcemap
{
type: 'module',
src: '/src/components/App.vue?t=1634567890'
}
// Webpack 源码映射
// 需要额外的 sourcemap 文件
{
devtool: 'source-map',
output: {
sourceMapFilename: '[name].map'
}
}
8. 生态系统支持:
// Webpack 生态
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
};
// Vite 生态
export default {
plugins: [
// Vite 特有的插件系统
vue(),
react()
]
};