热更新 #
什么是热更新? #
热更新(Hot Module Replacement,HMR)允许在开发过程中修改 Vuex 模块代码后,无需刷新页面即可看到更新效果,同时保留当前的应用状态。
基本配置 #
Webpack 配置 #
javascript
// store/index.js
import { createStore } from 'vuex'
import user from './modules/user'
import cart from './modules/cart'
const store = createStore({
modules: {
user,
cart
}
})
export default store
// 热更新配置
if (import.meta.hot) {
import.meta.hot.accept(['./modules/user', './modules/cart'], (newModules) => {
const newUser = newModules[0].default
const newCart = newModules[1].default
store.hotUpdate({
modules: {
user: newUser,
cart: newCart
}
})
})
}
Vite 配置 #
javascript
// store/index.js
import { createStore } from 'vuex'
import user from './modules/user'
import cart from './modules/cart'
const store = createStore({
modules: {
user,
cart
}
})
export default store
// Vite 热更新
if (import.meta.hot) {
import.meta.hot.accept('./modules/user', (newModule) => {
store.hotUpdate({
modules: {
user: newModule.default
}
})
})
import.meta.hot.accept('./modules/cart', (newModule) => {
store.hotUpdate({
modules: {
cart: newModule.default
}
})
})
}
动态导入模块 #
自动热更新所有模块 #
javascript
// store/index.js
import { createStore } from 'vuex'
// 动态导入所有模块
const moduleFiles = import.meta.glob('./modules/*.js')
const modules = {}
for (const path in moduleFiles) {
const moduleName = path.replace(/^\.\/modules\/(.+)\.\w+$/, '$1')
modules[moduleName] = moduleFiles[path]
}
export const createStoreInstance = async () => {
const loadedModules = {}
for (const [name, importFn] of Object.entries(modules)) {
const module = await importFn()
loadedModules[name] = module.default
}
return createStore({
modules: loadedModules
})
}
export default await createStoreInstance()
热更新辅助函数 #
javascript
// store/hmr.js
export function setupHMR(store, moduleMap) {
if (import.meta.hot) {
Object.entries(moduleMap).forEach(([moduleName, modulePath]) => {
import.meta.hot.accept(modulePath, (newModule) => {
store.hotUpdate({
modules: {
[moduleName]: newModule.default
}
})
})
})
}
}
// 使用
import { setupHMR } from './hmr'
const store = createStore({ /* ... */ })
setupHMR(store, {
user: './modules/user',
cart: './modules/cart'
})
export default store
保留状态 #
基本状态保留 #
热更新默认会保留当前状态:
javascript
// 修改模块代码后,状态会保留
// 例如:修改 user 模块的 mutation
// 当前登录状态不会丢失
重置状态 #
如果需要在热更新时重置状态:
javascript
if (import.meta.hot) {
import.meta.hot.accept('./modules/user', (newModule) => {
// 获取新模块
const newUser = newModule.default
// 重置状态
const oldState = store.state.user
const newState = newUser.state()
store.hotUpdate({
modules: {
user: {
...newUser,
state: () => newState
}
}
})
})
}
完整配置示例 #
项目结构 #
text
store/
├── index.js
├── hmr.js
└── modules/
├── user.js
├── cart.js
└── products.js
入口文件 #
javascript
// store/index.js
import { createStore } from 'vuex'
import user from './modules/user'
import cart from './modules/cart'
import products from './modules/products'
const store = createStore({
modules: {
user,
cart,
products
},
strict: process.env.NODE_ENV !== 'production'
})
// 热更新配置
if (import.meta.hot) {
// 用户模块
import.meta.hot.accept('./modules/user', (newModule) => {
console.log('[HMR] Updating user module')
store.hotUpdate({
modules: {
user: newModule.default
}
})
})
// 购物车模块
import.meta.hot.accept('./modules/cart', (newModule) => {
console.log('[HMR] Updating cart module')
store.hotUpdate({
modules: {
cart: newModule.default
}
})
})
// 产品模块
import.meta.hot.accept('./modules/products', (newModule) => {
console.log('[HMR] Updating products module')
store.hotUpdate({
modules: {
products: newModule.default
}
})
})
}
export default store
模块文件 #
javascript
// store/modules/user.js
const state = () => ({
profile: null,
token: null
})
const mutations = {
SET_PROFILE(state, profile) {
state.profile = profile
},
SET_TOKEN(state, token) {
state.token = token
}
}
const actions = {
async login({ commit }, credentials) {
// ...
}
}
const getters = {
isLoggedIn: state => !!state.token
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
调试热更新 #
检查热更新状态 #
javascript
if (import.meta.hot) {
console.log('HMR is enabled')
import.meta.hot.on('vite:beforeUpdate', (update) => {
console.log('Module will update:', update)
})
import.meta.hot.on('vite:afterUpdate', (update) => {
console.log('Module updated:', update)
})
}
Vue DevTools #
热更新后,Vue DevTools 可能需要重新连接。可以添加以下代码:
javascript
if (import.meta.hot) {
import.meta.hot.dispose(() => {
// 清理
})
import.meta.hot.accept(() => {
// 更新后通知 DevTools
if (window.__VUE_DEVTOOLS_GLOBAL_HOOK__) {
window.__VUE_DEVTOOLS_GLOBAL_HOOK__.Vue.util.defineReactive(
store,
'_vm',
store._vm
)
}
})
}
常见问题 #
1. 状态丢失 #
javascript
// 确保模块导出的是函数形式
export default {
state: () => ({ ... }), // 正确
// state: { ... } // 可能导致状态丢失
}
2. 热更新不生效 #
javascript
// 确保路径正确
import.meta.hot.accept('./modules/user', ...) // 相对路径
3. 类型错误 #
typescript
// TypeScript 中需要类型声明
declare const import.meta: {
hot: {
accept: (cb: (mod: any) => void) => void
}
}
最佳实践 #
1. 开发环境启用 #
javascript
if (import.meta.hot) {
// 只在开发环境配置
}
2. 模块独立更新 #
javascript
// 每个模块独立配置热更新
import.meta.hot.accept('./modules/user', ...)
import.meta.hot.accept('./modules/cart', ...)
3. 添加日志 #
javascript
import.meta.hot.accept('./modules/user', (newModule) => {
console.log('[HMR] User module updated')
store.hotUpdate({ modules: { user: newModule.default } })
})
总结 #
热更新要点:
| 要点 | 说明 |
|---|---|
| 配置方式 | import.meta.hot.accept |
| 更新方法 | store.hotUpdate |
| 状态保留 | 默认保留当前状态 |
| 调试 | 使用 console.log 和 DevTools |
继续学习 useStore,了解组合式 API 中的使用。
最后更新:2026-03-28