es表格如何制作(图文ESLint在中大型团队的应用实践)(1)

作者:宋鹏 美团技术团队

转发链接:https://mp.weixin.qq.com/s/jb8yozm-p-b6MBAb46SP7A

引言

代码规范是软件开发领域经久不衰的话题,几乎所有工程师在开发过程中都会遇到,并或多或少会思考过这一问题。随着前端应用的大型化和复杂化,越来越多的前端工程师和团队开始重视 JavaScript 代码规范。得益于前端开源社区的繁盛,当下已经有几种较为成熟的 JavaScript 代码规范检查工具,包括 JSLint、JSHint、ESLint、FECS 等等。本文主要介绍目前较为通用的方案——ESLint,它是一款插件化的 JavaScript 代码静态检查工具,其核心是通过对代码解析得到的 AST(Abstract Syntax Tree,抽象语法树)进行模式匹配,定位不符合约定规范的代码。

ESLint 的使用并不复杂。依照 ESLint 的文档安装相关依赖,根据个人/团队的代码风格进行配置,即可通过命令行工具或借助编辑器集成的 ESLint 功能对工程代码进行静态检查,发现和修复不符合规范的代码。如果想降低配置成本,也可以直接使用开源配置方案,例如 eslint-config-airbnb 或 eslint-config-standard。

对于独立开发者,或者执行力较强、技术场景较为单一的小型团队而言,直接使用 ESLint 及其生态提供的一些标准方案,可以用较低成本来实现 JavaScript 代码规范的落地。如果再搭配一些辅助工具(例如 husky 和 lint-staged),整个流程会更加顺畅。但对于数十人的大型前端团队来说,面向数百个前端工程,规模化的应用统一的 JavaScript 代码规范,问题就会变得较为复杂。如果直接利用现有的开源配置方案,可能会使工作事倍功半。

问题分析

规模化应用统一的 ESLint 代码规范,会涌现各类问题,根源在于大型团队和小团队(或独立开发者)的差异性:

技术层面上:

在团队层面,随着人员的增加和组织结构的复杂化:

因为存在诸多差异,我们在设计具体方案时,需要考虑和解决更多问题,以保证规范的落实。针对上述分析,我们梳理了以下需要解决的问题:

解决方案

为了能在团队内实现 JavaScript 代码规范的统一,在分析和思考团队规模化应用存在的问题后,我们设计了一套完整的技术解决方案。该方案包括多场景统一的 ESLint 规则配置、代码集成交付检查、自动化接入工具、执行状况监测分析等四个模块。通过各个模块协调配合,共同解决上文提出的问题,在降低维护成本、提升执行效率的同时,也保障了代码规范的统一。

整体方案的设计如下图所示:

es表格如何制作(图文ESLint在中大型团队的应用实践)(2)

  1. 多场景统一的 JavaScript 规范:该模块是整个方案的核心,借助 ESLint 的特性,通过分层分类的结构设计,在保证基础规则一致性的同时,实现了对不同场景、技术选型的支撑。
  2. 代码集成交付检查:该模块是方案落地执行的保障,将代码静态检查集成到持续交付工作流中。具体设计实现上,在保证交付质量的同时,也通过定制集成检查工具降低了开发者的应用执行成本。
  3. 自动化接入和升级方案:通过命令行工具提供“一键”接入/升级能力,同时集成到团队脚手架中,大大降低了工程接入和维护的成本。
  4. 执行状况监测分析:通过对工具运行和代码集成交付检查过程进行埋点、检查结果收集和分析,了解方案的应用状态和效果。
方案实现

上文中提出的问题,通过各模块的协调配合能够得到有效地解决,但具体到各个模块的实现,仍然需要进一步深入思考,以设计出更加合理的实现方案。本章将对方案的四个核心模块进行详细介绍。

通用 ESLint 配置方案

这一模块主要借助 ESLint 的基础特性,采用分层分类的结构设计,提供多场景、多技术方案的通用配置方案,并使方案具备易维护、易扩展的特性。

ESLint 特性简介

在进行 ESLint 配置方案设计前,我们先看一下 ESLint 的一些特点。

1. 插件化

下图简单地描述了 ESLint 的工作过程:

es表格如何制作(图文ESLint在中大型团队的应用实践)(3)

ESLint 的能力更像一个引擎,通过提供的基础检测能力和模式约束,推动代码检测流程的运转。原始代码经过解析器的解析,在管道中逐一经过所有规则的检查,最终检测出所有不符合规范的代码,并输出为报告。借助插件化的设计,不但可以对所有的规则进行独立的控制,还可以定制和引入新的规则。ESLint 本身并未和解析器相绑定,我们可以使用不同的解析器进行原始代码解析,例如可以使用 babel-eslint 支持更新版本、不同阶段的 ES 语法,支持 JSX 等特殊语法,甚至可以借助 @typescript-eslint/parser 支持 TypeScript 语言的检查。

2. 配置能力全面、可层叠、可共享

ESLint 提供了全面、灵活的配置能力,可以对解析器、规则、环境、全局变量等进行配置;可以快速引入另一份配置,和当前配置层叠组合为新的配置;还可以将配置好的规则集发布为 npm 包,在工程内快速应用。

3. 社区生态较为成熟

开源社区中基于 ESLint 的项目非常多,既有针对各种场景、框架的插件,也有各种 ESLint 规则配置方案,基本可以涵盖前端开发的所有场景。

规范配置方案设计

基于 ESLint 的插件化、可层叠配置特性,以及面向各种场景、框架的开源方案,我们设计了如下图所示的 ESLint 配置架构:

es表格如何制作(图文ESLint在中大型团队的应用实践)(4)

该配置架构采用了分层、分类的结构,其中:

具体的实际项目中,可以灵活的选择各层级、各类型的搭配,获得和项目匹配的 ESLint 规则集。例如,对于使用 TypeScript 语言的 React 项目,可以将基础层、框架层的 React 分支、以及 TypeScript 支撑层的 React 分支层叠到一起,最终形成适用于该项目的 ESLint 配置。如果项目不再使用 TypeScript 语言,只需要将 ts-react 这一层去掉即可。

基于上述方案最终形成了如下图所示的 ESLint 配置集:

es表格如何制作(图文ESLint在中大型团队的应用实践)(5)

考虑到维护、升级和应用成本,我们最终选择将所有配置放到一个 npm 包中,而不是每种类型分别设置。仍以使用 TypeScript 语言的 React 项目为例,只需在工程中进行如下配置:

es表格如何制作(图文ESLint在中大型团队的应用实践)(6)

这种通过分层、分类的结构设计,还有利于后期的维护:

众所周知,TypeScript 类型的项目使用 TSLint 进行代码检查,也是一种简单、便捷的方案。但在本方案中我们依旧选择了:eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin 的组合方案。主要有以下几点原因:

根据最新消息,TypeScript在 2019 路线图 中明确表明后续对 Lint 工具的支持和建设会以对 ESLint 进行适配的方式为主。

代码集成检查

基于团队对工程化基础设施的建设,将代码规范静态检查与开发工作流集成,保证代码规范的落实。

通常而言,工程接入 ESLint 后,可以在开发的同时借助编辑器集成的 ESLint 检查提示能力(例如 VSCode 的 ESLint 插件),实时发现和修改不符合规范的语法错误和风格问题。但这仍不能避免因一些主观因素或疏漏造成的规范执行不到位,所以我们考虑在开发工作流的特定节点自动执行代码静态检查,阻断不合规范代码的提交或交付。

集成静态检查的开发工作流节点有很多,我们主要参考以下两种方案:

如果将两者进行结合,可能会事半功倍,效果如下图所示:

es表格如何制作(图文ESLint在中大型团队的应用实践)(7)

常用的代码提交检查方法一般是 husky 与 lint-staged 结合,该代码 Commit 时,通过 githook 触发对 git 暂存区文件的检查。但考虑到团队现有工程数量庞大、存在大量行数较多的文件,虽然 lint-staged 策略能够降低部分成本,但仍稍显不足。为此,我们对该方法进行优化,定制了本地代码提交检查工具 precommit-eslint,其核心特点是:

使用效果如下图所示:

es表格如何制作(图文ESLint在中大型团队的应用实践)(8)

在美团,我们使用自主开发的 CI 系统,并在独立部署的 Sonar 系统上定制化实现了相应规则,基本可以满足诉求,这里就不再赘述。对于独立的团队,基于 ESLint 提供的工具,可以很容易的实现使用 Node 快速搭建一个代码检测服务或平台,大家有兴趣不妨一试。

自动化接入工具

这个模块主要通过 CLI 工具提供方案自动化接入的能力,降低工程接入和升级的成本。如果不借助自动化工具,在工程中接入上述方案还是有一定的工作量和复杂度的,大致步骤如下:

1. 安装 Eslint。

2. 根据项目类型安装对应的 ESLint 规则配置 npm 包。

3. 根据项目类型安装相关的插件、解析器等。

4. 根据项目类型配置 .eslintrc 文件。

5. 安装代码提交检查工具。

6. 配置 package.json。

7. 测试及修复问题。

在这个过程中,特别需要注意依赖的版本问题:依赖之间的版本兼容性,例如 typescript 和 @typescript-eslint/parser 之间的兼容性;依赖对规则的支持性,比如某个版本的插件中去除了对某个规则的支持,但规则配置中仍然配置了该规则,此时配置就会失效。对于 ESLint 对熟悉的开发者而言,在配置的过程中都会或多或少遇到兼容性、解析异常、规则无效等问题,反复排查和定位问题会浪费大量的精力。

因此,在设计开发自动化接入工具时,我们综合考虑了操作步骤、依赖版本、规则集和工程方案的兼容性,设计了如下的工作流程:

es表格如何制作(图文ESLint在中大型团队的应用实践)(9)

该工具流程简单,不管什么开发场景和框架选型,繁琐的接入流程都可以简化为一条命令,需要配合工程方案升级时同样如此。如下图所示,执行该命令后项目就完成了 ESLint 的接入,使用统一的规则规范编码,同时在代码提交时自动进行增量检查:

es表格如何制作(图文ESLint在中大型团队的应用实践)(10)

埋点与统计分析

统计分析的主要目的是掌握方案应用执行状况和效果,理论上应当支持工程和大盘两个视角,如下图所示:

es表格如何制作(图文ESLint在中大型团队的应用实践)(11)

执行情况分析其实并不复杂,核心是信息采集和分析。在本方案中,信息采集通过 precommit-eslint 工具实现:在 git commit 触发本地代码检查后,脚本会把检查结果(包括检查是否通过、错误或警告信息的数量级别等)上报;信息的统计分析借助日志上报分析平台实现,美团使用的是 CAT 平台(如果团队或公司没有专门的平台,可以在上文提到的代码检测服务平台中实现这部分功能)。为了便于数据的聚合分析,我们将一次代码提交检查中出现的问题数量进行了分级:

比如下图中,2019年3月第一周的代码提交检查结果统计(综合采样率 0.2),很明显,所有检查失败的提交中,错误数量在 10 个以内的占比最大,修复成本不高。

1. 提交检查异常分布(仅筛选检查未通过信息)

es表格如何制作(图文ESLint在中大型团队的应用实践)(12)

2. 提交检查警告信息分析

es表格如何制作(图文ESLint在中大型团队的应用实践)(13)

除此之外,还可以对单一工程,在更细的时间粒度上去观察提交检查的执行情况。

效果质量主要分析工程质量的变化:一方面可以通过代码检查执行通过率变化趋势、检查结果分布去看持续的生产流程中,代码质量是否有所提升;另一方面,由于代码检查采用增量模式,需要对工程代码进行整体分析,得到工程整体的不规范代码占比及变化趋势,从而从工程维度分析判断质量效果(涉及到权限相关问题,目前团队中未采用工程分析的方法)。具体的分析会在方案应用效果中一并进行介绍。

方案应用

除了上述整体方案外,为保证开发者使用更方便,我们还进行了一些配套工作:

目前,该套方案已经接入美团外卖、餐饮平台、闪购、榛果、金融等多个团队,基于埋点统计分析统计到的应用情况如下:

同时,我们持续统计上述数据的变化趋势,跟踪代码质量提升效果,以2018年12月到2019年3月的数据为例(截止2019年3月第一周,以周为时间统计尺度):

es表格如何制作(图文ESLint在中大型团队的应用实践)(14)

从图中可以看出,最近三个月检查通过率整体呈上升趋势,但 2019 年 1 月的第 2 周和第 3 周集成检查通过率有明显下降。分析项目信息发现,在 2019 年 1 月的第 2 周有一批新项目接入,代码检查规范检查出几十个错误。但整体来看,目前集成检查通过率基本稳定在 75% - 80%,从变化趋势看仍有上升空间。

方案实施之后,我们做了一个用户调研,发现整体方案的运营正在发挥着正向的作用。一方面,在一定程度上提升了多人协作的效率,无论是共同维护一个工程还是在多个工程间切换,避免了代码风格不一致带来的可读性成本和格式化风险;另一方面,会帮助大家发现和避免一些简单的语法错误。

规划和思考

该方案已经稳定应用,除了现有功能,我们还在思考是否可以更进一步的优化,提供更丰富的能力。由此规划了一些仍未落地的方向:

  1. 扩展支持 HTML 和 CSS 的代码风格检查:虽然近几年前端框架、组件库的建设一定程度上减少了业务开发中(尤其是中后台业务)对 HTML 和 CSS 的需求,但是规范 HTML 和 CSS 的代码风格仍是必要的。基于此,可以用同样的思路将 HTML 和 CSS 的代码静态检查方案集成到当前的方案中,不再局限于 JavaScript(或 TypeScript)。
  2. 进一步的封装:目前整体方案会将所有依赖和配置暴露在工程内,如果将其完全封装在一个工具内会更便于应用,但难点在于兼顾灵活性、对编辑器的支持等问题。
  3. 增加工程维度的代码质量趋势分析:目前代码检查策略是增量检查,可以对接入的工程定期全量检查,基于时间线分析工程的代码质量变化趋势。
  4. 进一步深入分析检查结果和统计数据,发现一些潜在问题,为推动开发质量提升提供辅助,如:
  5. 统计开发者在工程中关闭或调整的规则,分析占比较高的规则被关闭的原因,进而调整规则或推动规则的执行。
  6. 统计分布检查出错误的规则分布,梳理出最常出问题的代码规则,发布对应的最佳实践或手册。

以上是美团外卖团队在 ESLint 方案规模化应用过程中的一些实践,欢迎大家提出建议,一起沟通交流。

作者简介

宋鹏,美团外卖事业部终端研发工程师。

About 团队

美团外卖事业部终端团队,负责的多个终端和平台直接连接亿万用户、数百万商家和几万名运营与销售,目标是在保障业务高稳定、高可用的同时,持续提升用户体验和研发效率。

在用户方向上,构建了全链路的高可用体系,客户端、Web前端和小程序等多终端的可用性在99%左右;跨多端高复用的局部动态化框架在首页、广告、营销等核心路径的落地,提升了30%的研发效率;

在商家方向上,从提高进程优先级、VoIP Push拉活、doze等方面进行保活定制,并提供了Shark、短链和Push等多条触达通道,订单到达率提升至98%以上;

在运营方向上,通过标准化研发流程、建设组件库和Node服务以及前端应用的管理与页面配置等提升10%的研发效率。

推荐JavaScript经典实例学习资料文章

《Deno是代码的浏览器,你认同吗?》

《前端存储除了 localStorage 还有啥?》

《Javascript 多线程编程​的前世今生》

《微前端方案 qiankun(实践及总结)》

《「图文」V8 垃圾回收原来这么简单?》

《Webpack 5模块联邦引发微前端的革命?》

《基于 Web 端的人脸识别身份验证「实践」》

《「前端进阶」高性能渲染十万条数据(时间分片)》

《「前端进阶」高性能渲染十万条数据(虚拟列表)》

《图解 Promise 实现原理(一):基础实现》

《图解 Promise 实现原理(二):Promise 链式调用》

《图解 Promise 实现原理(三):Promise 原型方法实现》

《图解 Promise 实现原理(四):Promise 静态方法实现》

《实践教你从零构建前端 Lint 工作流「干货」》

《高性能多级多选级联组件开发「JS篇」》

《深入浅出讲解Node.js CLI 工具最佳实战》

《延迟加载图像以提高Web网站性能的五种方法「实践」》

《比较 JavaScript 对象的四种方式「实践」》

《使用Service Worker让你的 Web 应用如虎添翼(上)「干货」》

《使用Service Worker让你的 Web 应用如虎添翼(中)「干货」》

《使用Service Worker让你的 Web 应用如虎添翼(下)「干货」》

《前端如何一次性处理10万条数据「进阶篇」》

《推荐三款正则可视化工具「JS篇」》

《如何让用户选择是否离开当前页面?「JS篇」》

《JavaScript开发人员更喜欢Deno的五大原因》

《仅用18行JavaScript实现一个倒数计时器》

《图文细说JavaScript 的运行机制》

《一个轻量级 JavaScript 全文搜索库,轻松实现站内离线搜索》

《推荐Web程序员常用的15个源代码编辑器》

《10个实用的JS技巧「值得收藏」》

《细品269个JavaScript小函数,让你少加班熬夜(一)「值得收藏」》

《细品269个JavaScript小函数,让你少加班熬夜(二)「值得收藏」》

《细品269个JavaScript小函数,让你少加班熬夜(三)「值得收藏」》

《细品269个JavaScript小函数,让你少加班熬夜(四)「值得收藏」》

《细品269个JavaScript小函数,让你少加班熬夜(五)「值得收藏」》

《细品269个JavaScript小函数,让你少加班熬夜(六)「值得收藏」》

《深入JavaScript教你内存泄漏如何防范》

《手把手教你7个有趣的JavaScript 项目-上「附源码」》

《手把手教你7个有趣的JavaScript 项目-下「附源码」》

《JavaScript 使用 mediaDevices API 访问摄像头自拍》

《手把手教你前端代码如何做错误上报「JS篇」》

《一文让你彻底搞懂移动前端和Web 前端区别在哪里》

《63个JavaScript 正则大礼包「值得收藏」》

《提高你的 JavaScript 技能10 个问答题》

《JavaScript图表库的5个首选》

《一文彻底搞懂JavaScript 中Object.freeze与Object.seal的用法》

《可视化的 JS:动态图演示 - 事件循环 Event Loop的过程》

《教你如何用动态规划和贪心算法实现前端瀑布流布局「实践」》

《可视化的 js:动态图演示 Promises & Async/Await 的过程》

《原生JS封装拖动验证滑块你会吗?「实践」》

《如何实现高性能的在线 PDF 预览》

《细说使用字体库加密数据-仿58同城》

《Node.js要完了吗?》

《Pug 3.0.0正式发布,不再支持 Node.js 6/8》

《纯JS手写轮播图(代码逻辑清晰,通俗易懂)》

《JavaScript 20 年 中文版之创立标准》

《值得收藏的前端常用60余种工具方法「JS篇」》

《箭头函数和常规函数之间的 5 个区别》

《通过发布/订阅的设计模式搞懂 Node.js 核心模块 Events》

《「前端篇」不再为正则烦恼》

《「速围」Node.js V14.3.0 发布支持顶级 Await 和 REPL 增强功能》

《深入细品浏览器原理「流程图」》

《JavaScript 已进入第三个时代,未来将何去何从?》

《前端上传前预览文件 image、text、json、video、audio「实践」》

《深入细品 EventLoop 和浏览器渲染、帧动画、空闲回调的关系》

《推荐13个有用的JavaScript数组技巧「值得收藏」》

《前端必备基础知识:window.location 详解》

《不要再依赖CommonJS了》

《犀牛书作者:最该忘记的JavaScript特性》

《36个工作中常用的JavaScript函数片段「值得收藏」》

《Node H5 实现大文件分片上传、断点续传》

《一文了解文件上传全过程(1.8w字深度解析)「前端进阶必备」》

《【实践总结】关于小程序挣脱枷锁实现批量上传》

《手把手教你前端的各种文件上传攻略和大文件断点续传》

《字节跳动面试官:请你实现一个大文件上传和断点续传》

《谈谈前端关于文件上传下载那些事【实践】》

《手把手教你如何编写一个前端图片压缩、方向纠正、预览、上传插件》

《最全的 JavaScript 模块化方案和工具》

《「前端进阶」JS中的内存管理》

《JavaScript正则深入以及10个非常有意思的正则实战》

《前端面试者经常忽视的一道JavaScript 面试题》

《一行JS代码实现一个简单的模板字符串替换「实践」》

《JS代码是如何被压缩的「前端高级进阶」》

《前端开发规范:命名规范、html规范、css规范、js规范》

《【规范篇】前端团队代码规范最佳实践》

《100个原生JavaScript代码片段知识点详细汇总【实践】》

《关于前端174道 JavaScript知识点汇总(一)》

《关于前端174道 JavaScript知识点汇总(二)》

《关于前端174道 JavaScript知识点汇总(三)》

《几个非常有意思的javascript知识点总结【实践】》

《都2020年了,你还不会JavaScript 装饰器?》

《JavaScript实现图片合成下载》

《70个JavaScript知识点详细总结(上)【实践】》

《70个JavaScript知识点详细总结(下)【实践】》

《开源了一个 JavaScript 版敏感词过滤库》

《送你 43 道 JavaScript 面试题》

《3个很棒的小众JavaScript库,你值得拥有》

《手把手教你深入巩固JavaScript知识体系【思维导图】》

《推荐7个很棒的JavaScript产品步骤引导库》

《Echa哥教你彻底弄懂 JavaScript 执行机制》

《一个合格的中级前端工程师需要掌握的 28 个 JavaScript 技巧》

《深入解析高频项目中运用到的知识点汇总【JS篇】》

《JavaScript 工具函数大全【新】》

《从JavaScript中看设计模式(总结)》

《身份证号码的正则表达式及验证详解(JavaScript,Regex)》

《浏览器中实现JavaScript计时器的4种创新方式》

《Three.js 动效方案》

《手把手教你常用的59个JS类方法》

《127个常用的JS代码片段,每段代码花30秒就能看懂-【上】》

《深入浅出讲解 js 深拷贝 vs 浅拷贝》

《手把手教你JS开发H5游戏【消灭星星】》

《深入浅出讲解JS中this/apply/call/bind巧妙用法【实践】》

《手把手教你全方位解读JS中this真正含义【实践】》

《书到用时方恨少,一大波JS开发工具函数来了》

《干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)》

《手把手教你JS 异步编程六种方案【实践】》

《让你减少加班的15条高效JS技巧知识点汇总【实践】》

《手把手教你JS开发H5游戏【黄金矿工】》

《手把手教你JS实现监控浏览器上下左右滚动》

《JS 经典实例知识点整理汇总【实践】》

《2.6万字JS干货分享,带你领略前端魅力【基础篇】》

《2.6万字JS干货分享,带你领略前端魅力【实践篇】》

《简单几步让你的 JS 写得更漂亮》

《恭喜你获得治疗JS this的详细药方》

《谈谈前端关于文件上传下载那些事【实践】》

《面试中教你绕过关于 JavaScript 作用域的 5 个坑》

《Jquery插件(常用的插件库)》

《【JS】如何防止重复发送ajax请求》

《JavaScript Canvas实现自定义画板》

《Continuation 在 JS 中的应用「前端篇」》

作者:宋鹏 美团技术团队

转发链接:https://mp.weixin.qq.com/s/jb8yozm-p-b6MBAb46SP7A

,