EditorConfig、Eslint 、Prettier、Husky、Commitlint、Lint-staged、commitizen 规范前端工程代码规范

297 阅读10分钟

开发中,代码的规范很重要。当一个前端项目有多个开发者时,每个开发者都有自己的编码风格,甚至大家用的格式化插件都不一样,最终就会造成代码风格混乱,一定程度上造成了代码维护上的难度。

好在根据现有的工具和插件便可以做到团队之间代码的规范统一,于是写下来做记录和参考。

EditorConfig

场景值:编辑器和IDE编写代码,保持一致的简单编码风格,有助于从事同一项目的开发人员再跨多个编辑器和IDE使用时保持一致的编码风格。EditorConfig包含的内容比较少,主要是配置我们的编辑器,编写代码时的简单规则,不足以满足项目更多需求

主流编辑器支持
  • 默认支持,Webstorm、IntelliJ IDEA
  • 需要安装插件支持,Visual Studio Code、Atom
支持多种文件

文件匹配规则传送门:editorconfig.org/#file-forma…

就近原则

打开文件时,EditorConfig插件会在打开的文件的目录中以及每个父目录中查找名为.editorconfig的文件。如果到达根文件路径或找到root = true的EditorConfig文件,将停止对.editorconfig文件的搜索。 离文件最近的配置规则生效,优先级更高;一般在根目录设置一个配置文件即可。

配置文件
    # http://editorconfig.org
    root = true

    # 说明
    ## 设置文件编码为 UTF-8;
    ## 用两个空格代替制表符;
    ## 在保存时删除尾部的空白字符;
    ## 在文件结尾添加一个空白行;
    [*]
    indent_style = space
    indent_size = 2
    end_of_line = lf
    charset = utf-8
    trim_trailing_whitespace = true
    insert_final_newline = true

    [*.md]
    trim_trailing_whitespace = false

    [Makefile]
    indent_style = tab

Prettier

Prettier很多配置项是 JS 这门语言特有的规范。Editorconfig和Prettier二者有重叠的部分,但大部分并不相同。所以前端项目往往两者都有,非要只选一个的话选 Prettier 而不是 EditorConfig。

配置项

  • VSCode 首选项-设置-扩展.settings.json中更改通用配置
{
    // 使能每一种语言默认格式化规则
    "[html]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[css]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[less]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[javascript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },

    /*  prettier的配置 */
    "prettier.printWidth": 120, // 超过最大值换行
    "prettier.tabWidth": 2, // 缩进字节数
    "prettier.useTabs": false, // 缩进不使用tab,使用空格
    "prettier.semi": true, // 句尾添加分号
    "prettier.singleQuote": true, // 使用单引号代替双引号
    "prettier.proseWrap": "preserve", // 默认值。因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行
    "prettier.arrowParens": "avoid", //  (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号
    "prettier.bracketSpacing": true, // 在对象,数组括号与文字之间加空格 "{ foo: bar }"
    "prettier.disableLanguages": ["vue"], // 不格式化vue文件,vue文件的格式化单独设置
    "prettier.endOfLine": "auto", // 结尾是 \n \r \n\r auto
    "prettier.eslintIntegration": false, //不让prettier使用eslint的代码格式进行校验
    "prettier.htmlWhitespaceSensitivity": "ignore",
    "prettier.ignorePath": ".prettierignore", // 不使用prettier格式化的文件填写在项目的.prettierignore文件中
    "prettier.jsxBracketSameLine": false, // 在jsx中把'>' 是否单独放一行
    "prettier.jsxSingleQuote": false, // 在jsx中使用单引号代替双引号
    "prettier.parser": "babylon", // 格式化的解析器,默认是babylon
    "prettier.requireConfig": false, // Require a 'prettierconfig' to format prettier
    "prettier.stylelintIntegration": false, //不让prettier使用stylelint的代码格式进行校验
    "prettier.trailingComma": "es5", // 在对象或数组最后一个元素后面是否加逗号(在ES5中加尾逗号)
    "prettier.tslintIntegration": false // 不让prettier使用tslint的代码格式进行校验
}

  • .prettierrc单独配置 (优先级最高),最后格式化的生效策略同样是就近原则,一步步匹配目标文件最近父目录的配置文件,越近优先级越高。
{
  // 设置强制单引号
  "singleQuote": true,
  // 为多行数组的非末尾行添加逗号 es5的对象,数组等
  "trailingComma": "es5",
  // 每行最大宽度 100
  "printWidth": 100,
  // 设置语句末尾不加分号
  "semi": false,
  // jsx中使用单引号
  "jsxSingleQuote": true,
}

Eslint

场景值:代码识别和报告的插件化的检测工具,它的目的是保证代码规范的一致性和及时发现代码问题、提前避免错误发生。

配置项

// .eslintrc.js
module.exports = {
  //...
  extends: [
    'eslint-config-myconfig',    // 全称
//  'myconfig'                      缩写
    'plugin:myplugin/recommended'// 插件中的 extends
  ], 
  plugins: ['myplugin'],
  rules: {
    'quotes': 'single',
    'space-before-blocks': 'always',
    'myplugin/hello': true      //  自定义插件规则
  },
  //...
};
  • extends 扩展,集成一个个配置方案的最佳实践,即别人配置好的规则
  • plugins 扩展,一堆自定义的规则的集合。可能有:总结的最佳实践。比如说禁止项目中setTimeout的第二个参数是数字,那么就需要写一个这样的插件来进行约束。再比如对vue中template代码进行约束。

配置总览

{
    // 别人可以直接使用你配置好的ESLint, ESLint 一旦发现配置文件中有 "root": true,它就会停止在父级目录中寻找。
    "root": true,
    
    // 指定解析器
    "parser": "babel-eslint",
    
    // 指定解析器选项,EsLint通过parserOptions,允许指定校验的ecma的版本,及ecma的一些特性
    "parserOptions": {
        "ecmaVersion": 2019, // 指定ECMAScript支持的版本,6为ES6
        "sourceType": "module", // 指定来源的类型,有两种”script”或”module”
        "ecmaFeatures": {
            "jsx": true // 启动JSX
        }
    },
    
    // 加入第三方插件,三方插件同样提供rules、extends等配置
    "plugins": ["vue"],
        
    // 继承别的规则配置文件
    "extends": [
        "eslint:recommended",
        "plugin:jest/recommended",
        "plugin:vue/recommended",
        "prettier"
    ],
    
    // 指定将在所有插件规则之间共享的设置
    "settings": {
        
    },
        
    // 指定规则
    "rules": {
        "no-new": 0, // 是否允许new构造函数不赋值给变量
        "no-shadow": 0, // 是否允许来自被屏蔽的变量的变量声明(比如一个被全局定义过的变量 是否允许在局部的function里再次被定义)
        "camelcase": 1, // 是否强制使用驼峰拼写法命名规定
        "no-bitwise": 0, // 按位操作的规则
        "func-names": 0, // 定义方法的规则
        "no-console": 0, // 是否允许使用console
        "no-plusplus": 0, // 是否允许 ++ -- 这样的操作写法
        "arrow-parens": 2, // 方法箭头左侧属性是否加()
        "comma-dangle": 0, // 结尾处k-v值后面是否允许逗号
        "default-case": 0, // switch-case语句是否强制加default case
        "prefer-template": 0, // 是否强制使用``这样的template字面量符号代替拼接字符串
        "consistent-return": 0, // 是否强制return指定值
        "no-param-reassign": 0, // 是否禁止参数变量再分配值
        "no-nested-ternary": 0, // 是否禁止嵌套三元表达式
        "operator-linebreak": 0, // 是否强制段行风格
        "object-curly-newline": 0, // 是否强制花括号内段行风格
        "no-underscore-dangle": 1, // 是否强制下划线变量命名风格
        "no-unused-expressions": 0, // 是否禁止不用的表达式存在
        "no-restricted-globals": 0, // 是否禁用特定的全局变量(可自定义)
        "function-paren-newline": 0, // 是否强制方法的参数换行
        "class-methods-use-this": 0, // 是否强制class函数体内出现this
        "implicit-arrow-linebreak": 0, // 是否不允许方法中=>右边换行
        "space-before-function-paren": 0, // 是否强制方法圆括号左边空格
        "max-len": ["error", {"code": 150}], // 是否强制代码一行内的字符上限
        "prefer-destructuring": 0, // 是否强制使用对象解构
    },
    
    // env:你的脚本将要运行在什么环境中
    // Environment可以预设好的其他环境的全局变量,如brower、node环境变量、es6环境变量、mocha环境变量等
    "env": {
        "browser": true,
        "commonjs": true,
        "es6": true
    },
    
    // 指定你所要使用的全局变量,true代表允许重写、false代表不允许重写
    "globals": {
        "window": false,
        "document": false,
        "navigator": false
    }
}

Husky 版本 ^7.0.1

对git执行的一些命令,通过对应的hooks钩子触发,执行自定义的脚本程序。当您提交或推送时,您可以使用它来检查您的提交消息运行测试、检查代码等。Husky 支持所有 Git 钩子

配置使用教程

传送门:typicode.github.io/husky/#/?id…

Commitlint

帮助您的团队遵守提交约定。通过支持 npm 安装的配置,它使提交约定的共享变得容易。用来规范commit的提交
首先认识公认的commit message传送门:www.cnblogs.com/youcong/p/9…

设置

commitlint.config.js配置

/**
 * @description commit-msg校验规则
 * @link https://commitlint.js.org/#/
 * @typeEnum
 * feat 新增功能
 * fix bug修复
 * refactor 代码重构
 * style 不影响程序逻辑的代码修改(修改空白字符,补全缺失的分号等)
 * test 新增测试用例或是更新现有测试
 * revert 回滚某个更早之前的提交
 * chore 改变构建流程、或者增加依赖库、工具等
 * merge 代码合并
 * docs 文档改动
 */
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [2, 'always', ['docs', 'feat', 'fix', 'refactor', 'docs', 'chore', 'style', 'revert', 'merge']],
    'type-case': [0],
    'type-empty': [0],
    'scope-empty': [0],
    'scope-case': [0],
    'subject-full-stop': [0, 'never'],
    'subject-case': [0, 'never'],
    'header-max-length': [0, 'always', 72],
  },
}

Lint-staged

本地暂存代码检查工具,只会对暂存区的文件运行已经配置linter或其他任务,可以对特定文件执行特定的操作。例如如下配置 1.对所有js文件pretter格式和eslint校验 2.针对run文件夹下,从索引中删除文件,但是本地文件还存在,只是不希望这个文件被版本控制

"lint-staged": {
    "**/*.js": [
      "prettier --write ./ ",
      "eslint",
     ],
    "dist/*": [
      "git rm --cached"
     ]
  },

lint-staged传送门:www.npmjs.com/package/lin…

commitizen

Commitizen 是一个帮助撰写规范 commit message 的工具。他有一个命令行工具 [cz-cli],借助它提供的 git cz 命令替代 git commit 命令,生成符合规范的 commit message,(link.segmentfault.com/?enc=T2sl3h…)

使用官方默认配置

// 1. 安装 commitizen
npm install commitizen -D

// 2. 安装和初始化 cz-conventional-changelog
npx commitizen init cz-conventional-changelog --save-dev --save-exact

// 3. 使用git cz

image.png

自定义配置校验配置

1. 安装cz-customizable
yarn add  cz-customizable -D


2.在package.json中添加配置代码
{
  ...
  "scripts": {
    "commit": "cz"
  },
  "config": {
    "commitizen": {
      "path": "./node_modules/cz-customizable"
    },
    "cz-customizable": {
      "config": ".cz-configrc.js"
    }
  }
}

3. 在根目录添加cz配置文件,并添加配置
touch .cz-config.js

4. 配置文件详情
module.exports = {
  types: [
    { value: 'wip', name: '💪  Work in Progress | 开发中' },
    { value: 'feat', name: '✨  Features | 新功能' },
    { value: 'fix', name: '🐛  Bug Fixes | 修复' },
    { value: 'style', name: '💄  Styles | 代码样式' },
    { value: 'refactor', name: '🔨  Code Refactoring | 代码重构' },
    { value: 'ci', name: '💚  Fixing CI Build | CI 配置' },
    { value: 'revert', name: '⏪  Revert | 回退' },
    { value: 'build', name: '📦  Build System | 打包构建' },
    { value: 'chore', name: '🗯   Chore | 构建/工程依赖/工具' },
    { value: 'test', name: '✅  Tests | 测试' },
    { value: 'docs', name: '📝  Documentation | 文档变更' },
    { value: 'init', name: '🚀  Init | 初始化' },
  ],

  // 步骤
  messages: {
    type: '请选择提交的类型;',
    customScope: '请输入修改的范围(可选)',
    subject: '请简要描述提交(必填)',
    body: '请输入详细描述(可选)',
    footer: '请选择要关闭的issue(可选)',
    confirmCommit: '确认要使用以上信息提交?(y/n)',
  },

  // 跳过步骤
  skipQuestions: ['customScope','body', 'footer'],

  // 模块名
  // scopes: [{ name: 'account' }]

  // 默认长度
  subjectLimit: 72,
}

样式如下: image.png

其中我们不一定全部使用,比如我们团队不想在提交过程中一步步确认,那么就可以不使用commitizen,不过每次提交就得记住commitlint.config.js的提交规范。


以上完整的配置传送门:github.com/lecheng-lc/…


相关问题QA

Q:VSCode ESLint插件.eslintignore文件不生效原因 A:juejin.cn/post/684490…

Q:esllint和prettier冲突
A:使用eslint-plugin-prettier插件来解决,在eslint.js中的extends属性中

module.exports = {
  extends: ['standard', 'prettier']
}

Q:eslint配置文件优先级怎行的

  • JavaScript - 使用 .eslintrc.js 然后输出一个配置对象。
  • YAML - 使用 .eslintrc.yaml 或 .eslintrc.yml 去定义配置的结构。
  • JSON -使用 .eslintrc.json 去定义配置的结构,ESLint 的 JSON 文件允许 JavaScript 风格的注释。
  • Deprecated -使用 .eslintrc,可以使 JSON 也可以是YAML。
  • package.json - 在 package.json 里创建一个 eslintConfig属性,在那里定义你的配置

Q:网上搜的husky配置怎么不起作用
A:在husky6.0.0版本之前是可以在package.json中使用,但在6.0.0及之后使用方式变了,可以看下husky官网

参考文章