善用工具统一你的代码风格

1,065 阅读9分钟

在团队开发中,我们总是碰到这样或者那样的问题,加分号还是不加分号?tab还是空格?换行还是不换行?你是否还在为代码风格与同事争论不休?关于代码风格,我们很难区分谁对谁错,不同的人有不同偏好,唯有强制要求才能规避争论。

所以,团队关于代码风格必须遵循两个基本原则:

  • 少数服从多数;
  • 用工具统一风格。

以下几个工具可以帮助你在开发中来统一我们的前端代码风格。

Eslint

Eslint大家对这种工具可能比较熟悉,它是一个可组装的JavaScript和JSX检查工具,发现并修复JavaScript代码中的问题,用来进行代码的校验。

简单的使用入门

  1. 安装eslint
    npm install -g eslint
  2. 准备一个js文件来测试一下
function merge () {
  var ret = {};
  for (var i in arguments) {
    var m = arguments[i];
    for (var j in m) ret[j] = m[j];
  }
  return ret;
}

console.log(merge({a: 123}, {b: 456}));
  1. 新建一个eslint配置文件.eslintrc.js,我们以eslint:recommended为基础配置
module.exports = {
  extends: 'eslint:recommended',
};
  1. 执行eslint merge.js
eslint merge.js
  10:1  error  Unexpected console statement  no-console
  10:1  error  'console' is not defined      no-undef

✖ 2 problem (2 error, 0 warnings)

根据提示信息,我们可以知道: 第一条报错,不能使用console; 针对第 1 条提示,我们可以禁用no-console规则。将配置文件.eslintrc.js改为这样:

module.exports = {
  extends: 'eslint:recommended',
  rules: {
    'no-console': 'off',
  },
};

第二条报错,console变量未定义,不能使用未定义的变量。 这是因为 JavaScript 有很多种运行环境,比如常见的有浏览器和 Node.js,另外还有很多软件系统使用 JavaScript 作为其脚本引擎,比如 PostgreSQL 就支持使用 JavaScript 来编写存储引擎,而这些运行环境可能并不存在console这个对象。另外在浏览器环境下会有window对象,而 Node.js 下没有;在 Node.js 下会有process对象,而浏览器环境下没有。

所以在配置文件中我们还需要指定程序的目标环境:

module.exports = {
  extends: 'eslint:recommended',
  env: {
    node: true,
  },
  rules: {
    'no-console': 'off',
  },
};

再重新执行检查时,已经没有任何提示输出了,说明merge.js已经完全通过了检查。

  1. 使用eslint --fix 自动修复命令

eslint提供了自动修复命令,可以对一些常见的错误进行自动修复。我们可以利用这个特性来自动格式化项目代码,这样就可以保证代码书写风格的统一。

将merge.js中的var ret = {};这一行前面多加一个空格,再执行 ESLint 检查:

eslint merge.js
  2:4  error  Expected indentation of 2 space characters but found 3  indent

✖ 1 problem (1 error, 0 warnings)

这时候提示的是缩进只能为 2 个空格,而文件的第 2 行却发现了 3 个空格。 之后再执行

eslint merge.js --fix

可以发现merge.js文件被修改了,新添加的空格被去除了。

以上过程通过展示了在一个简单的js文件中引入eslint,进行文件格式校验的过程,了解了eslint在项目中是如何被引入以及如何发挥作用的。

很多人刚开始接触 ESLint 时觉得太难,是因为过太过于迷信权威。刚接触eslint就直接引入一些业界已经集成好的高度定制化的配置eslint规范。比如 Airbnb 公司的 JavaScript 风格,在 GitHub 上受到了很大的好评,其实我自己也非常认可这样的编码风格。但每个团队都会根据自己的的实际情况来定制不同的东西,我们并不能随便照搬过来。 直接使用eslint-config-airbnb这种某个公司高度定制化的配置,直接用来检查整个项目好几十个JS文件,而不是eslint:recommended这样保守的。可想而知那是怎样的画面。

当我们学会了走路之后,可以试着跑一跑了,这时可以尝试引入上文提到的各大公司提供的高度配置的规范,这样当项目文件很大很多的时候可以省一些事。当然每个项目每个团队都有适合自己的开发规范,如果我们觉得 eslint-config-airbnb 规则配置中个别规则并不符合当前项目的要求,可以直接在 .eslintrc.js 配置 rules 属性,优先级高于共享规则 airbnb。

顺便说一句,如果觉得官方提供的默认规则不好用,可以自定义规则配置文件,然后发布成 Npm 包。

先学会简单地配置规则,如果要更深入地定制自己的规则,建议阅读
规则说明文档
ESLint 规则详解(一)
ESLint 规则详解(二)

文件配置

ESLint 支持几种格式的配置文件

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

如果同一个目录下有多个配置文件,ESLint 只会使用一个。优先级顺序如下

1 .eslintrc.js
2 .eslintrc.yaml
3 .eslintrc.yml
4 .eslintrc.json
5 .eslintrc
6  package.json

Prettier

Prettier翻译过来是“更漂亮的”,来看看官网对他的定义:

  • 它是一款代码格式化工具,
  • 支持多种语言
  • 与大多数编辑器集成
  • 不需要太多配置

使用prettier配置我们的项目,按下保存键,代码即被格式化,使得我们可以节省更多的时间和精力,不需要在代码评审中讨论风格。

很多人通常会将eslint与prettier混为一谈,首先从定义上看eslint是一款代码校验工具,而Prettier区别于eslint的,prettier一款代码格式化工具。 prettier不仅能格式化javascript,还能支持jsx和css。总的来说它支持以下文件格式:

  • JavaScript, including ES2017
  • JSX
  • Angular
  • Vue
  • Flow
  • TypeScript
  • CSS, Less, and SCSS
  • HTML
  • JSON
  • GraphQL
  • Markdown, including GFM and MDX
  • YAML

最重要的区别在于,prettier提供很少的配置项,它本身就是为了让用户少思考这些风格,把代码风格全部交给工具。它更像是提供了一种方案,用以保持所有输出的代码符合一致性的原则。

如何对Prettier进行配置

一共有三种方式支持对Prettier进行配置:

  1. 根目录创建.prettierrc文件,能够写入YML、JSON的配置格式,并且支持.yaml/.yml/.json/.js后缀;
  2. 根目录创建.prettier.config.js文件,并对外export一个对象;
  3. 在package.json中新建prettier属性。

下面我们使用prettierrc.js的方式对prettier进行配置,同时讲解下各个配置的作用。

module.exports = {
  "printWidth": 80, //一行的字符数,如果超过会进行换行,默认为80
  "tabWidth": 2, //一个tab代表几个空格数,默认为80
  "useTabs": false, //是否使用tab进行缩进,默认为false,表示用空格进行缩减
  "singleQuote": false, //字符串是否使用单引号,默认为false,使用双引号
  "semi": true, //行位是否使用分号,默认为true
  "trailingComma": "none", //是否使用尾逗号,有三个可选值"<none|es5|all>"
  "bracketSpacing": true, //对象大括号直接是否有空格,默认为true,效果:{ foo: bar }
  "parser": "babylon" //代码的解析引擎,默认为babylon,与babel相同。
}

配置大概列出了这些,还有一些其他配置可以在官方文档进行查阅。

注意一点,parser的配置项官网列出了如下可选项:

  • babylon
  • flow
  • typescript Since v1.4.0
  • postcss Since v1.4.0
  • json Since v1.5.0
  • graphql Since v1.5.0
  • markdown Since v1.8.0 但是如果你使用了vue的单文件组件形式,记得将parser配置为vue,目前官方文档没有列出来。当然如果你自己写过AST的解析器,也可以用你自己的写的parser: require("./my-parser")。

ESLint 与 Prettier配合使用

通常,ESLint 与 Prettier配合使用。 首先肯定是需要安装prettier,并且你的项目中已经使用了ESLint,有eslintrc.js配置文件。 npm i -D prettier

配合ESLint检测代码风格 安装插件 npm i -D eslint-plugin-prettier

eslint-plugin-prettier插件会调用prettier对你的代码风格进行检查,其原理是先使用prettier对你的代码进行格式化,然后与格式化之前的代码进行对比,如果过出现了不一致,这个地方就会被prettier进行标记。

接下来,我们需要在eslint配置文件的rules中添加,"prettier/prettier": "error",表示被prettier标记的地方抛出错误信息。

//.eslintrc.js
{
  "plugins": ["prettier"],
  "rules": {
    "prettier/prettier": "error"
  }
}

借助ESLint的autofix功能,在保存代码的时候,自动将抛出error的地方进行fix。因为我们项目是在webpack中引入eslint-loader来启动eslint的,所以我们只要稍微修改webpack的配置,就能在启动webpack-dev-server的时候,每次保存代码同时自动对代码进行格式化。

const path = require('path')
module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: 'pre',
        include: [path.join(__dirname, 'src')],
        options: {
          fix: true
        }
      }
    ]
}

EditorConfig

一些细心的童鞋可能回发现,项目里面经常会有个.editorconfig的文件,那么,它究竟是干嘛的呢?事实上,它也能帮助我们在开发中保持一定的规范。

先设想一个场景,一个大型项目,可能有很多位同事一起工作,而由于习惯的不同,导致他们用的编辑器五花八门,有vscode,有webstorm,有sublime,等等,它们默认的格式化设置是不同的,有的是2格缩进,有的则是4格。规则的不同,导致代码风格的差异,这样就会给后期的运维工作带来不可预料的风险。so bad!

所以,EditorConfig就是来做这件事的工具,它的作用就是

帮助跨不同的编辑器和ide为多个开发人员维护一致的编码风格。

知道了它是干什么,那么它是怎么用的呢?

配置EditorConfig

  1. 安装插件

每个编辑器都有相应的插件,这里以vscode为例,我们需要安装EditorConfig:

  1. 配置.editorconfig文件

在根目录下新建.editorconfig文件

# 是否是顶级配置文件,设置为true的时候才会停止搜索.editorconfig文件
root = true

[*]
# 文件编码格式,一般为utf-8
charset = utf-8
# 缩进类型
indent_style = space
# 缩进数量
indent_size = 2
# 换行符类型格式,一般用lf
end_of_line = lf
# 末尾行后加多一行空行
insert_final_newline = true
# 删除行尾的空格
trim_trailing_whitespace = true

做完以上两步后,vscode会自动的按照以上规范进行新建文件。