Pinia 热更新 #

概述 #

热模块替换(HMR)允许在开发过程中更新 Store 的代码,而无需刷新整个页面。这对于保持应用状态、提高开发效率非常有用。

Vite 配置 #

基本配置 #

ts
// stores/index.ts
import { createPinia, acceptHMRUpdate } from 'pinia'

export const pinia = createPinia()

// 在 Vite 中配置 HMR
if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(pinia))
}

单个 Store 的 HMR #

ts
// stores/counter.ts
import { defineStore, acceptHMRUpdate } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++
    }
  }
})

// 配置 HMR
if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useCounterStore))
}

统一配置 #

ts
// stores/index.ts
import { createPinia } from 'pinia'

export const pinia = createPinia()

// 统一导出所有 stores
export * from './user'
export * from './cart'
export * from './product'
ts
// main.ts
import { createApp } from 'vue'
import { pinia } from './stores'
import App from './App.vue'

const app = createApp(App)
app.use(pinia)
app.mount('#app')

// 配置 HMR
if (import.meta.hot) {
  import.meta.hot.accept('./stores', (newStores) => {
    // 重新加载所有 stores
  })
}

Webpack 配置 #

基本配置 #

ts
// stores/counter.ts
import { defineStore, acceptHMRUpdate } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() { this.count++ }
  }
})

// Webpack HMR
if (module.hot) {
  module.hot.accept(acceptHMRUpdate(useCounterStore))
}

手动 HMR 处理 #

保留状态 #

ts
// stores/user.ts
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    name: '',
    email: '',
    preferences: {
      theme: 'light'
    }
  }),
  actions: {
    updateName(name: string) {
      this.name = name
    }
  }
})

if (import.meta.hot) {
  import.meta.hot.accept((newModule) => {
    // 获取当前 store 实例
    const store = useUserStore()
    
    // 保存当前状态
    const currentState = { ...store.$state }
    
    // 更新 store 定义
    newModule?.useUserStore
    
    // 恢复状态
    store.$patch(currentState)
  })
}

使用 acceptHMRUpdate #

ts
import { defineStore, acceptHMRUpdate } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() { this.count++ }
  }
})

// acceptHMRUpdate 会自动处理状态保留
if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useCounterStore))
}

HMR 工作原理 #

更新流程 #

text
1. 文件修改
   ↓
2. Vite/Webpack 检测到变化
   ↓
3. 触发 HMR 更新
   ↓
4. acceptHMRUpdate 处理更新
   ↓
5. 保留现有状态
   ↓
6. 更新 Store 定义
   ↓
7. 恢复状态
   ↓
8. 组件重新渲染

状态保留策略 #

ts
// 默认行为:保留所有状态
acceptHMRUpdate(useCounterStore)

// 自定义:选择性保留状态
if (import.meta.hot) {
  import.meta.hot.accept((newModule) => {
    const store = useCounterStore()
    const { name, email } = store.$state  // 只保留部分状态
    
    // 更新 store
    // ...
    
    store.$patch({ name, email })
  })
}

常见问题 #

1. Store ID 变化 #

如果修改了 Store 的 ID,HMR 可能无法正确工作:

ts
// 修改前
export const useUserStore = defineStore('user', { /* ... */ })

// 修改后
export const useUserStore = defineStore('userStore', { /* ... */ })  // ID 变化

// 解决方案:刷新页面

2. Setup Store 的 HMR #

Setup Store 的 HMR 需要特别注意:

ts
// stores/counter.ts
import { defineStore, acceptHMRUpdate } from 'pinia'
import { ref, computed } from 'vue'

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const double = computed(() => count.value * 2)
  
  function increment() {
    count.value++
  }
  
  return { count, double, increment }
})

if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useCounterStore))
}

3. 跨 Store 引用 #

当 Store 之间有依赖关系时:

ts
// stores/cart.ts
import { defineStore, acceptHMRUpdate } from 'pinia'
import { useUserStore } from './user'

export const useCartStore = defineStore('cart', {
  state: () => ({ items: [] }),
  actions: {
    checkout() {
      const userStore = useUserStore()
      // ...
    }
  }
})

if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useCartStore))
}

调试 HMR #

查看更新日志 #

ts
if (import.meta.hot) {
  import.meta.hot.accept((newModule) => {
    console.log('Store updated:', newModule)
  })
}

使用 DevTools #

Vue DevTools 可以帮助你:

  • 查看 Store 的当前状态
  • 监控状态变化
  • 追踪 HMR 更新

最佳实践 #

1. 始终配置 HMR #

ts
// 每个 store 文件末尾添加
if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useXxxStore))
}

2. 使用 TypeScript #

ts
// 类型安全的 HMR
if (import.meta.hot) {
  import.meta.hot.accept(
    acceptHMRUpdate(useCounterStore, import.meta.hot)
  )
}

3. 开发环境检测 #

ts
// 只在开发环境启用
if (import.meta.env.DEV && import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useCounterStore))
}

下一步 #

现在你已经掌握了热更新,接下来让我们学习测试策略。

最后更新:2026-03-28