vue cli源码学习之cli-plugin-vuex
jscodeshift库简介
jscodeshift 是一个用于代码转换的工具,特别适用于 JavaScript 和 TypeScript 代码。它基于 Recast 和 AST(抽象语法树)来解析、遍历和修改代码。jscodeshift 提供了一种编程方式来批量修改代码,常用于代码重构、升级库版本、自动化代码修复等场景。
jscodeshift 的主要功能
- 解析代码:将源代码解析为 AST,便于程序化地分析和修改代码结构。
- 遍历和查找:提供强大的 API 来遍历 AST,并查找特定的节点(如函数调用、变量声明等)。
- 修改代码:允许对 AST 进行修改,添加、删除或替换节点。
- 生成代码:将修改后的 AST 转换回代码字符串。
使用 jscodeshift
首先,你需要全局安装 jscodeshift:
npm install -g jscodeshift
创建转换脚本
编写一个 JavaScript 文件作为转换脚本。例如,以下是一个简单的转换脚本示例:
module.exports = (fileInfo, api) => {const j = api.jscodeshift;const root = j(fileInfo.source);// 查找所有的函数声明root.find(j.FunctionDeclaration).forEach(path => {// 在这里对每个函数声明进行操作console.log(path.node.id.name);});return root.toSource();
};
运行转换
使用 jscodeshift 命令行工具运行转换脚本:
jscodeshift -t path/to/transform.js path/to/your/code
-t 指定转换脚本的路径。 path/to/your/code 是你想要转换的代码文件或目录。
常用 API
- find:查找特定类型的节点。
- replaceWith:替换找到的节点。
- forEach:遍历找到的节点。
- toSource:将 AST 转换回代码字符串。
generator\injectUseStore.js
使用 jscodeshift 库对 JavaScript 文件进行代码转换。具体来说,它查找并修改所有的 createApp 调用,向其添加 use(store) 方法调用。以下是代码的详细解释:
1. 导入和初始化:
j 是 jscodeshift 的一个实例,用于解析和转换代码。
root 是代码的根节点,表示整个代码文件的抽象语法树(AST)。
2. 查找 createApp 调用:
使用 root.find(j.CallExpression, …) 查找所有的函数调用表达式。
检查这些调用是否是 createApp 函数或 Vue.createApp 方法。
3. 替换 createApp 调用:
使用 appRoots.replaceWith 方法,将找到的 createApp 调用替换为调用 use(store)。
具体实现是将 createApp 调用节点转换为一个新的调用表达式,添加 use 方法和 store 参数。
4. 返回修改后的代码:
使用 root.toSource() 将修改后的 AST 转换回代码字符串并返回。
这段代码的主要目的是在 Vue 项目中自动为 createApp 调用添加 use(store),以便在应用中使用 Vuex 状态管理。
module.exports = (file, api) => {const j = api.jscodeshiftconst root = j(file.source)// 查找所有的 createApp 调用const appRoots = root.find(j.CallExpression, (node) => {// 检查是否是 createApp 函数调用if (j.Identifier.check(node.callee) && node.callee.name === 'createApp') {return true}// 检查是否是 Vue.createApp 方法调用if (j.MemberExpression.check(node.callee) &&j.Identifier.check(node.callee.object) &&node.callee.object.name === 'Vue' &&j.Identifier.check(node.callee.property) &&node.callee.property.name === 'createApp') {return true}})// 替换 createApp 调用,添加 use(store)appRoots.replaceWith(({ node: createAppCall }) => {return j.callExpression(j.memberExpression(createAppCall, j.identifier('use')),[j.identifier('store')])})// 返回修改后的代码return root.toSource()
}
在 jscodeshift 中,j.identifier 是一个用于创建或匹配标识符(Identifier)节点的函数。标识符是编程语言中用于命名变量、函数、类等的名称。在 JavaScript 中,标识符可以是任何有效的变量名或函数名。
j.identifier 的作用
- 创建标识符节点:当你需要在 AST 中插入一个新的标识符时,可以使用 j.identifier 来创建这个节点。例如,如果你想创建一个名为
myVariable 的标识符节点,可以这样做:
const myIdentifier = j.identifier('myVariable');
匹配标识符节点:在查找或遍历 AST 时,你可以使用 j.Identifier.check(node) 来检查某个节点是否是标识符节点。
generator\template-vue3\src\store\index.js
import { createStore } from 'vuex'export default createStore({state: {},getters: {},mutations: {},actions: {},modules: {}
})
这个代码是一个使用 Vuex 创建的 Vue 3 状态管理存储(store)的基本模板。Vuex 是 Vue.js 的一个状态管理模式和库,通常用于管理应用程序的全局状态。
以下是代码的主要部分及其作用:
- import { createStore } from ‘vuex’: 从 Vuex 库中导入 createStore函数,用于创建一个新的 Vuex 存储实例。
- export default createStore({ … }): 创建并导出一个Vuex 存储实例。
这个实例包含以下几个部分:
- state: 用于存储应用程序的状态数据。
- getters:用于从状态中派生出一些状态数据。
- mutations: 用于定义更改状态的同步方法。
- actions:用于定义可以包含异步操作的函数,这些函数最终会提交 mutation 来改变状态。
- modules: 用于将存储分割成更小的模块。
这个模板是一个起始点,开发者可以根据应用的需求来填充和扩展这些部分。
generator\index.js
module.exports = (api, options = {}, rootOptions = {}) => {// 向入口文件中注入 store 的导入语句api.injectImports(api.entryFile, `import store from './store'`)if (rootOptions.vueVersion === '3') {// 如果 Vue 版本是 3,转换脚本并扩展包依赖api.transformScript(api.entryFile, require('./injectUseStore'))api.extendPackage({dependencies: {vuex: '^4.0.0' // 使用 Vuex 4.0.0 版本}})// 渲染 Vue 3 的模板api.render('./template-vue3', {})} else {// 向根选项中注入 storeapi.injectRootOptions(api.entryFile, `store`)api.extendPackage({dependencies: {vuex: '^3.6.2' // 使用 Vuex 3.6.2 版本}})// 渲染 Vue 2 的模板api.render('./template', {})}if (api.invoking && api.hasPlugin('typescript')) {// 如果正在调用并且有 TypeScript 插件,转换文件/* eslint-disable-next-line node/no-extraneous-require */const convertFiles = require('@vue/cli-plugin-typescript/generator/convert')convertFiles(api)}
}
这段代码是一个用于 Vue CLI 插件的生成器模块,专门用于配置 Vuex(Vue 的状态管理库)。它根据项目的 Vue 版本和是否使用 TypeScript 插件来调整项目的配置。以下是代码的主要功能:
-
注入导入语句:
向项目的入口文件中注入 import store from ‘./store’,以便在项目中使用 Vuex 的 store。 -
根据 Vue 版本进行配置:
如果 rootOptions.vueVersion 是 ‘3’,则:
转换入口文件的脚本以适应 Vue 3 的使用方式。
扩展项目的 package.json,添加 Vuex 4.0.0 版本的依赖。
渲染适用于 Vue 3 的模板。
否则(即 Vue 版本为 2),则:
向根选项中注入 store。
扩展项目的 package.json,添加 Vuex 3.6.2 版本的依赖。
渲染适用于 Vue 2 的模板。
3.TypeScript 支持:
如果正在调用生成器并且项目中有 TypeScript 插件,则调用 TypeScript 转换文件的功能,以确保 TypeScript 文件的正确配置。
这段代码的目的是在使用 Vue CLI 创建项目时,自动配置 Vuex 和相关的依赖项,以便开发者可以更方便地使用 Vuex 进行状态管理。
api.extendPackage 方法是 Vue CLI 插件 API 提供的一个功能,用于扩展或修改项目的 package.json 文件。通过这个方法,你可以在插件生成器中动态地添加、修改或删除项目的依赖、脚本、配置等。
添加依赖:可以向项目中添加新的依赖项或开发依赖项。
修改脚本:可以添加或修改 npm 脚本。
配置字段:可以添加或修改 package.json 中的其他字段,如 browserslist、eslintConfig 等。
使用示例
api.extendPackage({dependencies: {vuex: '^4.0.0'},devDependencies: {'eslint-plugin-vue': '^7.0.0'},scripts: {serve: 'vue-cli-service serve',build: 'vue-cli-service build'}
})