Eslint+Prettier+Husky+lint-staged构建前端工作流

585 阅读8分钟

需求背景

现状

最近新接手一个小程序项目,不管是从项目目录结构划分还是代码层面,整体看起来一个字:乱!!!下面描述的情况随处可见,还有很多未列举的。

// 1-申明了变量却未使用
const util = require('xxx')


// 2-对于后续无修改的变量,还是用var/let申明的
let device = 'iPhone 12'


// 3-后端返回的type, 建议用===对后端输出的数据类型做强类型校验
// 下面的写法后端返回1 or '1'都会走TODO,后端输出不太严谨
if(type == 1) { // TODO }


// 4-单引号、双引号不确定-> 代码样式感
var device = 'iPhone 12'
var version = "v4.5.0.20220524"

预期目标

  • 提升代码一致性、可读性

  • 提升代码洁癖

基础实践

技术总指南: eslint + prettier + husky + lint-staged

    1. 项目根目录package.json中新增如下配置
"devDependencies": {
  "@babel/core": "^7.16.7",
  "@babel/eslint-parser": "^7.16.5",
  "eslint": "^8.5.0",
  "eslint-plugin-prettier": "^4.0.0",
  "prettier": "^2.5.1"
}
    1. 安装依赖
npm install
    1. 项目根目录下新建.eslintrc.js文件(注意: 文件名是.eslintrc.js而不是eslintrc.js)
module.exports = {
  root: true,
  env: {
    es6: true,
    browser: true,
    node: true,
  },
  parser: '@babel/eslint-parser',
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
    ecmaFeatures: {
      // lambda表达式
      arrowFunctions: true,
      // 解构赋值
      destructuring: true,
      // class
      classes: true,
    },
  },
  globals: {
    wx: true,
    App: true,
    Page: true,
    getCurrentPages: true,
    getApp: true,
    Component: true,
    requirePlugin: true,
    requireMiniProgram: true,
  },
  rules: {},
}
    1. 项目根目录下新建.eslintignore文件, 该文件主要用来配置哪些目录or页面可跳过eslint的校验(忽略路径是相对项目根目录路径而言的)。
node_modules
    1. 新建.prettierrc.js文件, 该文件是关于prettier相关配置。
module.exports = {

}
    1. 新建.babel.config, 暂时未发现什么用。
module.exports = {
  presets: [],
  plugins: [],
}
    1. package.json中新增lint脚本命令, 避免每次都需要手动输入很长的一段执行命令
"scripts": {
  "lint": "eslint --ext .js ./"
}
    1. 配置完成,进入测试阶段,如下为测试文件。
// 测试文件代码-test.js
const testFn = function () {
    let name = 'test'
    let age = 20
    let userinfo = {}
    userinfo.name = name
    userinfo.age = age
}
testFn()
    1. 执行测试脚本
npm run lint
    1. 运行效果,报错了。

咦,看图好像所有的报错信息都一样Error:

报错信息: Parsing error: No Babel config file detected for /user/xxx/. Either disable config file checking with requireConfigFile: false, or configure Babel so thar it can find the config files.

解决方案: 在.eslintrc.js文件中新增如下配置。

parserOptions: {
  requireConfigFile: false
}
    1. 再次执行测试脚本,看效果。

咦,竟然0 errors,明显跟预期不符合。

问题所在: .eslintrc.js文件中rules规则字段未配置。

    1. .eslintrc.js文件中新增rules规则配置
rules: {
  'prefer-const': 1, // 要求使用 const 声明那些声明后不再被修改的变量
}
    1. 再次执行测试脚本,看效果。

根据error or warning信息,找到对应的文件去做修改即可。

至此,你已经成功了一半了,继续加油哦。

进阶实践

通常在刚开始搭建项目的时候没考虑这么多,随着项目团队人员的增加&需求变多,规范化的前端工作流很有必要,很多是对旧项目接入eslint,用上面的基础方案会面临一些问题:

  • 旧项目导出可见var/let申明的常量,比如上面那条规则可能就有几千个error(吓得立马删规则跑路),能否实现增量更新呢 (即若对全工程的文件进行扫描&&之前的前段工程并未主动代码规则的检测,很大可能出现成百上千个error,基本上是崩溃的。因此要及时止损,只对当前add的文件进行检测,历史代码可以切换到新分支进行修复后合并)

在接手的旧项目中引入eslint后,报错信息足足2000多条,简直难以想象(因涉及到公司很多代码就不附图了)

下图为个人的一个小程序旧项目引入eslint后,报错信息也有几百条,费劲哦:

  • 每次都需要人工执行npm run lint太繁琐了、不科学。

**Husky + lint-stage能够帮我们解决上述问题。
**husky是一个为git客户端增加hook的工具。用于对Git暂存区中的文件执行代码检测,结合husky用到pre-commit这个hook,在执行commit之前,可以运行一些自定义操作。

实现原理剖析:

  • 待提交的代码git add添加到暂存区
    • 完成对增量代码的检查、进入stage区的文件进行扫描即可
  • 执行git commit

  • husky注册在git pre-commit的钩子函数被调用,执行lint-staged

  • lint-staged取得所有被提交的文件依次执行写好的任务(Eslint && Prettier)

  • 若有错误则停止任务同时打印错误信息;等待修复后再commit

  • 若无错误则成功commit,可push到远程;

接下来我们看看要怎么样需求才能被实现呢?

    1. 安装husky && lint-staged
npm install -D husky lint-staged
    1. package.json中新增相关配置
      But需要注意的是:pre-commit钩子虽可在执行git commit的时候触发 → 比如lint检查、单元测试、代码美化等操作但是要保证速度不要太慢,不然每次commit很久也是不好的体验。
"husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.js": [
      "eslint",
      "prettier --write",
      "git add"
    ]
  }
    1. 测试git bash or sourceTree提交(测试代码用的如上的test.js)

咦,好像没生效啊,直接提交成功了:

问题所在: husky跟pre-commit未建立关联。

    1. 在终端输入如下命令

该命令会在.husky文件夹下新建.pre-commit文件, 你需要留意是否有生成。

npx husky add .husky/pre-commit "npx lint-staged"
    1. 再次验证查看效果: ok的

至此,其实就已经满足了整个符合eslint规范的代码才允许被提交,构建了统一的工作流。但其实还遗留了两个问题:

  • 若每次提交的文件过大,eslint的时间是成正比增加的,那能否在我们编码的时候就暴露问题呢?

  • eslint rules配置千千万,怎么选择适合团队的rules规则呢,是否能用一些主流的规范呢?

若您想解决这俩个问题,请往下看👇!!!

高级实践

    1. 接入编码过程实时报错
    • 1.1 编辑器vscode安装插件: 插件-搜索eslint-安装插件

安装插件成功后记得重新下编辑器, 然后你就能看到编码中的文件test.js相关的报错信息在调试器-问题处可实时查看。

其实本身不符合规范的, 基于安装的eslint版本是v2.2.2,也是会在文件处用波浪线表示,鼠标移上去会有相应的错误处理方案, eg如下图:

扩展: 非所有的开发者都会选择用vscode编辑器,对于使用微信开发者工具的开发者,其实也是可以引入eslint插件的,感兴趣的可戳此链接: 微信开发者工具扩展插件版本能否支持手动更新?

    1. 接入airbnb规范
    • 2.1 package.json中新增下面依赖
npm install eslint-config-airbnb --save-dev
npm install eslint-config-airbnb-base --save-dev
    • 2.2 修改.eslintrc.js文件
extends: [
   'airbnb-base',
   // 'plugin:promise/recommended'
   'prettier',
 ],
    • 2.3 去除.eslintrc.js中rules的配置,默认使用airbnb的,不满足团队规范的在此处做覆盖即可。
// delete rules的配置
rules: {


}
    • 2.4 执行npm run lint命令测试airbnb是否引入成功

你会看到报错信息,之前的warning警告也变成了error, 是应用了airbnb的效果。

可选配置

eslint auto fix

    1. 其实eslint的部分rules是支持自动fix的,若我们想实现该功能,可修改package.json文件中的lint命令。
"scripts": {
  "lint": "eslint --fix --ext .js ./"    // 新增该语句
}
    1. 测试运行效果,执行npm run lint脚本
// test.js
const testFn = function () {
  const userinfo = {};
  let sex = '女';
  userinfo.sex = sex;
};
testFn();


// npm run lint自动fix后该文件变动如下:
const testFn = function () {
  const userinfo = {};
  const sex = '女';
  userinfo.sex = sex;
};
testFn();

你会发现,自动把对于let申明的变量后续无修改的,自动改成建议的const申明为常量。But不是所有的规则都适合fix,目前刚接入的阶段,建议采用人工fix比较好。

prettier的配置

prettier主要是用于统一样式,比如双引号、单引号这种。

  • .prettier文件中新增如下配置
module.exports = {
  singleQuote: true   // 统一格式化后单引号
}
  • 测试代码如下
const testFn = () => {
  const userinfo = {};
  const sex = "女";
  userinfo.sex = sex;
};
testFn();
  • 借助sourcTree提交后的效果:

咦,好像配置不生效啊,因为没有主动改成单引号:

经过排查之后发现是prettier的配置文件名写错了, 应该是.prettierrc.js而不是.prettier.js哦,需要小心。
纠正后再次测试,OK的,已经生效。

落地相关QA(持续更新)

问题一

问题描述: 使用mac的某一个小伙伴反馈在mac系统提交的代码没走eslint校验,大概率是由于脚本是不可执行的,执行下如下脚本给执行脚本添加执行权限。

解决方案如下: 项目根目录下执行如下脚本添加权限.

chmod ug+x .husky/*

问题二

问题描述: 切换到新分支,然后一顿操作写了很多代码提交,咦,发现竟然没法提交代码了。

报错信息如下: Some of your tasks use git add command. Please remove it from the config since all modifications made by tasks will be automatically added to the git commit index.

后经排查发现:有同事在新分支上对.husky目录下的钩子文件有改动。

解决方案如下: 删除本地node_modules文件,重新npm install一下即可.

写在最后

若有错误之处, 恳请留言, 定会及时更正!

创作不易,如果您从文章中学到了东西,麻烦点个赞或者关注下再走呗,您的支持是我持续创作的动力!