Vuex 4 迁移指南:从 Vuex 3.x 升级到 4.0 的破坏性变更与新特性实战
【免费下载链接】vuex🗃️ Centralized State Management for Vue.js.项目地址: https://gitcode.com/gh_mirrors/vu/vuex
本篇指南基于 Vuex 官方迁移文档(docs/guide/migrating-to-4-0-from-3-x.md)整理而成,系统梳理从 Vuex 3.x 升级到 Vuex 4(本仓库当前版本为 4.1.0)时必须处理的破坏性变更:安装流程、TypeScript 支持、构建产物形态以及createLogger的导出位置变化,并介绍 Vuex 4 引入的新特性useStore组合式函数。读完本文,你将能够对照迁移清单逐项改造现有 Vuex 3 项目,完成与 Vue 3 生态对齐的升级。
Vuex 4 的核心 API 几乎全部沿袭自 Vuex 3,绝大多数代码无需改动即可继续工作;真正的风险集中在少数破坏性变更上。先给出结论,再逐项展开:
| 变更类别 | 3.x 写法 | 4.x 写法 |
|---|---|---|
| 创建 store | new Vuex.Store({...}) | createStore({...}) |
| 安装到应用 | Vue.use(Vuex) | app.use(store) |
TypeScript 中的this.$store | 内置全局类型 | 需自行声明模块扩充(module augmentation) |
createLogger导入 | vuex/dist/logger | 直接从vuex导入 |
| Composition API 取 store | 无(需手动provide/inject) | useStore() |
破坏性变更一:安装流程(Installation process)
为了与 Vue 3 全新的初始化流程对齐,Vuex 4 的安装方式发生了改变。Vue 3 应用不再通过Vue.use()全局安装插件,而是先创建应用实例、再通过app.use()安装 store。相应地,Vuex 4 引入createStore函数用于创建 store:
import { createStore } from 'vuex' export const store = createStore({ state () { return { count: 1 } } })安装时,把store 本身(而不是 Vuex 插件对象)传给app.use():
import { createApp } from 'vue' import { store } from './store' import App from './App.vue' const app = createApp(App) app.use(store) app.mount('#app')从源码结构看,createStore只是Store构造函数的语法糖:在 src/store.js 中,createStore(options)直接return new Store(options);而Store类在 src/store.js 中实现了install(app, injectKey)方法,其核心工作是:
install (app, injectKey) { app.provide(injectKey || storeKey, this) app.config.globalProperties.$store = this // ...devtools 接入 }即通过 Vue 3 的 Provide/Inject 机制向整棵组件树提供 store,同时把它挂到app.config.globalProperties.$store,从而保持 Options API 中this.$store的访问方式不变。
提示:严格来说
new Store({...})的语法在 Vuex 4 中仍然可用(Store类依旧被导出,见 src/index.js),并不构成破坏性变更。但官方推荐使用createStore,以便与 Vue 3 和 Vue Router Next 的初始化风格保持一致。
破坏性变更二:TypeScript 支持
Vuex 4移除了 Vue 组件内this.$store的全局类型声明,这是为了解决 issue #994(全局类型声明会污染所有组件的this类型推断)。因此,在 TypeScript 项目中必须自己声明模块扩充(module augmentation),为this.$store提供正确的类型。
在项目中添加如下声明文件(例如vuex-shim.d.ts):
// vuex-shim.d.ts import { ComponentCustomProperties } from 'vue' import { Store } from 'vuex' declare module '@vue/runtime-core' { // Declare your own store states. interface State { count: number } interface ComponentCustomProperties { $store: Store<State> } }这份声明文件需要被 TypeScript 纳入编译范围(通常只要放在项目根目录或被tsconfig.json的include覆盖即可)。更完整的类型化方案——包括使用InjectionKey为useStore注入类型、以及封装自定义useStore组合函数以避免到处传 key 的样板代码——参见 docs/guide/typescript-support.md,仓库的类型声明位于 types/index.d.ts,并有 types/test/index.ts 等类型测试用例持续校验。
破坏性变更三:构建产物与 Vue 3 对齐(Bundles are now aligned with Vue 3)
Vuex 4 生成的构建产物与 Vue 3 保持完全一致的命名与形态约定,共四类:
| 构建产物 | 用途 | 特点 |
|---|---|---|
vuex.global(.prod).js | 浏览器<script src="...">直接引入 | 暴露Vuex全局变量;IIFE 格式(不再是 UMD);内置硬编码的 prod/dev 分支,.prod.js为预压缩版本,生产环境必须使用 |
vuex.esm-browser(.prod).js | 原生 ES Module 导入 | 供浏览器<script type="module">直接使用 |
vuex.esm-bundler.js | 配合webpack、rollup、parcel等打包器 | 保留process.env.NODE_ENV分支守卫,由打包器在构建时替换;不附带压缩版本(压缩在整体打包后统一进行) |
vuex.cjs.js | Node.js 服务端渲染(SSR) | 通过require()引入的 CommonJS 格式 |
这六份产物(含 prod 变体)的产出规则定义在 rollup.config.js:vuex.esm-browser.js与vuex.esm-browser.prod.js为format: 'es'+browser: true;vuex.esm-bundler.js为format: 'es'且不标记 browser;vuex.global(.prod).js为format: 'iife',其输出名固定为Vuex;vuex.cjs.js为format: 'cjs'。其中__DEV__的替换策略也印证了文档描述(rollup.config.js):bundler 版本替换为(process.env.NODE_ENV !== 'production')表达式,其余版本按构建环境硬编码为布尔值。
在实际项目中,package.json 的入口映射决定了不同环境下使用哪份产物:main指向dist/vuex.cjs.js(Node/CommonJS)、module指向dist/vuex.esm-bundler.js(打包器)、browser指向dist/vuex.esm-browser.js(浏览器原生 ESM)、unpkg/jsdelivr指向dist/vuex.global.js(CDN 直接引入)。此外,本仓库还提供dist/vuex.mjs(见 package.json 的exports.import与 src/index.mjs 的 re-export 逻辑)用于 Node ESM 场景,并有 test/esm/esm-import.mjs 与 test/esm/esm-test.js 对其做端到端验证。
升级时建议检查自己的引入方式:凡是依赖 UMD 全局脚本加载方式的项目,需要改为 IIFE 的vuex.global.js,或改用打包器/ES Module 方案;生产环境务必切换到.prod产物。
破坏性变更四:createLogger从核心模块导出
在 Vuex 3 中,createLogger需要从vuex/dist/logger单独导入;Vuex 4 将其并入核心包,直接由vuex包导出:
import { createLogger } from 'vuex'对应地,src/index.js 中createLogger从./plugins/logger导入并随默认导出对象与命名导出一起暴露。升级时只需删除旧的vuex/dist/logger导入语句,统一从vuex导入即可。
createLogger本身提供了丰富的日志控制选项,实现位于 src/plugins/logger.js,各参数及其默认值如下:
| 参数 | 默认值 | 作用 |
|---|---|---|
collapsed | true | 是否折叠 console 分组(groupCollapsedvsgroup) |
filter | (mutation, stateBefore, stateAfter) => true | 过滤哪些 mutation 需要记录 |
transformer | state => state | 输出前转换 state(如序列化为 JSON) |
mutationTransformer | mut => mut | 输出前转换 mutation 记录 |
actionFilter | (action, state) => true | 过滤哪些 action 需要记录 |
actionTransformer | act => act | 输出前转换 action 记录 |
logMutations | true | 是否记录 mutation |
logActions | true | 是否记录 action |
logger | console | 自定义日志对象 |
其实现通过store.subscribe订阅 mutation、通过store.subscribeAction订阅 action,每次变更时深拷贝前后 state,并以%c样式输出 prev state、mutation、next state 三行,便于在 Vue Devtools 之外快速定位状态变更链路。
新特性:useStore组合式函数
Vuex 4 新增了面向 Composition API 的useStore函数,用于在组件的setup钩子中获取 store 实例:
import { useStore } from 'vuex' export default { setup () { const store = useStore() // store.state.count / store.getters / store.commit / store.dispatch ... } }useStore的底层实现非常简单,本质是对 Vue 3inject的封装(src/injectKey.js):
export const storeKey = 'store' export function useStore (key = null) { return inject(key !== null ? key : storeKey) }它从组件树上注入由Store.install(app.provide(injectKey || storeKey, this))提供的 store 实例。默认使用内置的storeKey(字符串'store');在 TypeScript 项目中,可以传入自定义的InjectionKey<Store<State>>以获得类型完整的 store,该 key 需要在安装时一并传入app.use(store, key),详细做法见 docs/guide/typescript-support.md。
在setup中使用 store 的完整姿势如下(见 docs/guide/composition-api.md):
import { computed } from 'vue' import { useStore } from 'vuex' export default { setup () { const store = useStore() return { // 用 computed 保持响应式 count: computed(() => store.state.count), double: computed(() => store.getters.double), // 提交 mutation 与派发 action increment: () => store.commit('increment'), asyncIncrement: () => store.dispatch('asyncIncrement') } } }仓库中的 examples/composition 目录提供了完整的 Composition API 示例应用(counter、chat、shopping-cart、todomvc 等),例如 examples/composition/counter/store.js 展示了createStore+useStore的最小闭环用法,是迁移后验证新 API 的良好参照。
迁移自检清单
完成上述改造后,建议按以下清单逐项确认:
- 创建与安装:
new Vuex.Store(...)已替换为createStore(...);Vue.use(Vuex)已替换为app.use(store),且app.use(store)在app.mount()之前调用。 - TypeScript 类型:已添加模块扩充声明文件(
vuex-shim.d.ts或vuex.d.ts),this.$store与useStore()均获得正确类型;类型测试可参考 types/test/index.ts。 - 构建产物:确认所引用的 bundle 是 Vue 3 对齐后的新命名(
vuex.global.js、vuex.esm-browser.js、vuex.esm-bundler.js、vuex.cjs.js),生产环境使用.prod变体;若通过 CDN 引入,注意 Global 构建已从 UMD 改为 IIFE。 - 日志插件:
createLogger已从vue包导入(import { createLogger } from 'vuex'),旧路径vue/dist/logger已移除。 - Vue 版本:Vuex 4 的 peer dependency 为 Vue
^3.2.0(见 package.json),请确保项目中的 Vue 版本满足该要求;在升级 Vuex 前应先完成 Vue 2 → Vue 3 的迁移。
最后提醒:迁移文档对应的进一步阅读入口为 docs/guide/typescript-support.md 与 docs/guide/composition-api.md,安装方式参见 docs/installation.md。官方建议在 Vuex 4 迁移时尽量以createStore+useStore的新风格书写新代码,将旧的 Options API 风格代码逐步收敛到新 API 上。
【免费下载链接】vuex🗃️ Centralized State Management for Vue.js.项目地址: https://gitcode.com/gh_mirrors/vu/vuex
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考