
如果你和我一样,你可能每天都在使用许多开源工具,却从未思考过它们是如何开始的。很少有项目会分享其创建的“原因”:它们试图解决的实际问题,以及首次遇到该问题的时间。当然,你无需了解开源项目的起源故事也能从中受益,但我总是觉得听听这一切是如何开始的很有意思。
我最近意识到,我从未分享过 ESLint 的起源故事。我曾在之前的文章中分享过我在此过程中做出的一些决定,但从未提及最初的导火索以及 ESLint 的诞生。正如你将看到的,ESLint 的创建并非源于某种神圣的干预或灵光一闪,而是通过一系列事件最终促成了 ESLint 的诞生。
那个错误
我刚到 Box 公司不久,一位队友正在处理一个奇怪的错误。一位客户报告说,在使用 Internet Explorer 7(当时我们可能是最后一家支持 IE7 的公司之一)的 Web 应用程序时遇到了问题。一位开发人员显然在一些 JavaScript 代码中使用了原生的 XMLHttpRequest
对象,而不是我们内部的包装器。这对任何其他浏览器都不是问题,内部使用 IE7 进行测试也没有问题。问题出现的原因是客户有一个内部安全策略,禁用了 Internet Explorer 中的 ActiveX,而且由于 IE7 中原生的 XMLHttpRequest
对象实际上只是 ActiveX 对象的包装器,因此也被阻止了。
解决方案很简单,只需确保每个人都知道使用内部的 Ajax 包装器,而不是原生的 XMLHttpRequest
对象。但是我们如何强制执行这一点呢?事实证明,Box 公司在构建系统中有一个 JavaScript “linter”。我之所以给 linter 加上引号,是因为它实际上只是一系列针对 JavaScript 代码运行的正则表达式。对于这种情况,我的队友添加了一个针对 “XMLHttpRequest” 的正则表达式,问题就解决了。如果有人试图提交与该模式匹配的 JavaScript 文件,构建就会失败。
以我的经验来看,在源代码上使用正则表达式从来都不是一个好主意。我希望有一种更好的方法在构建过程中进行此类检查。我认为一定有人已经解决了这个问题,所以我开始寻找解决方案。
会是 JSHint 吗?
我做的第一件事是给当时的 JSHint 维护者 Anton Kovalyov[1] 发送电子邮件。我记得读过一篇博客文章[2],说 JSHint 计划支持插件,但找不到任何关于该功能已实现的信息。从过去为 JSHint 贡献代码以及为 Yahoo 的一个项目修改 JSLint 的经验来看,我知道 JSHint 最初并没有设置为支持插件,而且如果没有正式的支持,就无法轻松修改 JSHint 来实现我想要的功能。
Anton 告诉我,插件提案已经停滞不前,看起来不会被实施。我很失望,因为这似乎是解决问题的最直接途径。我感谢了他,并请他不要因为我创建了一个能够满足我需求的 linter 而感到冒犯。我想支持 JSHint,但我觉得这是一个需要解决的问题,无论有没有 JSHint。
灵感
在深入研究 Box 公司的构建系统后,我发现除了临时的 JavaScript linter 之外,实际上还有一个 PHP linter 在运行。然而,PHP linter 比 JavaScript linter 复杂得多。PHP linter 没有使用正则表达式,而是将代码解析为抽象语法树 (AST),然后检查 AST 中的模式以进行报告。
当我阅读代码时,我可能一直在点头表示“是”。我立刻意识到这正是我需要为 JavaScript 做的事情。如果有一种方法可以将 JavaScript 解析为 AST,然后检查 AST 中的问题就好了。
基础工作
考虑到所有这些想法,我邀请 Ariya Hidayat[3] 来 Box 公司就他喜欢的任何主题发表演讲。碰巧的是,他做了一场关于 Esprima[4] 的演讲,Esprima 是他用 JavaScript 编写的 JavaScript 解析器。在演讲中,Ariya 讨论了拥有 JavaScript 的 AST 表示形式的用处,并引用了几个已经构建在 Esprima 之上的工具。这些工具包括用于遍历 AST 的 estraverse 和用于作用域分析的 escope,两者都是 Yusuke Suzuki 编写的。
随着 Ariya 继续演讲并举例说明 AST 可以解决的各种问题,一种新工具的想法在我脑海中形成了。对我来说,应该有一个工具可以执行 Ariya 提到的所有评估,这很有道理。毕竟,它们都只是为了不同的目的而使用 AST。为什么不使用一个所有工具都可以使用的 AST 呢?
开始
很大程度上归功于 Esprima、estraverse 和 escope 的可用性,我能够在几个周末内拼凑出 ESLint 的第一个原型。对我来说,这三个实用程序代表了我创建新工具所需的一切,该工具可以轻松找到 JavaScript 代码中的问题模式。如果我必须从头开始创建这些工具,毫无疑问,ESLint 今天就不会存在。基于这些工具,我能够快速迭代,最终,你今天所知的 ESLint 工具诞生了。
(我觉得有必要指出,当时不只有我一个人在寻求创建基于 AST 的 linter。JSCS[5] 也在大约同一时间开发,当前的 ESLint 维护者 Ilya Volodin 在发现 ESLint 之前也在开发自己的项目。如果当时我没有提出类似 ESLint 的东西,那么毫无疑问其他人也会提出。感谢 Ariya 和 Yusuke,所有的组件都已经存在,只是需要有人以有用的方式将它们组合在一起。)