一,介绍
前端的自动化代码规范工具
- JavaScript/TypeScript 规范。主流的 Lint 工具包括 Eslint、Prettier;
- 样式开发规范。主流的 Lint 工具包括Stylelint、Prettier;
- Git 提交规范。主流的 Lint 工具包括Commitlint。
prettier
用于代码格式校验,一般用于格式化
eslint
用于代码格式和质量的校验
二,配置
prettier
在scripts里面一般执配置脚本代码检查
"format":"prettier —write ."
// .prettierrc
{
"singleQuote": true
}
eslint
在scripts里面一般执配置脚本格式化
"lint":"eslint --fix ."
// .eslintrc.js
{
parser:'@typescript-elsint/parser',// ESLint底层默认使用ESpree来进行ast解析,espree是基于acorn实现的
plugins:[],// 扩展规则
extends:[],// 继承另一份配置
rules: { // 具体规则
quotes: "off",
"no-unused-vars": "error",
}
}
三,原理
-
1、 首先禁掉 ESLint/插件 中与 Prettier 冲突的规则,创建一个包 eslint-config-prettier,里面定义了被禁掉的 ESLint/插件 规则。
没有创造新的规则,它只是关闭了 ESLint 中一些不必要的规则以及可能与 Prettier 冲突的规则
-
2、 创建一个插件 eslint-plugin-prettier,定义一条规则 prettier/prettier,调用 Prettier,配合 ESLint 实现运行
eslint --fix按 Prettier 规则自动格式化代码我们看下
eslint-plugin-prettier的代码,以 ESLint 规则的方式运行 Prettier,通过 Prettier 找出格式化前后的差异,并以 ESLint 问题的方式报告差异,同时针对不同类型的差异提供不同的 ESLint fixer
const {
showInvisibles,
generateDifferences,
} = require('prettier-linter-helpers');
const { name, version } = require('./package.json');
const { INSERT, DELETE, REPLACE } = generateDifferences;
let prettierFormat;
function reportDifference(context, difference) {
const { operation, offset, deleteText = '', insertText = '' } = difference;
const range = /** @type {Range} */ ([offset, offset + deleteText.length]);
const [start, end] = range.map(index =>
(context.sourceCode ?? context.getSourceCode()).getLocFromIndex(index),
);
context.report({
messageId: operation,
data: {
deleteText: showInvisibles(deleteText),
insertText: showInvisibles(insertText),
},
loc: { start, end },
fix: fixer => fixer.replaceTextRange(range, insertText),
});
}
const eslintPluginPrettier = {
meta: { name, version },
configs: {
recommended: {
extends: ['prettier'],
plugins: ['prettier'],
rules: {
'prettier/prettier': 'error',
'arrow-body-style': 'off',
'prefer-arrow-callback': 'off',
},
},
},
rules: {
prettier: {
meta: {
docs: {
url: 'https://github.com/prettier/eslint-plugin-prettier#options',
},
type: 'layout',
fixable: 'code',
schema: [
// Prettier options:
{
type: 'object',
properties: {},
additionalProperties: true,
},
{
type: 'object',
properties: {
usePrettierrc: { type: 'boolean' },
fileInfoOptions: {
type: 'object',
properties: {},
additionalProperties: true,
},
},
additionalProperties: true,
},
],
messages: {
[INSERT]: 'Insert `{{ insertText }}`',
[DELETE]: 'Delete `{{ deleteText }}`',
[REPLACE]: 'Replace `{{ deleteText }}` with `{{ insertText }}`',
},
},
create(context) {
const usePrettierrc =
!context.options[1] || context.options[1].usePrettierrc !== false;
const fileInfoOptions =
(context.options[1] && context.options[1].fileInfoOptions) || {};
const sourceCode = context.sourceCode ?? context.getSourceCode();
const filepath = context.filename ?? context.getFilename();
const onDiskFilepath =
context.physicalFilename ?? context.getPhysicalFilename();
const source = sourceCode.text;
return {
Program() {
if (!prettierFormat) {
// Prettier is expensive to load, so only load it if needed.
prettierFormat = require('synckit').createSyncFn(
require.resolve('./worker'),
);
}
const eslintPrettierOptions = context.options[0] || {};
const parser = context.languageOptions?.parser;
let prettierSource;
try {
prettierSource = prettierFormat(
source,
{
...eslintPrettierOptions,
filepath,
onDiskFilepath,
parserMeta:
parser &&
(parser.meta ?? {
name: parser.name,
version: parser.version,
}),
parserPath: context.parserPath,
usePrettierrc,
},
fileInfoOptions,
);
} catch (err) {
if (!(err instanceof SyntaxError)) {
throw err;
}
let message = 'Parsing error: ' + err.message;
const error =
/** @type {SyntaxError & {codeFrame: string; loc: SourceLocation}} */ (
err
);
if (error.codeFrame) {
message = message.replace(`\n${error.codeFrame}`, '');
}
if (error.loc) {
message = message.replace(/ \(\d+:\d+\)$/, '');
}
context.report({ message, loc: error.loc });
return;
}
if (prettierSource == null) {
return;
}
if (source !== prettierSource) {
const differences = generateDifferences(source, prettierSource);
for (const difference of differences) {
reportDifference(context, difference);
}
}
},
};
},
},
},
};
module.exports = eslintPluginPrettier;
四,配置步骤
npm安装 prettier 、eslint-config-prettier、 eslint-plugin-prettier,配置 .eslintrc.js
eslint-plugin-prettier 提供了这样一个配置 plugin:prettier/recommended多了rules规则,分离出 pluginName,它就是 plugin: 和最后一个 / 的之间部分
{
extends: [
..., // 其他
"prettier", // eslint-config-prettier
]
plugins: ["prettier"], // eslint-plugin-prettier
rules: {
"prettier/prettier": "error" // 开启规则
}
}
推荐文章
欢迎关注我的前端自检清单,我和你一起成长