0基础搞懂项目工程化配置--lint的关系

127 阅读10分钟

项目工程化配置--lint

1.husky

husky的作用就是形成git hooks钩子的形成,在git的各种操作,会调用husky对应的一些操作

// 安装husky
npm install husky
// husky初始化(作用就是生成.husky文件)
npx husky init
// .husky/_/里面的文件就是一些git会调用的一些hooks,外面的是自己写的hooks,因为里面的一些hooks定义了解释器和执行脚本,所以在外部自己写的一些hooks就不需要要去配置,如果里面没有这些操作,则需要在自定义hooks里面写上该解释器和加载该脚本

image.png

1.1 pre-commit

# pre-commit 里面就是在commit之前会调用的,在这里可以使用eslint,stylelint,prettier校验,格式化代码
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx eslint && npx stylelint && npx prettier

1.1.1 为什么使用lint-staged
# pre-commit文件 
# 按道理应该如上这样去写,但是这里使用lint-staged,是因为上面的代码每次都是全量扫描及修复,会很浪费性能,所以使用lint-staged只对暂存区进行校验,你可以理解为lint-stage是一个集合操作,把所有的lint操作都集合在了一起,只对暂存区生效
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged -c .lintstagedrc.json

lint-staged需要一个配置文件,该配置文件告诉了lint-staged如何操作,如下所示,对代码进行了eslint,prettier和stylelint校验和修复

//.lintstagedrc.json
{
  "{src,public}/**/*": [
    "pnpm exec eslint -c .eslintrc.cjs --ignore-path .eslintignore --fix src/ public/",
    "prettier --write --ignore-unknown src/"
  ],
  "{src,public}/**/*.{css,scss,vue,html}": [
    "pnpm exec stylelint --config .stylelintrc.json --fix \"src/**/*.{css,scss,vue}\" \"public/**/*.html\""
  ]
}

1.2 commit-msg

# commit-msg 里面就是在commit提交信息前所进行的操作,这里进行的操作是对commit的信息进行校验,具体校验规则会放到单独的commitlint讲解
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no -- commitlint --edit ${1}

至此,husky的作用就完成了。

2.lint-staged里面的lint

代码lint阶段分为eslint,prettier,stylelint

2.1 eslint

eslint用来校验js,根据解析器生成ast树去检查语法和词法,可以使用插件进行扩展就可以对vue、typescript等文件进行校验,可以使用别人提前规范好的config,直接使用他们的规则

# 安装eslint
npm intsall eslint
# 初始化,创建配置文件
npx eslint --init

[!IMPORTANT] 注意:eslint@8版本生成的配置文件为.eslintrc.js,eslint@9版本以后生成的配置文件为eslint.config.mjs,并且eslint@9移除了样式格式化,样式格式化建议采用prettier,具体可参考 文档

// .eslintrc.js
module.exports = {
    "env": {
        "browser": true,
        "es2021": true,
        "node": true
    },
    "extends": "eslint:recommended",
    "overrides": [
        {
            "env": {
                "node": true
            },
            "files": [
                ".eslintrc.{js,cjs}"
            ],
            "parserOptions": {
                "sourceType": "script"
            }
        }
    ],
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
  	"ignorePatterns": ["temp.js", "**/vendor/*.js"],
    "rules": {
    }
}

//eslint.config.mjs
import globals from "globals";
import pluginJs from "@eslint/js";

export default [
  {languageOptions: { globals: {...globals.browser, ...globals.node} }},
  pluginJs.configs.recommended,
];

由于脚手架和以前项目都是eslint@8,所以本文只对eslint@8进行说明

2.1.1 env与globals和文件的关系

你直接在一个js文件中使用Window,会报错not defined,原因是eslint他检查出来没有定义,但我们在网页使用的时候是一定有这个东西的,所以我们在globals里面定义一个Window,这样子eslint看到以后,喔~我有这个变量,于是就不报错了,但是我们浏览器有很多变量,你能把它一个一个都加在globals里面吗,是的 有人已经做了,env的作用就是把这种环境变量统一加进去,避免我们操作

image.png

上图globals和env.browser任何一个都可以解决掉Window报错

2.1.2 rules 规则

rules就是一套规则,在eslint里面已经预设了很多,大概200多条吧,你可以创建项目的时候根据这些规则去写自己需要的(开玩笑的),首先你得清楚这些规则就是在eslint校验代码的时候用的,其次这些规则当你想集成的时候已经有人做了

  • eslint:recommended 推荐配置,eslint在这些规则里面推荐了一些自己觉得好的
  • eslint:all 所有配置,你的代码必须遵守我所有的规则,否则我就报错
  • 第三方配置,比如你在框架创建的时候让你选择的airbnb,standard等

rules在查看的时候,里面的对钩意思就是在eslint:recommended里面存在的,小扳手的意思是eslint可以自动修复,小灯泡的意思是这些需要手动修复

2.1.3 extends继承

就如同class的继承一样,他也是继承别人的配置,比如默认配置中就是继承了eslint:recommended 配置文件,

比如我们自己安装一个第三方的配置推荐文件(都是以eslint-config开头)

# 安装第三方配置包
npm intsall eslint-config-standard
//eslintrc.js
module.exports = {
    "extends": ["eslint:recommended","standard"],
    "rules": {
      semi: 'off'
    }
}

此处的eslint-config-可以省略,如果推荐的第三方里面有一些规则你不喜欢,你可以在rules里面改为warn或者off

2.1.4 plugins插件

eslint默认只对js这些起作用,那如果是ts和vue的话,eslint本身是无能为力的,但是借助plugins就可以拓展eslint的能力,让其有在ts和vue中校验的能力(都是以eslint-plugin开头)

npm intsall eslint-plugin-vue
module.exports = {
  extends: [
    // add more generic rulesets here, such as:
    // 'eslint:recommended',
    'plugin:vue/vue3-recommended',
    // 'plugin:vue/recommended' // Use this if you are using Vue.js 2.x.
  ],
  // plugins:['vue']
  rules: {
    // override/add rules settings here, such as:
    // 'vue/no-unused-vars': 'error'
  }
}

比如上述的配置,在安装完之后就需要需要 plugins:['vue'] (可省略eslint-plugin-),引用了之后,对了,仅仅是引用,并无卵用,你插件装了,eslint有这个校验vue的能力,但是他没规则呀,所以在extends里面就需要继承这个插件里面推荐的规则集(配置文件),这样子才算完整,同时,因为你有这个extends就默认了你要用这个插件,插件这个就可以忽略掉了

2.1.5 parser解析器

有些插件使用了之后,还需要更改解析器

npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint typescript
/* eslint-env node */
module.exports = {
  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  root: true,
};

为什么要更改解析器?是当你的文件默认解析器无法识别并解析成为AST树校验的时候,就需要对特殊文件指定对应的解析器

2.1.6 overrides

这个配置,普遍性和特异性 这个就是特异性,针对特定文件进行特定eslint的配置,里面的参数配置基本和外部的差不多,都有extends,plugins,rules等

需要值得注意的是里面配置文件的glob模式

module.exports = {
  root: true,
  env: {
    browser: true,
    es2021: true,
  },
  extends: ['eslint:recommended'],
  parserOptions: {
    ecmaVersion: 12,
    sourceType: 'module',
  },
  rules: {
    'no-console': 'warn', // 全局规则
  },
  overrides: [
    {
      files: ['*.ts'], // 针对所有 TypeScript 文件
      parser: '@typescript-eslint/parser', // 使用 TypeScript 解析器
      plugins: ['@typescript-eslint'], // 使用 TypeScript 插件
      extends: [
        'eslint:recommended',
        'plugin:@typescript-eslint/recommended', // 引入 TypeScript 推荐规则
      ],
      rules: {
        'no-unused-vars': 'off', // 在 TypeScript 中关闭该规则
      },
    },
    {
      files: ['*.jsx'], // 针对所有 JSX 文件
      rules: {
        'react/prop-types': 'off', // 关闭 prop-types 规则
      },
    },
    {
      files: ['*.test.js'], // 针对所有测试文件
      env: {
        jest: true, // 指定测试环境
      },
      rules: {
        'no-unused-expressions': 'off', // 关闭该规则以允许 chai 断言
      },
    },
  ],
};
  • 对所有的js使用eslint:recommended配置
  • 对ts使用ts配置,并更改解析器
  • 对jsx和测试文件更改特定规则和指定环境
2.1.7 eslint忽略文件
2.1.7.a ignorePatterns
  • ignorePatterns 中的 glob 模式是相对于配置文件所在的目录而言的。
  • 你不能在 overrides 属性中使用 ignorePatterns 属性。
  • .eslintignore 中定义的模式优先于配置文件的 ignorePatterns 属性。
2.1.7.b .eslintignore

跟.gitignore一样忽略想要忽略的文件或文件夹,注意分隔符用正斜杠,默认是忽略node_modules

2.1.8 .eslintrc/.eslintrc.js、.eslintignore 和 package.json中eslint配置的关系
{
    "name": "mypackage",
    "version": "0.0.1",
    "eslintConfig": {
        "env": {
            "browser": true,
            "node": true
        }
    },
    "eslintIgnore": ["hello.js", "world.js"]
}

eslint会默认先采用.eslintrc/.eslintrc.js、.eslintignore的配置,其次才会去才去package.json的配置

[!TIP] 建议采取单独文件配置,这样package.json清爽

2.2 eslint 与 vscode eslint插件的区别

很多人容易把eslint和eslint插件搞混,其实一句话就概括了,eslint只是一个npm包,在你执行命令时候才会执行,你所看到vscode界面上的错误都是eslint插件调用你的eslint npm包,用你的配置文件.eslintrc起了一个服务,然后实时监测你的文件变化,有错我就给你标红

[!CAUTION]

注意:eslint插件的状态可以在输出,eslint中查看,如果最下面eslint状态红的时候,就说明插件运行有问题,就得需要去排查,下面的两处错误,是我从eslint@9改成eslint@8,但是配置文件还是eslint@9的配置文件报的错

image.png

2.3 prettier

2.3.1 安装prettier
npm install --save-dev --save-exact prettier

当你使用 npm install --save-dev --save-exact prettier,npm 会将依赖项版本号精确保存到 package.json,不允许自动升级到兼容的次版本或补丁版本。

2.3.2 prettier配置文件

配置文件有很多,只列举了其中一种,可以是js也可以是json

//.prettierrc
{
  "trailingComma": "es5",
  "tabWidth": 4,
  "semi": false,
  "singleQuote": true,
  "overrides": [
    {
      "files": "*.test.js",
      "options": {
        "semi": true
      }
    },
    {
      "files": ["*.html", "legacy/**/*.js"],
      "options": {
        "tabWidth": 4
      }
    }
  ]
}

与eslint很像,也有对特殊需求的处理,当然也有对继承的处理

image.png

2.3.3 prettier忽略文件

跟.gitignore和.eslintignore一样

//.prettierignore
# Ignore artifacts:
build
coverage

# Ignore all HTML files:
**/*.html
2.3.4 prettier与eslint、stylelint起冲突

如果你使用 ESLint,请安装 eslint-config-prettier 以使 ESLint 和 Prettier 相互配合。它会关闭所有不必要的或可能与 Prettier 冲突的 ESLint 规则。Stylelint 有一个类似的配置:stylelint-config-prettier

2.3.5 prettier与.editconfig/vscode的setting起冲突

都是以.prettierrc为主

2.4 stylelint

2.4.1 stylelint安装
npm install --save-dev stylelint stylelint-config-standard
2.4.2 stylelint配置文件
//.stylelintrc{
{
  "extends": ["stylelint-config-standard", "./myExtendableConfig"],
  "rules": {
    "alpha-value-notation": "number"
  },
  "overrides": [
    {
      "files": ["*.scss", "**/*.scss"],
      "customSyntax": "postcss-scss"
    },
    {
      "files": ["components/**/*.css", "pages/**/*.css"],
      "rules": {
        "alpha-value-notation": "percentage"
      }
    }
  ],
  "ignoreFiles": ["**/*.js"]
}

配置文件与eslint配置文件类似,也有特殊项配置,rules参考官网,extends继承一个config

2.4.3 stylelint忽略文件

同eslint配置一样可以在配置文件中加忽略文件,也可以单独一个忽略文件

//.stylelintignore
vendor/**/*.css

3.commitlint

commitlint是校验commit信息的一个npm包

# 第一步 安装@commitlint等工具,@commitlint/config-conventional 是 Commitlint 的预定义配置,它提供了一组基于 Conventional Commits 标准的规则,用于验证提交信息是否符合规范。
npm install --save-dev @commitlint/config-conventional @commitlint/cli


# 需要一个配置文件名为commitlint.config.js,当 husky commit-msg 钩子调用的时候, npx commitlint 的时候会自动读取,从而使用规范标准校验
echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js

那此时有人说那我就直接提交每次不是这不对,就是那不对,是的,因为如果你没学这个规范标准的话,你提交不正确就会报错,所以推荐使用commitizen

3.1 扩展 commitizen

为了使用户git提交符合规范的信息,使用的是 commitizen ,这个npm包的作用就是替代用户自己git commit -m '阿巴阿巴',生成比较规范的提交信息

# 看你自己需求,需不需要全局安装
npm install commitizen

# 如果是仅仅安装了这个包,使用npx cz的时候,会跳出下面的信息,

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch main
# Changes to be committed:
#       modified:   .husky/commit-msg
#       modified:   .husky/pre-commit
#
# Changes not staged for commit:
#       deleted:    .czrc
#
# Untracked files:
#       .czrc11
#

# 应该是看着一脸懵逼,所以需要给commitizen一个适配器,适配器就是创建交互式信息,让你按照他的流程创建,我们因为使用的是commitlint去校验,所以我们安装符合commitlint的适配器

npm install @commitlint/cz-commitlint

安装了以后,需要一个配置文件,告诉commitzen我给你配的适配器是@commitlint/cz-commitlint,两者选择其一即可

a.在package.json中的config字段配置
 "config": {
    "commitizen": {
      "path": "@commitlint/cz-commitlint"
    }
  }
b.创建一个文件.czrc
{
  "path": "@commitlint/cz-commitlint"
}

此时再去运行npx cz,则得到一个符合commitlint的交互式提示,按照该提示进行操作,就不会报错了

npx cz
# ? Select the type of change that you're committing: (Use arrow keys)
# ❯ feat:       A new feature 
#   fix:        A bug fix 
#   docs:       Documentation only changes 
#   style:      Changes that do not affect the meaning of the code (white-space, formatting, # missing semi-colons, etc) 
#   refactor:   A code change that neither fixes a bug nor adds a feature 
#   perf:       A code change that improves performance 
#   test:       Adding missing tests or correcting existing tests