- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第35期,链接: juejin.cn/post/707970… 。
1. vite-pretty-lint
项目中配置合适的代码格式化配置方案助于统一项目代码风格,让开发者专注于代码逻辑本身,更有助于提高团队协作中代码的可读性,提高协作效率。
一般以下步骤:
- 安装eslint和配置eslintrc.json
- 安装prettier和配置prettier.json
当多个项目或者团队多人需要公用一套格式化配置时,重复的工作就需要通过工具来解放双手。vite-pretty-lint是一个自动为vite项目添加eslint和prettier的工具包,研究源码有助于学习批量给多个项目添加配置或者修改文件的思路。
vite-pretty-lint配置:
- 在vite项目中运行 npm init vite-pretty-lint 即可完成默认配置
github地址: github.com/tzsk/vite-p…
\
2. 主要项目结构
vite-pretty-lint
...
├── lib
│ ├── ast.js // ast语法树模板
│ ├── main.js // 项目入口
│ ├── shared.js // 公共配置模板
│ ├── templates // 不同项目类型的配置模板
│ │ ├── react-ts.js
│ │ ├── react.js
│ │ ├── vue-ts.js
│ │ └── vue.js
│ └── utils.js // 公共方法
├── tests // 测试相关
...
├── package-lock.json
├── package.json
└── vitest.config.js
3. 本地运行与调试
拉下代码,本地安装依赖之后准备运行项目。
这里学到一个新知识点:
new npm inite 命令会执行package.json的bin中配置的命令
从package.json中可以看出,npm create-vite-pretty-lint时,执行的时入口文件"lib/main.js"
{
...
"bin": {
"create-vite-pretty-lint": "lib/main.js"
},
...
}
可以使用node lib/main.js本地运行进行调试
然而,直接在该项目中运行node lib.mian.js,脚本中止并提示找不到vite.config.js
原因是该工具是在vite项目的运行环境中执行配置方法的,所以正确的本地调试方法应该是在一个本地的vite项目中调用该package。
正确本地运行姿势:
- 新初始化一个本地的vite项目vite-demo
- 在vite项目中运行 node ../vite-pretty-lint/lib/main.js
目录关系
...
├── vite-demo
└── vite-pretty-lint
4. 源码的调试和学习
本地运行的过程结合lib/main.js中的代码,可以大致了解工具运行的过程如下:
过程的逻辑很清晰,主要的逻辑lib/main.js中,有许多值得学习的地方
4.1 npm package: chalk
运行时发现的终端输出的字符带生动的样式,原来是chalk发挥的作用
console.log(
chalk.bold(
gradient.morning('\n🚀 Welcome to Eslint & Prettier Setup for Vite!\n')
)
);
结果:
\
4.2 npm package: enquirer
命令行中的选择过程是通过enquirer实现的
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'],
},
]);
}
结果:
\
4.3 process.cwd()
该方法返回 Node.js 进程的当前工作目录。
通过此node API在vite项目运行此npm包时,vite-pretty-lint可以定位到vite项目的目录地址,并且获取对应的配置以备修改配置所需。
const projectDirectory = process.cwd();
const eslintFile = path.join(projectDirectory, '.eslintrc.json');
const prettierFile = path.join(projectDirectory, '.prettierrc.json');
const eslintIgnoreFile = path.join(projectDirectory, '.eslintignore');
...
const viteJs = path.join(projectDirectory, 'vite.config.js');
const viteTs = path.join(projectDirectory, 'vite.config.ts');
这个node API可以和几个类似的API结合学习
console.log(process.execPath) // 当前执行node的路径
console.log(process.cwd) // 当前命令行执行的路径
console.log(_dirname) // 当前执行脚本所在的路径
console.log(_filename) // 当前正在执行脚本的文件夹名
4.4 await import()
const { packages, eslintOverrides } = await import(
`./templates/${projectType}.js`
);
动态引入中尝试了把await删除,无法获取到packages和eslintOverrides,背后原因可以后面再深入学习。
4.5 node API:fs
fs(file system)是node中提供本地文件读写能力的核心模块
4.6 AST抽象语法树
viteEslint方法中,该方法主要功能是合并配置。大致过程是将动态选中的配置文件和公共配置文件通过babel转换为ast后在进行合并,合并之后通过babel转换为js。
export function viteEslint(code) {
const ast = babel.parseSync(code, {
sourceType: 'module',
comments: false,
});
const { program } = ast;
...
// 合并配置
...
ast.program = program;
return babel.transformFromAstSync(ast, code, { sourceType: 'module' }).code;
}
关于ast这点引用一些网上的文章进行学习了解:
这样入门 js 抽象语法树(AST),从此我来到了一个新世界
5. 总结
vite-pretty-lint工具源码逻辑简洁,逐行阅读下来还算比较轻松,但也有不少收获:
- npx与npm
- npm init 原理
- eslint+prettier 基本实现
- 命令行开发常用npm包:chalk, enquirer
- node APIs:各种路径相关的apis,fs文件系统模块
- babel与ast抽象语法树
- 对多个项目进行批量修改文件的封装思想