使用ESLint自定义插件保障团队最佳实践有效落地

3,417 阅读5分钟

硬广时间

内推咨询请加微信:389399428

字节跳动幸福里团队【校招/社招/实习】同步进行中,【前端/后端/客户端/测试/数仓/算法/产品/运营】均海量HC,等你一起来搞事情。

幸福里是字节跳动旗下集内容、社区、工具于一体的房产信息、服务、交易平台。产品基于个性化推荐引擎向用户推荐优质的房产内容和全面、真实的房源信息,致力于为用户提供全面、专业、可靠的购房决策支持。幸福里始于2018年8月,是国内发展最快的,集内容、社区、工具于一体的房产信息与服务平台,业务覆盖一二线共23城,现累积注册用户千万,目前进入高速增长期。

背景

最近开发中遇到这样几个实际场景:

  • 团队有详细的开发规范,也进行过宣贯,但组员提交的CodeReview代码依然充斥着大量不符合规范的代码,可能需要反复修改,耽误彼此的时间。
  • 项目中存在部分不符合规范的旧代码,新同学可能会直接对照老代码来开发。
  • 团队沉淀的最佳实践无法保障,例如代码分层或一些应该避免的写法,但总有人能写出不符合最佳实践要求的代码,出现业务逻辑或是请求代码混到UI层的现象。
  • 团队抽取出越来越多的公共物料,但新人很可能并不知道,在需要时仍然使用第三方库的组件,从而导致一些可能已经出现过N次的问题。

问题

  • 项目中虽然引入了ESLintPrettier,但代码质量依然无法保障,比如一些数据结构重组的场景,熟练使用ES6Lodash的开发者都能写出简洁易读的代码,但初学者可能会在很多场景都用嵌套在一起的for循环来完成,这并不是语法错误,但这样的代码会让代码变得臃肿且耦合,维护起来会更困难,而且整个工程的混乱程度增加了。
  • 开发规范和最佳实践条目都很多,开发者很可能因为自己疏忽或是加入时间晚而无法有效执行。
  • 代码检视时被大量的违反开发规范的低级问题干扰,虽然提了很多问题,但对于提交人和检视人来说时间的投入产出比都太低了。

解决思路

  • 利用ESLint提供的自定义插件能力,将团队公认的最佳实践和编码规范沉淀为规则,这样在开发时就能够直接发现并修改问题,降低Code Review低级问题或是重复问题的干扰,关注核心代码,提高团队代码产出的一致性。
  • 提供可参考的ESLint-PluginRule模板代码(最好集成到自己的脚手架中,避开了解yeoman脚手架及模板的心智负担)
  • Code Review过程中出现问题时,由提交人来编写自定义规则,更新插件,并解决代码仓中类似的问题,以此来均摊偿还技术债的问题,也有利于培养基建和技术沉淀意识。

动手

效果展示(示例中希望对一些组件强制开发者从团队沉淀的公共组件中引入):

step-by-step的教程可以参考这篇文章《手摸手教你定制ESLint Plugin rule以及ESLint的工作原理》,非常详细了,本文只做一些关键点的补充。API可参考:ESLint自定义规则常用API

基本概念

ESLint扩展开发中会出现Rule,Plugin,Config这几个概念,可以粗略地理解为Config可以在不同的项目中通过继承来复用,Config中可以包含多个PluginPlugin可以包含多个Rule

为什么不用自定义Rule

单独的Rule使用方式很诡异,需要在命令行中传参数来指定一个自定义Rule的目录路径,个人感觉复用起来很不方便,而Plugin的扩展方式直接在配置文件中就可以完成。

单元测试

使用yo脚手架生成的模板是自带单元测试模板的,但初始化RunTester类的时候需要传入一些配置参数,否则可能识别不了ES6+的语法(比如import)。单元测试中需要提供至少一组正确的和错误的示例代码,然后执行npm install安装依赖,通过npm run test就可以自动跑测试了。(基于mocha的自动化测试包已经集成进去了)

var ruleTester = new RuleTester({
  parserOptions: { ecmaVersion: 2015, sourceType: 'module' }
});

自定义配置

使用yo脚手架生成的模板只导出了rules自定义规则,事实上插件也支持直接导出一个配置:

module.exports.configs = {
  fConfig: {
    plugins: ['@avengers/ayaya'],
    rules: {
      '@avengers/ayaya/import-from-shared': [2]
    }
  }
};

// 使用时在eslintrc中增加插件配置

{
   extends:['plugin:@avengers/ayaya/fConfig'],
}

npm私有包的引用方式

开发完的插件可能托管在npm某个私有域名下(例如@avengers),下载插件时需要用如下命令:

npm install @avengers/eslint-plugin-ayaya,但声明继承或引用插件时不需要写通用前缀,使用上一节示例的语法即可,否则就容易看到 Definition for rule '@avengers/eslint-plugin-ayaya/class-name-cap' was not found 类似的报错。

规则支持用户自定义参数

配置时由用户传入配置:

 rules:{
        "@avengers/ayaya/import-from-shared":[2, {
            SomeProps:'dashnowords'
        }]
    }

在规则代码的create方法中,context.options[0]对应的就是用户传入的对象,也支持多参数(但通常没必要),除此之外还需要配置schema参数来约束参数的类型,这里使用的是标准的json-schema格式,如下所示:


横版二维码.png