前端工具考 - ESLint 篇
C 语言诞生之初,程序员编写的代码风格各异,在移植时会出现一些因为不严谨的代码段导致无法被编译器执行的问题。于是在 1979 年,一款叫 lint[1] 的程序被开发出来,能够通过扫描源代码检测潜在的错误。
此后 lint 的功能不断完善,类似的工具相继出现。不仅可以检测代码中的潜在 Bug,还能做一些类型检查。
JavaScript 为什么需要 lint
起初 JavaScript 被开发出来的目的只是用在 Web 页面里实现一些简单的交互(例如表单提交)。随着互联网发展,网站需要展示的内容更加丰富,交互也变得复杂,前端项目也越来越庞大;2009 年,NodeJS 的诞生使得 JavaScript 可以跑在服务端,更是让其地位更加突出。在 2017 年 GitHub 开发语言排行榜中,JavaScript 毫无疑问排在第一位。[2]
再加上 JavaScript 本身设计上存在许多缺陷[3],代码不严谨也可能就会触发神奇的错误。例如 ==
和 ===
的混用,可能会产生类型不一致引起的 Bug,经验不足的开发者很难察觉出异常。
2002 年,Douglas Crockford 开发了可能是第一款针对 JavaScript 的语法检测工具 —— JSLint[4],并于 2010 年开源。
JSLint 和 JSHint
JSLint 面市后,确实帮助许多 JavaScript 开发者节省了不少排查代码错误的时间。但是 JSLint 的问题也很明显——几乎不可配置,所有的代码风格和规则都是内置好的;再加上 Douglas Crockford 老爷子推崇道系「爱用不用」的优良传统,不会向开发者妥协开放配置或者修改他觉得是对的规则。于是 Anton Kovalyov 吐槽:「JSLint 是让你的代码风格更像 Douglas Crockford 的而已」[5],并且在 2011 年 Fork 原项目开发了 JSHint。
JSHint 的特点就是可配置,同时文档也相对完善,而且对开发者友好。很快大家就从 JSLint 转向了 JSHint。
ESLint 的诞生
起初几年,JSHint 一直是前端代码检测工具的首选,包括 Nicholas C. Zakas 也是 JSHint 的用户。但在 2013 年,Zakas 大佬发现 JSHint 已经无法满足自己定制化规则的需求,而且和 Anton 讨论后达成共识这根本在不可能在 JSHint 上实现。同时 Zakas 还设想发明一个基于 AST 的 lint,可以动态执行额外的规则,同时可以很方便的扩展规则。[6]
2013 年的 6 月份,Zakas 发布了全新的 lint 工具——ESLint[7]。
几乎同一时间,另一款和 ESLint 实现机制类似的代码风格检测工具——JSCS[8]——也诞生了。
可扩展性的胜利
ESLint 的出现并没有撼动 JSHint 的霸主地位。由于前者是利用 AST 处理规则,用 Esprima 解析代码,执行速度要比只需要一步搞定的 JSHint 慢很多;其次当时已经有许多编辑器对 JSHint 支持完善,生态足够强大。真正让 ESLint 逆袭的是 ECMAScript 6 的出现。
2015 年 6 月,ES2015 规范正式发布。但是发布后,市面上浏览器对最新标准的支持情况极其有限。如果想要提前体验最新标准的语法,就得靠 Babel 之类的工具将代码编译成 ES5 甚至更低的版本,同时一些实验性的特性也能靠 Babel 转换。这时 JSHint 就略尴尬,ES2015 变化很大,短期内无法完全支持。ESLint 可扩展的优势一下就体现出来了,不仅可以扩展规则,甚至连解析器也能替换。Babel 团队就为 ESLint 开发了 babel-eslint[9] 替换默认解析器,让 ESLint 率先支持 ES2015 语法。
也是在 2015 年,React 的应用越来越广泛,诞生不久的 JSX 也愈加流行。ESLint 本身也不支持 JSX 语法。还是因为可扩展性,eslint-plugin-react[10] 的出现让 ESLint 也能支持当时 React 特有的规则。
2016 年,JSCS 开发团队认为 ESLint 和 JSCS 实现原理太过相似,而且需要解决的问题也都一致,最终选择合并到 ESLint,并停止 JSCS 的维护。[11]
至此,ESLint 完美躺赢,替代 JSHint 成为前端主流工具。[12]
参考
- https://en.wikipedia.org/wiki/Lint_(software)
- https://octoverse.github.com/
- Douglas Crockford 的《Javascript: The Good Parts》里有很多
- http://jslint.com
- https://medium.com/@anton/why-i-forked-jslint-to-jshint-73a72fd3612
- https://www.nczonline.net/blog/2013/07/16/introducing-eslint/
- https://eslint.org
- http://jscs.info
- https://github.com/babel/babel-eslint
- https://github.com/yannickcr/eslint-plugin-react
- https://www.nczonline.net/blog/2016/02/reflections-on-eslints-success
- https://medium.com/@markelog/jscs-end-of-the-line-bc9bf0b3fdb2