硬广时间
内推咨询请加微信:389399428
字节跳动幸福里团队【校招/社招/实习】同步进行中,【前端/后端/客户端/测试/数仓/算法/产品/运营】均海量HC,等你一起来搞事情。
幸福里是字节跳动旗下集内容、社区、工具于一体的房产信息、服务、交易平台。产品基于个性化推荐引擎向用户推荐优质的房产内容和全面、真实的房源信息,致力于为用户提供全面、专业、可靠的购房决策支持。幸福里始于2018年8月,是国内发展最快的,集内容、社区、工具于一体的房产信息与服务平台,业务覆盖一二线共23城,现累积注册用户千万,目前进入高速增长期。
背景
最近开发中遇到这样几个实际场景:
- 团队有详细的开发规范,也进行过宣贯,但组员提交的CodeReview代码依然充斥着大量不符合规范的代码,可能需要反复修改,耽误彼此的时间。
- 项目中存在部分不符合规范的旧代码,新同学可能会直接对照老代码来开发。
- 团队沉淀的最佳实践无法保障,例如代码分层或一些应该避免的写法,但总有人能写出不符合最佳实践要求的代码,出现业务逻辑或是请求代码混到UI层的现象。
- 团队抽取出越来越多的公共物料,但新人很可能并不知道,在需要时仍然使用第三方库的组件,从而导致一些可能已经出现过N次的问题。
问题
- 项目中虽然引入了
ESLint
和Prettier
,但代码质量依然无法保障,比如一些数据结构重组的场景,熟练使用ES6
或Lodash
的开发者都能写出简洁易读的代码,但初学者可能会在很多场景都用嵌套在一起的for
循环来完成,这并不是语法错误,但这样的代码会让代码变得臃肿且耦合,维护起来会更困难,而且整个工程的混乱程度增加了。 - 开发规范和最佳实践条目都很多,开发者很可能因为自己疏忽或是加入时间晚而无法有效执行。
- 代码检视时被大量的违反开发规范的低级问题干扰,虽然提了很多问题,但对于提交人和检视人来说时间的投入产出比都太低了。
解决思路
- 利用
ESLint
提供的自定义插件能力,将团队公认的最佳实践和编码规范沉淀为规则,这样在开发时就能够直接发现并修改问题,降低Code Review低级问题或是重复问题的干扰,关注核心代码,提高团队代码产出的一致性。 - 提供可参考的
ESLint-Plugin
及Rule
模板代码(最好集成到自己的脚手架中,避开了解yeoman脚手架及模板的心智负担) - Code Review过程中出现问题时,由提交人来编写自定义规则,更新插件,并解决代码仓中类似的问题,以此来均摊偿还技术债的问题,也有利于培养基建和技术沉淀意识。
动手
效果展示(示例中希望对一些组件强制开发者从团队沉淀的公共组件中引入):
step-by-step的教程可以参考这篇文章《手摸手教你定制ESLint Plugin rule以及ESLint的工作原理》,非常详细了,本文只做一些关键点的补充。API可参考:ESLint自定义规则常用API
基本概念
ESLint
扩展开发中会出现Rule
,Plugin
,Config
这几个概念,可以粗略地理解为Config
可以在不同的项目中通过继承来复用,Config
中可以包含多个Plugin
,Plugin
可以包含多个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
格式,如下所示: