Implementation of hot module replacement
Implementation of Hot Module Replacement
Hot Module Replacement (HMR) is a core feature of modern front-end development toolchains, allowing applications to replace, add, or delete modules at runtime without a full page refresh. Vue 3 deeply integrates HMR through tools like @vue/compiler-sfc
and vite
, enabling developers to enjoy this feature with minimal additional configuration.
Basic Principles of HMR
The core of HMR lies in establishing a dependency graph between modules. When a file is modified, the toolchain locates the affected modules and pushes the changes to the client via WebSocket. Upon receiving the changes, the client runtime executes the module replacement logic. For example:
// Pseudocode illustrating the core HMR flow
if (import.meta.hot) {
import.meta.hot.accept('./moduleA.js', (newModule) => {
// Callback after the new module is loaded
console.log('Module updated:', newModule)
})
}
HMR Implementation Mechanism in Vue 3
Vue Single File Components (SFCs) require special handling for HMR because they consist of templates, scripts, and styles. @vue/compiler-sfc
compiles SFCs into JavaScript code with HMR markers:
// Compiled component code snippet
import { createHotContext } from "vite/hmr"
const __VUE_HMR_RUNTIME__ = createHotContext("/src/App.vue")
__VUE_HMR_RUNTIME__.createRecord('7ba5bd90', Component)
__VUE_HMR_RUNTIME__.reload('7ba5bd90', Component)
Optimization Strategy for Template Updates
Vue 3 employs special optimizations for template updates. When a template change is detected, it executes the following steps:
- Destroy the current component instance
- Recreate a new VNode tree
- Compare differences using the patch algorithm
- Minimize DOM operations
Example demonstrating HMR triggering for template modifications:
<!-- Before modification -->
<template>
<div>{{ count }}</div>
</template>
<!-- After modification -->
<template>
<div class="counter">{{ count }} times</div>
</template>
Implementation of State Preservation
Vue 3 preserves component state using the __VUE_HMR_RUNTIME__.rerender
method, which:
- Creates a new component instance
- Transfers the state from the old instance to the new one
- Triggers reactive system updates
Key code for state transfer:
function cloneState(original) {
if (typeof original === 'object' && original !== null) {
return reactive(original)
}
return original
}
Special Handling for Style Hot Updates
Style hot updates are divided into two scenarios:
<style>
block modifications: Directly replace the style element<style module>
modifications: Regenerate CSS module class names
Example of style HMR markers:
import { updateStyle } from "vite/client"
const __injectCSS = (css, id) => updateStyle(id, css)
__injectCSS("body{color:red}", "123456")
Custom HMR Handling Logic
Developers can customize handling logic using hot.accept
. A typical use case is store hot updates:
// store.js
export const store = reactive({ count: 0 })
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
// Merge state
Object.assign(store, newModule.store)
})
}
Error Recovery Mechanism
When HMR updates fail, Vue 3 implements a fallback strategy:
- Attempt component-level hot updates
- Fall back to parent component updates if unsuccessful
- Ultimately revert to a full page refresh
Example of error handling:
import.meta.hot.on('vite:beforeUpdate', () => {
// Preprocessing logic
})
import.meta.hot.on('vite:error', (err) => {
// Error handling
})
Performance Optimization Techniques
Vue 3's HMR incorporates several performance optimizations:
- Lazy loading of changed modules
- Update batching
- Dependency tree pruning
Key performance path code:
const queue = new Set()
let isFlushing = false
function queueUpdate(component) {
queue.add(component)
if (!isFlushing) {
isFlushing = true
Promise.resolve().then(flushUpdates)
}
}
Deep Integration with Build Tools
Vite achieves faster HMR updates through native ESM. Its core workflow:
- File system monitors file changes
- Sends update events via WebSocket
- Browser dynamically requests new modules
Example of Vite's HMR protocol:
{
"type": "update",
"updates": [
{
"type": "js-update",
"path": "/src/main.js",
"acceptedPath": "/src/main.js"
}
]
}
HMR Handling for Server-Side Rendering
SSR environments require special HMR handling:
- Client and server maintain separate module graphs
- Bidirectional HMR event communication
- Serialized state synchronization
Example SSR HMR configuration:
// vite.config.js
export default {
server: {
hmr: {
protocol: 'ws',
host: 'localhost',
port: 3000,
overlay: false
}
}
}
Boundary Condition Handling in HMR
Vue 3 addresses various edge cases:
- Dynamic component updates
- Async component loading
- KeepAlive component state preservation
Example of dynamic component HMR:
<script setup>
const componentMap = {
A: defineAsyncComponent(() => import('./CompA.vue')),
B: defineAsyncComponent(() => import('./CompB.vue'))
}
</script>
Hot Update Lifecycle Hooks
Vue components can listen to their own HMR events:
export default {
created() {
const unwatch = this.$watch(
() => this.$options.__hmrId,
() => {
// Custom logic during component hot updates
}
)
}
}
Atomicity Guarantee for Module Replacement
Vue 3 ensures atomicity in HMR updates:
- Synchronous updates for all dependencies
- Batched DOM updates
- Transactional state migration
Example of atomic update code:
function applyUpdate(module) {
performPreUpdateTasks()
try {
commitUpdate(module)
} catch (e) {
rollbackUpdate()
}
performPostUpdateTasks()
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:模板表达式的安全限制
下一篇:状态管理库的集成方式