开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情
前言
今天忙里偷闲,准备把团队常用的ESLint配置汇总起来,形成自己的规则包。
规则包使用lerna开发,内计划有三个模块
- base 不涉及框架的基础规则 包名
@eslint-config-guide/base - react jsx和react-hook的规则 包名
@eslint-config-guide/react - vue vue-jsx和vue相关的规则 包名
@eslint-config-guide/vue
先随便写了两条规则,放在base中,部署到npm后,打算先趟趟坑。
@eslint-config-guide/base内容如下
module.exports = {
'rules': { // 制定具体规则
'no-console': 'warn', // console 报警
'quotes': ['error', 'single'] // 引号必须单引号
}
}
demo中调用方式如下:
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
},
extends: [
'@guide/base',
],
};
看着貌似没毛病,eslint-config-可以被省略,@eslint-config-guide/base省略成@guide/base。
万万没想到啊,直接报错
[Error - 16:43:09] Error: Failed to load config "@guide/base" to extend from.
啥玩意? 找不到这个包,我打开node_modules查看路径,没毛病啊。
可能是我自己package.json没写main吧,报着这种心态的我,核对了自己的配置文件,并没有发现问题。
算了,不偷懒,写全称吧@eslint-config-guide/base。
[Error - 16:43:09] Error: Failed to load config "@eslint-config-guide/base" to extend from.
好嘛,换了个错误提示就换了个包名。
此处忽略大量的百度、google查找过程。
问题不大,遇事不决抄作业,我安装了常见的eslint-config-airbnb和`eslint-plugin-vue。
核对了package.json和入口文件后,心态有点崩,啥问题都没。
此时的我突然灵光一闪,是不是因为我是二级路径导致的问题呢,我又安装了一个二级路径的包@vue\eslint-config-typescript
看到这个包名,我还寻思人家大佬就是不一样,非得按照规则走,二级目录也不愿意省略eslint-config-。
对比完成后,没毛病啊。
诶,此时陷入深深的自我怀疑中。
要不我拿本地路径试试,将demo代码修改如下
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
},
extends: [
'./node_modules/@eslint-config-guide/base',
],
};
没毛病,正常运行,那就说明我代码没问题啊。
细细想来,那就是extends规则我有疏漏之处,看看官网的介绍吧
并没找到具体的规则解析。
逼自己看源码吧,有兴趣的可以一起看源码
规则
假设我们的配置文件如下
module.exports = {
extends: [
'eslint:recommended',
'eslint-config-react',
'react',
'./myRule.js',
'prettier/@typescript-eslint',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/eslint-plugin/recommended',
'plugin:@typescript-eslint/test/recommended', // 为了测试,杜撰的一个包
'plugin:@typescript-eslint/eslint-plugin-irene/recommended', // 为了测试,杜撰的一个包
'plugin:prettier/recommended',
]
}
由此可以看出extends 有几种写法
eslint 开头
如果是 eslint:recommended,加载 ESLint 推荐的规则
如果是 eslint:all,加载 ESLint 所有的规则
plugin: 开头
首先分割pluginName,也就是plugin: 和最后一个 / 的之间部分;有如下几种情况
plugin:@typescript-eslint/recommended的 pluginName 是@typescript-eslint;plugin:@typescript-eslint/eslint-plugin/recommended的 pluginName 是@typescript-eslint/eslint-plugin;plugin:@typescript-eslint/test/recommended的 pluginName 是@typescript-eslint/test;plugin:@typescript-eslint/eslint-plugin-irene/recommended的 pluginName 是@typescript-eslint/eslint-plugin-irene;plugin:prettier/recommended的 pluginName 是prettier;
获取到pluginName后,就可以得到标准化的包名
如果 pluginName 以 @ 开头,说明使用的是 scoped modules;有如下几种情况:
- pluginName 是 @scopeName 或 @scopeName/eslint-plugin,对应的包名是 @scopeName/eslint-plugin;
@typescript-eslint对应的是@typescript-eslint/eslint-plugin;@typescript-eslint/eslint-plugin对应的是@typescript-eslint/eslint-plugin;
- pluginName 是 @scopeName/xxx,且 xxx 不以 eslint-plugin 开头,对应的包名是 @scopeName/eslint-plugin-xxx;
@typescript-eslint/test对应的是@typescript-eslint/eslint-plugin-test;
- pluginName 是 @scopeName/eslint-plugin-xxx,对应的包名是 @scopeName/eslint-plugin-xxx;
@typescript-eslint/eslint-plugin-irene对应的是@typescript-eslint/eslint-plugin-irene;
如果 pluginName 不以 eslint-plugin- 开头,对应的包名是 eslint-plugin-xxx;例如:prettier 对应的是 eslint-plugin-prettier;
本地路径
一个本地路径,指向本地的 ESLint 配置,例如:./myRule.js; 以 . 开头,这是为了兼容之前的版本;
其余
根据 extendName 得到标准化的包名,这一步与 plugin 相同
如果 extendName 以 @ 开头,说明使用的是 scoped modules;有如下几种情况:
- extendName 是
@scopeName或@scopeName/eslint-config,对应的包名是@scopeName/eslint-config - extendName 是
@scopeName/xxx,且 xxx 不以eslint-config开头,对应的包名是@scopeName/eslint-config-xxx - extendName 是
@scopeName/eslint-config-xxx,对应的包名是@scopeName/eslint-config-xxx - extendName 不以
eslint-config-开头,对应的包名是eslint-config-xxx;例如:react对应的是eslint-config-react
结论
将包名改为@eslint-config-guide/eslint-config-base后,demo中的调用
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
},
extends: [
'@guide/base',
],
};
成功,但这个包名看着有点难受,先撤销发包,后续调整调整再发布
总结
一直以来,都以为是前面的eslint-config-和eslint-plugin-可以省略,却没想到第二层依然需要对应的前缀标识,这次真的涨知识了
纸上得来终觉浅,绝知此事要躬行。