vite-pretty-lint
库是一个为Vite
创建的Vue
或React
项目初始化eslint
和prettier
的库。
该库的目的是为了让开发者在创建项目时,不需要手动配置eslint
和prettier
,而是通过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');
一看这些名字就知道,这里是用来创建eslint
和prettier
的配置文件的,这里的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
这里只有两个问题,一个是项目类型,一个是包管理器,包管理器就是npm
,yarn
,pnpm
;
项目类型是用过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_process
的exec
来执行安装命令,参考:child_process
最后安装完成,通过fs
来写入对应的配置文件;
总结
通过学习vite-plugin-eslint
,我们学习到了在vite
项目中如何配置eslint
和prettier
;
并且在这个过程中,我们学习到了如何通过vite
的plugin
来实现对vite
的扩展;
还有这个项目的对vite
的配置文件的解析,通过babel
来解析vite
的配置文件,然后通过importList
来获取import
的配置,通过nonImportList
来获取非import
的配置,通过exportStatement
来获取export
的配置;
最后
最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。
有需要的小伙伴,可以点击下方卡片领取,无偿分享