如何为团队潜规则明码标价

靠谱的前端团队通常都会引入本身的代码风格规范,但真实项目中的问题经常不是统一了空格数量和是否加分号就能解决的,而是有不少看不见的暗坑。咱们是否有代码风格之上,对代码质量的更高级把控呢?ESLint 插件或许可以为你打开新世界的大门。
在前端发展突飞猛进的这个时代,咱们实际上正在面临日益严峻的前端代码腐化问题。譬如,但凡接手维护过前端项目的同窗,应该多少都遇到过这样的场景:
约定好的模块路径、命名方式等规范没有被遵照,项目展开像是人心涣散。
要作一样的事情,有的地方用了第三方库、有的地方用了内部库、有的地方本身从新裸写。
老语法和新语法混编共存。好比光导入一个库的方式,就有 ESM / CommonJS / UMD 等不一而足。
……
按照破窗理论,若是环境中的不良现象若是被听任存在,会诱令人们仿效,甚至变本加厉。但代码中的熵增现象并不意味着程序员们都是犯罪分子,不少时候上面这些问题,实际上源自于项目中对新人来讲陌生的隐式潜规则:
若是新同窗不知道咱们已经习惯了导入php

lodash/xxx

来减小包体积,那么他可能会全量导入 lodash。
若是新同窗不知道咱们已经封装了一个处理请求、序列化之类常见业务需求的基础库,那么他可能安装一个第三方库,甚至从新发明轮子。
若是新同窗不知道咱们的业务组件约定了需从某个公共基类继承,那么他就有可能另起炉灶搞一个他最容易理解的新版本。
……
这个层面上的一致性问题已经超出了是用空格仍是 tab,或者行尾加不加分号的范畴,市面上已有的代码风格检查工具是「管不到这么宽」的。固然了,这个层面的问题也确实能够用 Code Review 来解决,但人工评审未必在每一个标榜敏捷和 Moving Fast 的团队中都推得开。那么,咱们是否有更高效率的手段,来将这些隐式的「潜规则」沉淀下来呢?这里咱们尝试给出一种答案:编写本身的业务 Lint 插件。
在 2018 年,ESLint 基本已是靠谱前端脚手架中的必备依赖了。但多数状况下咱们都是使用一个现成的代码风格规范。但 ESLint 实际上并不只仅能够用于检测空格、换行等风格问题,在与业务开发规范相结合后,就会发现它还具备很是大的潜力。而本身从头编写一个 ESLint 插件的过程其实也并不复杂,让咱们来看看如何实践吧:
环境配置 和普通的前端项目同样,ESLint 插件也提供了一套开箱即用的脚手架。只须要安装全局依赖:前端

npm install -g yo generator-eslint

就能够建立咱们本身的插件了:node

mkdir eslint-plugin-demo
cd eslint-plugin-demo

yo eslint:plugin

? What is your name? ...
? What is the plugin ID? demo
? Type a short description of this plugin: ...
? Does this plugin contain custom ESLint rules? Yes
? Does this plugin contain one or more processors? No

npm install

初始化一个插件,就和react

create-react-app

同样简单对吧?
建立规则 如今是时候来建立咱们的第一条 Lint 规则了!做为例子,空格排版强迫症患者的笔者不喜欢在代码里看到这样的注释:程序员

// 获取abc数据2次

Web 上中文排版的惯例实际上是这样的:npm

// 获取 abc 数据 2 次

可是并非谁都和笔者同样甚至在微信聊天里都坚持手动插入空格,而在 commit 记录里强行改动别人的注释,也有种替人挖鼻孔的不适感。那么咱们把这个约定升级为 ESLint 的规则呢?咱们须要理解一点 ESLint 的工做原理。
ESLint 使用 Espree 这个 JavaScript parser 来解析你的项目源码。Parser 会将源代码字符串解析为一棵抽象语法树(AST),对于树中的每个节点,ESLint 都会寻找是否存在与之匹配的规则,若匹配则计算出该规则是否知足。而 AST 是什么样的呢?譬如一行json

// hello world

的 JS 代码文件,AST 格式形如:微信

{
  "type": "Program",
  "start": 14,
  "end": 14,
  "body": [],
  "innerComments": [
    {
      "type": "Line",
      "value": " hello world",
      "start": 0,
      "end": 14
      "range": [
        0,
        12
      ]
    }
  ],
  "//": "......"
}

基于这个数据结构,若是但愿对全部的变量声明语句添加规则,那么咱们的插件规则就形如:数据结构

module.exports = function (context) {
  return {
    'VariableDeclaration' (node) {
      // 在这里搞事情
      // ...
    }
  }
}

这个app

VariableDeclaration

是哪来的呢?这就是时候展现你做为资深前端,对于 ES Spec 的熟悉了!实际上,JavaScript 中的每一种语句,在规范中都定义了相应的类型,咱们按照类型名称便可编写对其进行校验的规则了。若是咱们但愿对注释作校验,那么将上面示例中的名称换成

Comment

便可。是否是很符合直觉呢?
上面的这种方式能够理解为很是经典的 Visitor 模式,它在方便声明式地编写规则的同时,也有相邻节点之间彻底透明,不方便一些复杂操做的问题。所以你也可使用一些更过程式的 API 来辅助规则的编写:

module.exports = {
  create: function (context) {
    const sourceCode = context.getSourceCode()

    return {
      // Program 至关于 AST 根节点
      Program () {
        const comments = sourceCode.getAllComments()
        comments.forEach(node => {
          if (/* 知足校验规则 */) {
            context.report(node, 'Something WRONG!')
          }
        })
      }
    }
  }
}

对于咱们如今检测空格的需求,一个现成的依赖是

pangu.js

。咱们在上面的注释处调用 pangu 的格式化 API 就可以实现校验了。但在实际编写本身的插件时,具体的业务规则每每不是难点,难点实际上在于对 JS 语法树结构的熟悉。这里特别推荐 astexplorer 这个工具,它可以直观地让你了解源码对应的 AST 结构,方便校验规则的编写。
到这里,咱们应该已经对编写规则有了一些直观的认识了。回到开头提出的问题,咱们就能够用 ESLint 对症下药了:
对于特定模块文件,咱们可以编写 ESLint 规则,要求其变量命名知足特殊的约定。
对于通过团队基础库封装后的原生 API,在 ESLint 规则中禁止它的出现,从而避免从新发明

fetch

一类的问题。
对于不符合最佳实践的语法使用,咱们能够及时告警。好比,发现 require 语句正在为

_

lodash

赋值时,这多半会带来包体积的剧增,能够编写规则来避免。
……
测试驱动 咱们已经知道了怎么编写灵活的校验规则,但这些代码多半在平常的业务开发中不会遇到,该怎么保证它靠谱呢?这就须要咱们引入测试驱动的开发模式了。
在插件的 package.json 里,会有这样的脚本:

"scripts": {
  "test": "mocha ./tests/**/*.js"
}

做为示例,咱们在

/tests

目录下添加

spacing-test.js

测试用例,填入这样的内容:

const rule = require('../lib/rules/spacing')
const RuleTester = require('eslint').RuleTester

const ruleTester = new RuleTester()
ruleTester.run('comment', rule, {
  valid: [
    '// 白色相簿 2'
  ],
  invalid: [
    {
      code: '// 白色相簿2',
      errors: [{
        message: 'Something WRONG!',
        type: 'Line'
      }]
    }
  ]
})

这就是经过测试驱动 ESLint 插件开发的基础方式了。对于规则所但愿覆盖到的代码片断,能够经过测试用例的形式提供,这会在很大程度上便利后来者的理解和维护。编写完测试用例后,执行用例的方式也很是简单:

npm test

测试用例所有经过,就表明着插件大功告成了!剩下的就是将它发布到 NPM 上,按照 ESLint 插件的配置方式,在你的项目中引入就行啦。在第一步脚手架为你生成的 README 中,这个过程已经有了很详尽的文档,在此就不赘述了。
总结 不少前端同窗为了钻研技术深度,会去阅读 ES Spec 的规范文档。但惋惜的是这个层面的内容不少时候对于通常的业务开发用处不是很大。但在你具有了开发(而不是使用)ESLint 插件的能力后,配合上你对 JS 自己的熟悉,就会有种解锁了「控制代码的代码」技能的船新感受:用代码去约束和优化代码自己,这就是 Meta Programming 的威力了吧。
上文中编写的注释插件也已经发布到 GitHub,欢迎参考或供强迫症同窗试用哦。最后忽然想没来由地提一句…
愿意为你在微信里加空格的妹子,必定是真爱了。
转载于猿2048:➮《如何为团队潜规则明码标价》

相关文章
相关标签/搜索