前言
年前为公司升级了新的monorepo项目架构,近来不用加班,在家得闲。便想再搭个monorepo项目,随便记录一下。
用到以下pnpm + vite3 + vue3 + ESLint + Stylelint + TypeScript
monorepe实战记录,此篇为其中一个的简单介绍。
了解ESLint
ESLint是代码检查工具,用于检查代码是否符合规范,通过一些规则来检查语法和约束代码风格。
使用ESLint有诸多好处
- 统一语法,比如约定不能使用var。
- 统一代码风格,比如约定结尾是否加分号,当团队多人协作时统一的编码风格至关重要。
- 避免一些低级错误,比如写错变量。
- 等等...
ESLint有两种工具
- 一种是代码编辑(比如VS Code)的扩展工具,用于在编写代码时给予提示
- 一种是npm包,通过node执行包相关命令检查代码。
ESLint使用
这里在一个vite + vue3的基础模板中加入eslint,其他项目的eslint配置都是相似的。
安装ESLint (npm包)
pnpm add eslint -D
配置ESLint
需要告知eslint需要用哪些规则,就得添加个配置文件。可以直接在package.json中配置,也可以在项目根目录下创建.eslintrc.*文件。
支持的格式按优先级顺序如下
.eslintrc.js
(优先推荐).eslintrc.yaml
.eslintrc.yml
.eslintrc.json
.eslintrc
(官网提示弃用,但试了还能用。不过还是尽量用其他格式吧)package.json
还允许在文件下夹创建配置文件,比如在src下创建配置文件,此时src文件夹下文件的配置选项为:从src文件夹往父目录查找配置文件(直到遇到有root:true选项的配置文件,或到根目录),配置选项就是这些配置的组合,并且内层的选项优先级高。
在项目根目录下创建.eslintrc.cjs
。
// .eslintrc.cjs
module.exports = {}
打算一步步添加配置来简单介绍eslint的使用,所以没有使用命令快捷生成配置文件。
后面会介绍通过pnpx eslint --init
来快速生成相应的配置文件。
常用命令
- 执行校验
[pnpx] eslint [文件|文件夹|.]
// 校验main.js文件
pnpx eslint main.js
// 校验src文件夹下所有js文件
pnpx eslint src
- 修复基础问题`--fix
// 添加--fix会自动修复一些不影响逻辑的基础问题
pnpx eslint src --fix
- 指定校验的文件类型
--ext
// eslint默认只校验.js文件,可以通过--ext指定更多类型文件,逗号隔开
pnpx eslint src --ext .js,.vue
一般都会将命令写入package.json中
// package.json
{
// ...
"scripts": {
// ...
"lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
}
}
一般常用的就这几个命令,了解更多命令请查看官网-命令行
配置选项介绍
前面只创建了个空的配置对象,还需要配置相应的选项,先了解它们。
项目当前只有一个js文件(src/main.js),先根据这个文件(作为最初案例代码)简单配置下选项以实现对它的校验。
parserOptions
指定想要支持的 JavaScript 语言选项
module.exports = {
parserOptions: {
// 支持的ECMAScript语法,默认ECMAScript 5。配置来支持其他语法
ecmaVersion: 12,
// 代码模块,选项包含:script(默认)、module
sourceType: 'module',
// 额外的语言特性
//ecmaFeatures: {
// 是否 允许在全局作用域下使用 `return` 语句
//globalReturn: false,
// 是否 启用全局严格模板[strict mode] (如果 `ecmaVersion` 是 5 或更高)
//impliedStrict: false,
// 是否 支持jsx
//jsx: false,
// 是否 启用实验性的 object rest/spread properties
//experimentalObjectRestSpread: false,
//}
}
}
parser
配置eslint的解析器(解析代码并返回ast语法树),默认Espree,也可配置其他符合要求的解析器(比如esprima)
module.exports = {
parser: 'esprima'
}
有些特殊文件还需要使用特征插件来解析,比如.vue文件需要使用vue-eslint-parser
解析器进行解析,也可以在parser中配置
module.exports = {
parser: 'vue-eslint-parser'
}
当还需要额外定义解析器时,可以在parserOptions.parser中配置。
比如已经配置了vuevue-eslint-parser
解析器,还需要使用TypeScript@typescript-eslint/parser
,就可以像下面这样配置。
module.exports = {
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
解析器需要符合以下要求
- 它必须是一个 Node 模块,可以从它出现的配置文件中加载。通常,这意味着应该使用 npm 单独安装解析器包。
- 它必须符合 parser interface。
rules
ESLint附带大量的规则,想要使用对应的规则,就需要将将规则ID配置以下值。
"off"
或0
- 关闭规则"warn"
或1
- 开启规则,使用警告级别的错误:warn
(不会导致程序退出)"error"
或2
- 开启规则,使用错误级别的错误:error
(当被触发的时候,程序会退出)
有两种方式配置规则。以配置规则IDsemi
(结尾是否有分号)为例
-
在配置文件中配置
module.exports = { // ... 一些其他配置,没有配置其他rule rules: { semi: 2 } }
对案例代码
执行检测pnpx eslint src/main.js
如图:报了4个丢失分号错误。 -
也在项目文件中以注释的形式【不推荐在代码里嵌入eslint规则】
再执行检测pnpx eslint src/main.js
如图,没报eslint的semi错误了
extends
一个配置文件可以被基础配置中的已启用的规则继承。
大白话eslint配置文件可以继承其他配置文件的配置选项
。
当需要配置某些规范(比如内置规范、第三方规范...),则需要在extends
选项中配置。
例如,假设有某个第三方配置包eslint-config-aaa
a,我们的配置文件.eslintrc.cjs内容如下
module.exports = {
// ...
rules: {
semi: 2
},
extends: 'eslint-config-aaa'
}
b,第三方配置包eslint-config-aaa的规则如下
module.exports = {
rules: {
indent: [2, 2],
semi: 0
}
}
c,那么继承最终规则如下
module.exports = {
rules: {
indent: [2, 2],
semi: 2
}
}
eslint-config-aaa包的rules的属性indent被继承,而semi被覆盖,可通过rules覆盖extends中继承的规则。具体规则如下
rules
属性可以做下面的任何事情以扩展(或覆盖)规则:
- 启用额外的规则
- 改变继承的规则级别而不改变它的选项:
- 基础配置:
"eqeqeq": ["error", "allow-null"]
- 派生的配置:
"eqeqeq": "warn"
- 最后生成的配置:
"eqeqeq": ["warn", "allow-null"]
- 覆盖基础配置中的规则的选项
- 基础配置:
"quotes": ["error", "single", "avoid-escape"]
- 派生的配置:
"quotes": ["error", "single"]
- 最后生成的配置:
"quotes": ["error", "single"]
extends可配置 指定配置的字符串(可用数组配置多个,比如extends: ['配置包1','配置包2']
),并且会递归读取extends配置中的配置。
extends值可以是以下这些
-
配置文件路径,例如
module.exports = { // ... extends: './eslint.js' // ./eslint.js 是本地的一个其他eslint配置文件的路径 }
-
可共享配置名称,
可共享配置
是个npm包,它输出一个配置对象。
这个可共享配置的npm包要求前缀:eslint-config-
。如比较流行的eslint-config-standard
;还支持npmscoped modules,比如@scope/eslint-config-myconfig
当配置时eslint-config-前缀可以省略,比如module.exports = { // ... // eslint-config-standard 的缩写 extends: 'standard' }
-
插件(后面介绍)输出的规则,配置时需要以
plugin:
开头,比如module.exports = { // ... // eslint-plugin-vue 插件的缩写 // plugin: ['vue'], // 使用eslint-plugin-vue插件输入的vue3-recommended规则 extends: 'plugin:vue/vue3-recommended' // }
-
eslint内置规则包
eslint:all
当前安装ESLint中所有的规则
(不推荐使用)eslint:recommended
当前安装ESLint中一些常用的规则
,在规则页面 中被标记为 √ 的规则。
module.exports = { // ... // 使用eslint推荐规则 eslint:recommended extends: 'eslint:recommended' }
plugins
当ESLint提供的规则如果不能满足需求,就需要通过配置插件来为ESLint扩展规则。
比如想对vue文件进行校验,就可以通过plugins
选项配置(配置选项时eslint-plugin-
前缀可省略)。
下面以让eslint支持vue项目校验为例,演示如何使用插件和配置插件以及规则。
- 先安装以下依赖包:
vue-eslint-parser
解析vue文件的解析器eslint-plugin-vue
为vue文件添加新规则的插件
pnpm add vue-eslint-parser eslint-plugin-vue -D
- 修改eslint配置文件
module.exports = { // ... parser: 'vue-eslint-parser', plugins: [ // eslint-plugin-vue的缩写,eslint-plugin-可省略 'vue' ], extends: [ // 使用eslint-plugin-vue插件提供的vue3-recommended规则 'plugin:vue/vue3-recommended' ] }
- 执行校验指令
npx eslint src --ext .js,.vue
可以看到已支持对vue文件校验了。
env
若想使用环境变量,比如浏览器下的window变量,需要开启对应的环境选项env
。比如
module.exports = {
env: {
browser: true
}
}
比较常用到的环境包括:
browser
- 浏览器环境中的全局变量。node
- Node.js 全局变量和 Node.js 作用域。commonjs
- CommonJS 全局变量和 CommonJS 作用域 (用于 Browserify/WebPack 打包的只在浏览器中运行的代码)。shared-node-browser
- Node.js 和 Browser 通用全局变量。es6
- 启用除了 modules 以外的所有 ECMAScript 6 特性(该选项会自动设置ecmaVersion
解析器选项为 6)。worker
- Web Workers 全局变量。amd
- 将require()
和define()
定义为像 amd 一样的全局变量。- 更多可用环境
globals
当使用当前文件源文件未定义的变量时,no-undef
规则将发出警告。此时就可以通过globals
选项来定义全局变量以规避no-undef
警告。
module.exports = {
globals: {
var1: 'writable', // writable 可写
var2: 'readonly', // readonly 仅读
var3: 'off' // off 禁用该全局变量
}
}
注意: 要启用no-global-assign规则来禁止对只读的全局变量进行修改。
overrides
当需要对某些文件规则重写时,可以使用overrides
选项。
例如 bin和lib下的js文件的规则重写。
module.exports = {
overrides: [{
files: ['bin/*.js', 'lib/*.js'],
excludedFiles: '*.test.js',
rules: {
quotes: ['error','single']
}
}]
}
.eslintignore
当需要告诉ESLint忽略某些文件时,可以在项目根目录创建.eslintignore
文件
# 这行是注释
node_modules
dist
也可以直接在package.json中配置
{
"eslintIgnore": ["node_modules","dist"]
}
命令形式创建配置文件。
就是直接执行npx eslint --init命令,然后根据项目情况选择就行,推荐直接跳到下一节点。下面记录的有点不太必要,但当时记都记录了就没删掉-
D:\data\st\vue\vite-vue3>npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
Need to install the following packages:
@eslint/create-config@0.4.2
Ok to proceed? (y)
提示需要安装对应的包@eslint/create-config
,直接按回车
? How would you like to use ESLint? ...
To check syntax only
To check syntax and find problems
> To check syntax, find problems, and enforce code style
询问如何使用ESLint?根据实际需要自行选择,
这里选择第三种 检查语法、发现问题并强制执行代码样式
? What type of modules does your project use? ...
> JavaScript modules (import/export)
CommonJS (require/exports)
None of these
项目用哪种模块?项目用的ESM,所以也选这个
? Which framework does your project use? ...
React
> Vue.js
None of these
用的哪种框架?项目用的Vue
? Does your project use TypeScript? » No / Yes
是否使用TypeScript?因当时用vite建demo没选ts模板,所以这里也选No
? Where does your code run? ... (Press <space> to select, <a> to toggle all, <i> to invert selection)
√ Browser
√ Node
代码在哪运行,会对应开启配置env选项的环境变量。都勾选
? How would you like to define a style for your project? ...
> Use a popular style guide
Answer questions about your style
定义哪种风格配置,这里选第一种用流行的风格配置规则
? Which style guide do you want to follow? ...
Airbnb: https://github.com/airbnb/javascript
> Standard: https://github.com/standard/standard
Google: https://github.com/google/eslint-config-google
XO: https://github.com/xojs/eslint-config-xo
遵循哪种风格?前两种用的多点,有些规则不太同,Airbnb要求必须加行尾分号、函数名后面必须加空格,Standard则反之。这里对比我更喜欢第二种 Standard,不过团队开发规则都是用定制的多,比如我们开发就是用的公司团队定制的规则。
? What format do you want your config file to be in? ...
> JavaScript
YAML
JSON
配置文件使用哪种风格,都可,这里推荐使用JavaScript。
Checking peerDependencies of eslint-config-standard-with-typescript@latest
The config that you've selected requires the following dependencies:
eslint-plugin-vue@latest eslint-config-standard-with-typescript@latest @typescript-eslint/eslint-plugin@^5.43.0 eslint@^8.0.1 eslint-plugin-import@^2.25.2 eslint-plugin-n@^15.0.0 eslint-plugin-promise@^6.0.0 typescript@*
? Would you like to install them now? » No / Yes
提示需要安装这种依赖,是否现在安装,Yes、
? Which package manager do you want to use? ...
npm
yarn
> pnpm
用哪种包管理工具,看各自情况,我选用pnpm
最后这里根据选择自动生成.eslintrc.mjs文件,默认内容如下(默认内容一般还需要修改配置以适应团队规范)。
module.exports = {
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'plugin:vue/vue3-essential',
'standard'
],
overrides: [
],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module'
},
plugins: [
'vue'
],
rules: {
}
}
VS Code安装eslint插件
通过eslint npm包可以通过命令行来检查代码,还可以通过VS Code的eslint插件使我们在写代码的时候就能给出提示。
在商店安装ESLint插件
不需要额外配置,eslint插件会根据前面配置的eslint配置文件对代码进行提示。
结合prettier
eslint专注于检查代码规范,也可以格式化代码,主要保证代码质量。
prettier专注于格式化代码,不会修改代码内容,保证代码美观,而且prettier还支持格式化其它语言的代码。
eslint虽然也能格式化代码,但有一些格式问题还是需要通过prettier。
ESLint与Prettier容易有一些规则冲突,可通过eslint-config-prettier
和eslint-plugin-prettier
,使配置以prettier为重。如下步骤配置,
1,使用前需先安装依赖
pnpm add eslint-config-prettier eslint-plugin-prettier prettier -D
2,修改.eslintrc.cjs
module.exports = {
extends: [
// ...
// eslint-plugin-prettier插件输入的内置规则,配置在最后
'plugin:prettier/recommended'
]
}
3,新增.prettierrc.cjs
可以新增规则,新增.prettierignore
配置忽略文件(和.eslintignore配置类似)。
// .prettierrc.cjs 常规配置
module.exports = {
// 一行最多 100 字符
printWidth: 100,
// 使用缩进符,false表示使用空格缩进
useTabs: true,
// 使用多少个空格缩进,个人习惯2个,也很多人喜欢是用4个缩进
tabWidth: 2,
tabSize: 2,
// 行尾需要有分号
semi: false,
// 使用单引号
singleQuote: true,
// 对象的 key 仅在必要时用引号
quoteProps: 'as-needed',
// jsx 不使用单引号,而使用双引号
jsxSingleQuote: false,
// 末尾不需要逗号 'es5' none
trailingComma: 'es5',
// 大括号内的首尾需要空格
bracketSpacing: true,
// jsx 标签的反尖括号需要换行
jsxBracketSameLine: false,
// 箭头函数,只有一个参数的时候,也需要括号
arrowParens: 'always',
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: 'preserve',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'css',
// 换行符使用 lf 结尾是 \n \r \n\r auto
endOfLine: 'lf',
};
eslint-plugin-prettier
: prettier插件,将prettier规则作为eslint规则运行。该插件还内置了一个规则配置recommended
eslint-config-prettier
: prettier配置,该配置关闭了一些与prettier冲突的eslint规则。
上面第2步配置了eslint-plugin-prettier
插件的内置推荐配置recommended
,该配置内容如下。
{
// 开启了 eslint-config-prettier 配置
// 它关闭了一些与Prettier冲突的ESLint规则。
"extends": ["prettier"],
// 注册了该插件
"plugins": ["prettier"],
"rules": {
// 启动该插件提供的规则,以ESLint运行该规则
"prettier/prettier": "error",
"arrow-body-style": "off",
"prefer-arrow-callback": "off"
}
}
通过以上配置可解决一些冲突,但还是有可能出现冲突。比如.eslintrc.* rules中和.prettierrc.* 中有配置相反的规则就会有冲突。
假设perttier配置结尾需要分号,eslint配置结尾不能有分号。
通过
eslint-config-prettier
和eslint-plugin-prettier
可解决prettier和eslint冲突问题,若还有冲突检查pretter(.prettierrc.* )和eslint(.eslintrc.* )的配置是否一致。
结尾
eslint基本使用到这就结束了,相信对eslint有一定的了解,甚至自己还能制定规则了吧。如感觉文章有点啰嗦,或介绍的不得要领的话,还请见谅。如有不对地方欢迎指出~