Vite項目自動添加eslint prettier源碼解讀
引言
vite-pretty-lint庫是一個為Vite創(chuàng)建的Vue或React項目初始化eslint和prettier的庫。
該庫的目的是為了讓開發(fā)者在創(chuàng)建項目時,不需要手動配置eslint和prettier,而是通過vite-pretty-lint庫來自動配置。
源碼地址:
使用
根據vite-pretty-lint庫的README.md,使用該庫的只需要執(zhí)行一行命令即可:
// 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就是一個初始化項目的包名;
執(zhí)行npm init vite-pretty-lint命令后,相當于執(zhí)行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');
一看這些名字就知道,這里是用來創(chuàng)建eslint和prettier的配置文件的,這里的projectDirectory就是當前項目的根目錄。
當然現(xiàn)在這些暫時還沒有用到,接著往下走:
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函數(shù),這個就是執(zhí)行命令的入口函數(shù),可以將代碼拉到最低下就知道了。
這里直接看askForProjectType函數(shù),這個函數(shù)是通過./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函數(shù)來獲取的:
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函數(shù)就是獲取templates文件夾下的所有文件夾,然后將文件夾名作為選項返回。

回到main.js文件,繼續(xù)往下看:
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: [],
};
繼續(xù)往下看:
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項目,然后程序結束。
繼續(xù)往下看:
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來創(chuàng)建一個spinner,參考:nanospinner
通過child_process的exec來執(zhí)行安裝命令,參考:child_process
最后安裝完成,通過fs來寫入對應的配置文件;
總結
通過學習vite-plugin-eslint,我們學習到了在vite項目中如何配置eslint和prettier;
并且在這個過程中,我們學習到了如何通過vite的plugin來實現(xiàn)對vite的擴展;
還有這個項目的對vite的配置文件的解析,通過babel來解析vite的配置文件,然后通過importList來獲取import的配置,通過nonImportList來獲取非import的配置,通過exportStatement來獲取export的配置;
以上就是Vite項目自動添加eslint prettier源碼解讀的詳細內容,更多關于Vite添加eslint prettier的資料請關注腳本之家其它相關文章!
相關文章
Dom-api MutationObserver使用方法詳解
這篇文章主要為大家介紹了Dom-api MutationObserver使用方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
微信小程序 實現(xiàn)動態(tài)顯示和隱藏某個控件
這篇文章主要介紹了微信小程序 實現(xiàn)動態(tài)顯示和隱藏某個控件的相關資料,需要的朋友可以參考下2017-04-04

