Vue CLI 项目集成 Vuex:@vue/cli-plugin-vuex 插件的安装、代码生成与 Vue 2/Vue 3 适配原理
【免费下载链接】vue-cli🛠️ webpack-based tooling for Vue.js Development项目地址: https://gitcode.com/gh_mirrors/vu/vue-cli
本篇文章以 Vue CLI 官方仓库中的@vue/cli-plugin-vuex插件文档(docs/core-plugins/vuex.md)为核心,讲解如何在已有 Vue CLI 项目中通过vue add vuex一步完成 Vuex 状态管理的接入。文章将结合该插件在仓库中的生成器源码、模板文件与自动化测试,深入拆解插件在 Vue 2 与 Vue 3 两种技术栈下的差异处理逻辑,帮助读者既会"用",也懂"为什么"。读完本文,你将掌握 Vue CLI 插件式架构下的 Vuex 安装全流程,并能在项目里根据 Vue 主版本自行判断插件生成代码的正确形态。
插件概览:Vuex 以插件形式接入 Vue CLI
Vue CLI 采用插件化架构:新建项目的package.json中,所有以@vue/cli-plugin-开头的依赖都是插件,它们可以修改内部 webpack 配置、向vue-cli-service注入命令,创建项目过程中列出的绝大多数功能选项也都由插件实现(见 docs/core-plugins/index.md)。
@vue/cli-plugin-vuex正是这一架构下的 Vuex 官方插件,仓库中的描述为 "vuex plugin for vue-cli"。它不负责 Vuex 状态管理本身的运行逻辑(那是 Vuex 库的职责),而是负责把 Vuex 正确"接入"一个 Vue CLI 工程:安装依赖、生成store目录与初始化代码、修改应用入口文件。从 packages/@vue/cli-plugin-vuex/package.json 可以看到,该插件当前版本为5.0.9,其peerDependencies声明为@vue/cli-service: ^3.0.0 || ^4.0.0 || ^5.0.0-0,即它可以配合 Vue CLI 3.x、4.x 与 5.x 使用。
与 Babel、TypeScript、ESLint 等插件不同,Vuex 插件本身不注入任何
vue-cli-service命令、也不修改 webpack 配置,其插件入口 packages/@vue/cli-plugin-vuex/index.js 是一个空实现(module.exports = (api, options = {}) => {})。它全部的实际工作都发生在"生成器"(generator)阶段,这正是插件在创建/添加功能时执行的代码。这一点从源码结构上可以清晰推断。
在已有项目中安装 Vuex
官方文档给出的安装方式非常简单,只需要一条命令:
vue add vuex在vue add执行时,Vue CLI 会解析并加载@vue/cli-plugin-vuex包,然后运行其生成器完成以下工作:
- 在
package.json的dependencies中写入vuex依赖(版本视 Vue 主版本而定); - 渲染
src/store/index.js初始化文件; - 修改应用入口文件(默认
src/main.js),完成 Vuex 的注册与注入。
vue add适用于任何已存在的 Vue CLI 工程——无论是通过vue create创建时未勾选 Vuex、还是后续需要补充状态管理能力,都可以用这条命令补齐。该命令与创建项目时勾选 Vuex 功能(见后文"创建项目时勾选")走的是同一套生成器逻辑。
生成器源码解析:Vue 2 / Vue 3 双分支
插件真正的核心逻辑位于 packages/@vue/cli-plugin-vuex/generator/index.js。该生成器接收三个参数:api(Generator API,提供注入 import、渲染模板、扩展 package.json 等能力)、options与rootOptions(根选项,包含vueVersion等项目级配置)。
生成器首先无条件执行一行注入:
api.injectImports(api.entryFile, `import store from './store'`)即在入口文件顶部引入生成的 store。随后根据rootOptions.vueVersion是否等于'3'走完全不同的两条分支。
Vue 3 分支
if (rootOptions.vueVersion === '3') { api.transformScript(api.entryFile, require('./injectUseStore')) api.extendPackage({ dependencies: { vuex: '^4.0.0' } }) api.render('./template-vue3', {}) }- 依赖安装 Vuex 4.x(
^4.0.0),这是 Vue 3 对应的 Vuex 大版本; - 渲染 packages/@vue/cli-plugin-vuex/generator/template-vue3/src/store/index.js 模板,使用 Vue 3 组合式 API 风格:
import { createStore } from 'vuex' export default createStore({ state: { }, getters: { }, mutations: { }, actions: { }, modules: { } })- 通过
transformScript调用 packages/@vue/cli-plugin-vuex/generator/injectUseStore.js 对入口文件做 AST 转换。
injectUseStore.js基于 jscodeshift 实现:它查找入口文件中的createApp(...)调用(同时兼容Vue.createApp(...)的写法),并把该调用替换为createApp(...).use(store),从而在应用实例上完成 Vuex 的注册。核心转换逻辑如下:
const appRoots = root.find(j.CallExpression, (node) => { // 匹配 createApp(...) 或 Vue.createApp(...) }) appRoots.replaceWith(({ node: createAppCall }) => { return j.callExpression( j.memberExpression(createAppCall, j.identifier('use')), [j.identifier('store')] ) })这样src/main.js中类似createApp(App).mount('#app')的代码会被自动改写为createApp(App).use(store).mount('#app')。
Vue 2 分支
} else { api.injectRootOptions(api.entryFile, `store`) api.extendPackage({ dependencies: { vuex: '^3.6.2' } }) api.render('./template', {}) }- 依赖安装 Vuex 3.x(
^3.6.2),即 Vue 2 配套版本; - 不渲染独立的注册代码,而是通过
api.injectRootOptions把store追加到根组件选项(根 Vue 实例的store字段)中; - 渲染 packages/@vue/cli-plugin-vuex/generator/template/src/store/index.js,采用 Vue 2 经典写法:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { }, getters: { }, mutations: { }, actions: { }, modules: { } })Vue 2 与 Vue 3 分支的差异本质上是两个大版本 Vuex API 的差异:Vue 2 需要Vue.use(Vuex)全局安装插件并new Vuex.Store(...),Vue 3 则使用createStore(...)工厂函数,且注册方式从根选项注入变为app.use(store)。
与 TypeScript 的协同
生成器末尾还有一段针对 TypeScript 工程的兼容逻辑:
if (api.invoking && api.hasPlugin('typescript')) { const convertFiles = require('@vue/cli-plugin-typescript/generator/convert') convertFiles(api) }即:当通过vue add vuex在已启用 TypeScript 的项目中安装 Vuex 时,会调用@vue/cli-plugin-typescript生成器提供的convert函数,把生成的模板文件转换为 TypeScript 版本。这一判断条件api.invoking表示"在已有项目上执行vue add"这一场景,api.hasPlugin('typescript')则检测项目是否已安装 TypeScript 插件。需要注意的是,转换功能要求@vue/cli-plugin-typescript已在当前项目中,因此跨插件调用通过require('@vue/cli-plugin-typescript/generator/convert')按需加载。
自动化测试:插件行为的可验证依据
仓库为插件行为编写了专门的单元测试 packages/@vue/cli-plugin-vuex/tests/vuexGenerator.spec.js,通过@vue/cli-test-utils的generateWithPlugin工具模拟生成过程并断言产物:
base用例验证默认(Vue 2)场景:生成的src/store/index.js存在且包含import Vuex,pkg.dependencies中包含vuex依赖;use with Vue 3用例将vueVersion设为'3'后验证:src/store/index.js包含import { createStore },src/main.js包含.use(store),且pkg.dependencies.vuex匹配^4。
这些断言与上文分析的生成器逻辑一一对应,读者在升级或修改插件行为后,可运行该测试快速回归验证。
创建项目时勾选 Vuex
除了vue add vuex,在vue create创建项目并勾选 Features 时,Vuex 也是一个可选项。从仓库结构可以看到,创建流程的功能提示由 packages/@vue/cli/lib/promptModules/vuex.js 提供,勾选后会在生成阶段应用同一个@vue/cli-plugin-vuex生成器。也就是说,无论项目是"创建时选中"还是"创建后补齐",最终得到的src/store/index.js骨架与入口文件改动完全一致,不存在两套初始化结果。
小结
@vue/cli-plugin-vuex是一个典型的"零运行时代码"的 Vue CLI 插件:运行时入口为空,全部价值集中在生成器阶段——自动安装正确版本的 Vuex 依赖(Vue 2 →^3.6.2,Vue 3 →^4.0.0)、渲染符合对应版本 API 的src/store/index.js骨架、并以根选项注入(Vue 2)或 jscodeshift AST 改写createApp().use(store)(Vue 3)的方式完成入口集成,同时对 TypeScript 工程自动执行类型转换。
实操时只需记住:
vue add vuex执行后检查三处产物即可确认接入成功:package.json中新增vuex依赖、src/store/index.js存在、入口文件src/main.js已完成注册。后续在store/index.js的state、getters、mutations、actions、modules各区块中填充业务状态即可投入开发。
如需深入了解 Vue CLI 插件生成器的通用 API(injectImports、injectRootOptions、render、extendPackage、transformScript等),可继续阅读 docs/dev-guide/generator-api.md;若想了解其他核心插件(Babel、TypeScript、ESLint、PWA 等)的接入方式,参见 docs/core-plugins/index.md。
【免费下载链接】vue-cli🛠️ webpack-based tooling for Vue.js Development项目地址: https://gitcode.com/gh_mirrors/vu/vue-cli
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考