【源码共读】Vite 项目自动添加 eslint 和 prettier

news2024/12/24 9:11:24

vite-pretty-lint库是一个为Vite创建的VueReact项目初始化eslintprettier的库。

该库的目的是为了让开发者在创建项目时,不需要手动配置eslintprettier,而是通过vite-pretty-lint库来自动配置。

源码地址:

  • vite-pretty-lint
  • github1s 直接看

使用

根据vite-pretty-lint库的README.md,使用该库的只需要执行一行命令即可:

// NPM
npm init vite-pretty-lint

// YARN
yarn create vite-pretty-lint

// PNPM
pnpm init vite-pretty-lint 

这里就涉及到了一个知识点,npm init <initializer>yarn create <initializer>pnpm init <initializer>,这三个命令的作用是一样的,都是用来初始化一个项目的。

<initializer>是一个初始化项目的包名,比如vite-pretty-lint就是一个初始化项目的包名;

执行npm init vite-pretty-lint命令后,相当于执行npx create-vite-pretty-lint命令;

这里不多讲解,参考:npm init

源码阅读

打开lib/main.js文件直接看,一开头就看到了下面这段代码:

const projectDirectory = process.cwd();

const eslintFile = path.join(projectDirectory, '.eslintrc.json');
const prettierFile = path.join(projectDirectory, '.prettierrc.json');
const eslintIgnoreFile = path.join(projectDirectory, '.eslintignore'); 

一看这些名字就知道,这里是用来创建eslintprettier的配置文件的,这里的projectDirectory就是当前项目的根目录。

当然现在这些暂时还没有用到,接着往下走:

async function run() {let projectType, packageManager;try {const answers = await askForProjectType();projectType = answers.projectType;packageManager = answers.packageManager;} catch (error) {console.log(chalk.blue('\n👋 Goodbye!'));return;}// 省略后面代码
} 

一个run函数,这个就是执行命令的入口函数,可以将代码拉到最低下就知道了。

这里直接看askForProjectType函数,这个函数是通过./utils.js文件来的,进去看看

 export function askForProjectType() {return enquirer.prompt([{type: 'select',name: 'projectType',message: 'What type of project do you have?',choices: getOptions(),},{type: 'select',name: 'packageManager',message: 'What package manager do you use?',choices: ['npm', 'yarn', 'pnpm'],},]);
} 

这里就是通过enquirer库来获取用户的输入,enquirer库是一个命令行交互的库,可以参考:enquirer

这里只有两个问题,一个是项目类型,一个是包管理器,包管理器就是npmyarnpnpm;

项目类型是用过getOptions函数来获取的:

export function getOptions() {const OPTIONS = [];fs.readdirSync(path.join(__dirname, 'templates')).forEach((template) => {const { name } = path.parse(path.join(__dirname, 'templates', template));OPTIONS.push(name);});return OPTIONS;
} 

getOptions函数就是获取templates文件夹下的所有文件夹,然后将文件夹名作为选项返回。

回到main.js文件,继续往下看:

const {packages, eslintOverrides} = await import(`./templates/${projectType}.js`);

const packageList = [...commonPackages, ...packages];
const eslintConfigOverrides = [...eslintConfig.overrides, ...eslintOverrides];
const eslint = {...eslintConfig, overrides: eslintConfigOverrides}; 

当用户回答完问题后,就会根据用户的选择来导入对应的模板文件,比如用户选择了react,那么就会导入./templates/react.js文件。

可以进去templates文件夹里面的文件看看,这里是vue.js文件:

export const packages = ['vue-eslint-parser', 'eslint-plugin-vue'];

export const eslintOverrides = [{files: ['*.js'],extends: ['eslint:recommended', 'plugin:prettier/recommended'],},{files: ['*.vue'],parser: 'vue-eslint-parser',parserOptions: {ecmaVersion: 'latest',sourceType: 'module',},extends: ['eslint:recommended','plugin:vue/vue3-recommended','plugin:prettier/recommended',],rules: {'vue/multi-word-component-names': 'off',},},
]; 

这里的packages就是需要安装的包,eslintOverrides就是eslint的配置,这里的配置就是vue项目的eslint配置。

然后下面就是一些合并的配置,都是通过shared.js文件来的:

// shared.js
export const commonPackages = ['eslint','prettier','eslint-plugin-prettier','eslint-config-prettier','vite-plugin-eslint',
];

export const eslintConfig = {env: {browser: true,es2021: true,node: true,},overrides: [],
}; 

继续往下看:

const commandMap = {npm: `npm install --save-dev ${packageList.join(' ')}`,yarn: `yarn add --dev ${packageList.join(' ')}`,pnpm: `pnpm install --save-dev ${packageList.join(' ')}`,
};
const viteConfigFiles = ['vite.config.js', 'vite.config.ts'];
const [viteFile] = viteConfigFiles.map((file) => path.join(projectDirectory, file)).filter((file) => fs.existsSync(file));

if (!viteFile) {console.log(chalk.red('\n🚨 No vite config file found. Please run this command in a Vite project.\n'));return;
} 

这里就是通过commandMap来获取对应的安装命令;

然后通过viteConfigFiles来获取vite的配置文件;

这里是vite.config.js或者vite.config.ts,然后通过viteFile来判断是否存在vite的配置文件;

没有vite的配置文件就证明不是vite项目,然后程序结束。

继续往下看:

const viteConfig = viteEslint(fs.readFileSync(viteFile, 'utf8'));
const installCommand = commandMap[packageManager];

if (!installCommand) {console.log(chalk.red('\n✖ Sorry, we only support npm、yarn and pnpm!'));return;
} 

这里就是通过viteEslint来获取vite的配置文件,然后通过installCommand来获取对应的安装命令。

vimEslint也是在shared.js文件里面的:

export function viteEslint(code) {const ast = babel.parseSync(code, {sourceType: 'module',comments: false,});const { program } = ast;const importList = program.body.filter((body) => {return body.type === 'ImportDeclaration';}).map((body) => {delete body.trailingComments;return body;});if (importList.find((body) => body.source.value === 'vite-plugin-eslint')) {return code;}const nonImportList = program.body.filter((body) => {return body.type !== 'ImportDeclaration';});const exportStatement = program.body.find((body) => body.type === 'ExportDefaultDeclaration');if (exportStatement.declaration.type === 'CallExpression') {const [argument] = exportStatement.declaration.arguments;if (argument.type === 'ObjectExpression') {const plugin = argument.properties.find(({ key }) => key.name === 'plugins');if (plugin) {plugin.value.elements.push(eslintPluginCall);}}}importList.push(eslintImport);importList.push(blankLine);program.body = importList.concat(nonImportList);ast.program = program;return babel.transformFromAstSync(ast, code, { sourceType: 'module' }).code;
} 

这里就是通过babel来解析vite的配置文件,然后通过importList来获取import的配置,通过nonImportList来获取非import的配置,通过exportStatement来获取export的配置;

参考:babel

接着往下看:

const spinner = createSpinner('Installing packages...').start();
exec(`${commandMap[packageManager]}`, {cwd: projectDirectory}, (error) => {if (error) {spinner.error({text: chalk.bold.red('Failed to install packages!'),mark: '✖',});console.error(error);return;}fs.writeFileSync(eslintFile, JSON.stringify(eslint, null, 2));fs.writeFileSync(prettierFile, JSON.stringify(prettierConfig, null, 2));fs.writeFileSync(eslintIgnoreFile, eslintIgnore.join('\n'));fs.writeFileSync(viteFile, viteConfig);spinner.success({text: chalk.bold.green('All done! 🎉'), mark: '✔'});console.log(chalk.bold.cyan('\n🔥 Reload your editor to activate the settings!'));
}); 

通过nanospinner来创建一个spinner,参考:nanospinner

通过child_processexec来执行安装命令,参考:child_process

最后安装完成,通过fs来写入对应的配置文件;

总结

通过学习vite-plugin-eslint,我们学习到了在vite项目中如何配置eslintprettier;

并且在这个过程中,我们学习到了如何通过viteplugin来实现对vite的扩展;

还有这个项目的对vite的配置文件的解析,通过babel来解析vite的配置文件,然后通过importList来获取import的配置,通过nonImportList来获取非import的配置,通过exportStatement来获取export的配置;

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/111610.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式 - 单例模式(一)

单例模式一 官方定义二 单例模式八种方式2.1 饿汉式&#xff08;静态常量&#xff09;代码案例案例分析2.2 饿汉式&#xff08;静态代码块&#xff09;代码案例案例分析2.3 懒汉式(线程不安全)代码案例案例分析2.4 懒汉式(线程安全&#xff0c;同步方法)代码案例案例分析2.5 懒…

数据要求说明书(GB856T——88)基于协同的在线表格forture-sheet

数据要求说明书 1引言 1.1编写目的 本份数据要求说明书详细的提供了系统中各个数据的流向&#xff0c;是设计数据库的关键所在。为以后的编码以及测试提供一份可靠的依据。 预期的读者&#xff1a;系统开发人员、系统测试人员、系统维护人员 1.2背景 待开发的数据库名称&a…

揭秘百度智能测试在测试定位领域的实践

以前&#xff0c;我们介绍了测试活动测试输入、测试执行、测试分析、测试定位和测试评估五个步骤中测试输入、执行、分析、评估的智能化研究和实践&#xff0c;本文重点介绍测试定位环节的智能化实践。 测试定位的主要作用是在构建失败或问题发生后&#xff0c;快速给出产生该现…

机器学习之回归

回归算法 线性回归 求解线性回归方法 正规方程梯度下降 迭代 API sklearn.linear_model.LinearRegression 正规方程优化fit_intercept 是否计算偏置量&#xff0c;没有的化经过原点属性 coef_ 回归系数intercept_ 偏置量 sklearn.linear_model.SGDRegressor 使用随机梯度…

转行了!文科生转程序员的外包工作经历分享

01 种子 我是一名文科生&#xff0c;法律专业&#xff0c;武汉某 211 &#xff0c;入这行纯属巧合。 大三下半年&#xff0c;大家纷纷准备秋招&#xff0c;我去校园招聘会上溜达了一圈&#xff0c;好奇而去&#xff0c;丧气而归。 或许是因为大学三年过得太过安逸(宅在宿舍打…

C#语言实例源码系列-实现本地磁盘目录

专栏分享点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册 &#x1f449;关于作者 众所周知&#xff0c;人生是一个漫长的流程&#xff0c;不断克服困难&#xff0c;不断反思前进的过程。在这个过程中…

POMO: Policy Optimization with Multiple Optima for Reinforcement Learning学习笔记

文章目录摘要零、一些基础1.梯度近似2.策略梯度定理3.REINFORCE4.REINFORCE with Baseline5.REINFORCE Actor-Critic一、介绍二、相关工作&#xff08;1&#xff09;深度强化学习构建法&#xff08;2&#xff09;推理技术&#xff08;3&#xff09;深度强化学习改善法三、激励四…

制作 iOS 证书

准备工作 您需要 注册并加入 Apple Developer Program&#xff0c;才能在 App Store 上架应用。请准备一台 macOS 系统的电脑&#xff0c;用于证书制作。 创建 App ID 登录 Apple Developer&#xff0c;选择 Certificates, Identifiers & Profiles 选项。 选择 Identifi…

自学编程和计算机科班出身的差别在哪里

前不久逛知乎的时候看到一个问题&#xff1a;自学编程和计算机科班出身的差别在哪里&#xff1f; 自己回答了一下&#xff0c;获得了比较多的点赞和评论&#xff0c;在这里也分享给大家。 985 通信专业学长&#xff0c;转行程序员&#xff0c;聊一聊我的看法&#xff1a;说一千…

k8s之Job 与 CronJob

写在前面 语雀原文阅读效果更佳&#xff1a; 5、Job与CronJob 语雀 《5、Job与CronJob》 Job 与 CronJob 接下来给大家介绍另外一类资源对象&#xff1a;Job&#xff0c;我们在日常的工作中经常都会遇到一些需要进行批量数据处理和分析的需求&#xff0c;当然也会有按时间来…

RK3568平台开发系列讲解(工具命令篇)常用 GIT 命令汇总

🚀返回专栏总目录 文章目录 一、GIT BASICS二、GIT DIFF三、UNDOING CHANGES四、REWRITING GIT HISTORY五、GIT BRANCHES六、REMOTE REPOSITORIES七、GIT CONFIG八、GIT LOG九、GIT RESET十、GIT PULL十一、GIT PUSH沉淀、分享、成长,让自己和他人都能有所收获!😄 一、GI…

基于51单片机的酒精气体检测器设计

使用说明&#xff1a; 上电以后&#xff0c;需要预热一段时间&#xff0c;此时lcd显示Loading... &#xff08;预热过程为电压先上升后下降的改成&#xff0c;通过检测电压来检测是否预热完成&#xff09; &#xff0c; 预热完成后显示酒精浓度&#xff0c;按下按下按键key1即…

MySQL:互联网公司常用分库分表方案汇总

本文目录 一、数据库瓶颈 IO瓶颈 CPU瓶颈 二、分库分表 水平分库 水平分表 垂直分库 垂直分表 三、分库分表工具 四、分库分表步骤 五、分库分表问题 非partition key的查询问题 非partition key跨库跨表分页查询问题 扩容问题 六、分库分表总结 七、分库分表示例 …

因特网概述

目录1 网络、互连网&#xff08;互联网&#xff09;和因特网2 因特网发展的三个阶段3 因特网的标准化工作4 因特网的组成1 网络、互连网&#xff08;互联网&#xff09;和因特网 网络&#xff08;Network&#xff09;由若干结点&#xff08;Node&#xff09;和连接这些结点的链…

2022年山东省职业院校技能大赛高职组“网络系统管理”赛项规程

2022年山东省职业院校技能大赛高职组“网络系统管理”赛项规程一、赛项名称赛项名称&#xff1a;网络系统管理赛项组别&#xff1a;高职组赛项类别&#xff1a;电子与信息大类二、竞赛目的本赛项旨在借鉴世界技能大赛的办赛理念与技术规程&#xff0c;通过竞赛让参赛选手经历一…

论文导读 | 关于内存子图匹配算法的调研

前言 近年来&#xff0c;图数据结构在学术界和工业界的应用越来越广泛&#xff0c;包括社交网络分析、道路分析、化学分子合成、生物蛋白质网络分析、金融欺诈检测等等。子图匹配&#xff08;Subgraph Matching&#xff09;是图分析领域研究的一个重要课题&#xff0c;其旨在一…

批发进销存软件哪个好用?求测评

产品产量增加&#xff0c;在其他条件不变的情况下&#xff0c;就会形成规模效应&#xff0c;这样产品的生产成本就会降低。批发市场就可以对接大批量生产和出售单价更低的商品。而零售业往往也会采取批发货物的方式来降级成本。但是产品种类多&#xff0c;对于的供应商和客户也…

FactoryBean

FactoryBean ①简介 FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同&#xff0c;配置一个FactoryBean类型的bean&#xff0c;在获取bean的时候得到的并不是class属性中配置的这个类的对象&#xff0c;而是getObject()方法的返回值。通过这种机制&…

网友:我30多岁了,现在转行学编程来得及吗?

这些年&#xff0c;互联网行业的变化发展很快&#xff0c;很多公司也是借助互联网发展的大趋势发展的非常好。 水涨船高&#xff0c;行业好&#xff0c;意味着互联网行业的从业者的工资也就跟着高&#xff0c;很多互联网行业刚入门的月薪基本都已经过万了&#xff0c;一些传统行…

Android设计模式详解之命令模式

前言 命令模式是行为型设计模式之一&#xff1b; 定义&#xff1a;将一个请求封装成一个对象&#xff0c;从而让用户使用不同的请求把客户端参数化&#xff1b;对请求排队或者记录日志&#xff0c;以及支持可撤销的操作&#xff1b; 使用场景&#xff1a; 需要抽象出待执行…