GitHub:咱们是这样弃用jQuery的

摘要: 技术债清理流程指南。javascript

最近,咱们将jQuery 彻底从 GitHub.com 的前端代码中移除了,这标志着咱们数年来逐步移除 jQuery这个渐进式的过程终于结束了,这对咱们来讲是一件里程碑式的事件。这篇文章将介绍过去咱们是如何依赖上jQuery的,随着时间地推移,咱们意识到再也不须要它,但到最后咱们并无使用另外一个库或框架取代它,而是使用标准的浏览器API实现了咱们所须要的一切。前端

早期,jQuery对咱们意义重大

GitHub.com在2007年末开始使用jQuery 1.2.1,那是谷歌发布 Chrome 浏览器的前一年。当时尚未经过CSS选择器来查询DOM元素的标准方法,也没有动态渲染元素的样式的标准方法,而Internet Explorer的XMLHttpRequest接口与其余不少API同样,在浏览器之间存在不一致性问题。java

jQuery让DOM操做、建立动画和“AJAX”请求变得至关简单,基本上,它让Web开发人员可以建立更加现代化的动态Web体验。最重要的是,使用jQuery为一个浏览器开发的代码也适用于其余浏览器。在GitHub的早期阶段,jQuery让小型的开发团队可以快速进行原型设计并开发出新功能,而无需专门针对每一个Web浏览器调整代码。jquery

基于jQuery简单的接口所构建的扩展库也成为GitHub.com前端的基础构建块:pjaxfaceboxgit

咱们将永远不会忘记John Resig和jQuery贡献者建立和维护的这样一个有用的基本库。github

后来的Web标准

多年来,GitHub成长为一家拥有数百名工程师的公司,并逐渐成立了一个专门的团队,负责 JavaScript代码的规模和质量。咱们一直在排除技术债务,有时技术债务会随着依赖项的增多而增加,这些依赖项在一开始会为咱们带来必定的价值,但这些价值也随着时间的推移而降低。ajax

咱们能够将jQuery与现代浏览器支持的Web标准的快速演化进行比较:小程序

  • $(selector)模式可使用querySelectorAll()来替换;
  • 如今可使用Element.classList来实现CSS类名切换;
  • CSS如今支持在样式表中而不是在JavaScript中定义可视动画;
  • 如今可使用Fetch Standard执行$.ajax请求;
  • addEventListener()接口已经足够稳定,能够跨平台使用;
  • 咱们可使用轻量级的库来封装事件委托模式;
  • 随着JavaScript语言的发展,jQuery提供的一些语法糖已经变得多余。

另外,链式语法不能知足咱们想要的编写代码的方式。例如:微信小程序

$('.js-widget')
  .addClass('is-loading')
  .show()

这种语法写起来很简单,可是根据咱们的标准,它并不能很好地传达咱们的意图。做者是否指望在当前页面上有一个或多个js-widget元素?另外,若是咱们更新页面标记并意外遗漏了js-widget类名,浏览器是否会抛出异常会告诉咱们出了什么问题?默认状况下,当没有任何内容与选择器匹配时,jQuery会跳过整个表达式,但对咱们来讲,这是一个bug。浏览器

最后,咱们开始使用Flow来注解类型,以便在构建时执行静态类型检查,而且咱们发现,链式语法不适合作静态分析,由于几乎全部jQuery方法返回的结果都是相同的类型。咱们当时之因此选择Flow,是由于@flow weak模式等功能可让咱们逐步将类型应用于无类型的代码库上。

总而言之,移除jQuery意味着咱们能够更多地依赖Web标准,让MDN Web文档成为前端开发人员事实上的默认文档,在未来能够维护更具弹性的代码,而且能够将30KB的依赖从咱们的捆绑包中移除,加快页面的加载速度和JavaScript的执行速度。

逐步解耦

虽然定下了最终目标,但咱们也知道,分配全部资源一次性移除 jQuery 是不可行的。这种匆匆忙忙的作法可能会致使网站功能出现回归。相反,咱们采起了如下的策略:

  • 设定指标,跟踪整一行代码调用jQuery的比率,并监控指标走势随时间变化的状况,确保它保持不变或降低,而不是上升。

  • 咱们不鼓励在任何新代码中导入jQuery。为了方便自动化,咱们建立了eslint-plugin-jquery,若是有人试图使用jQuery功能,例如 $.ajax,CI检查将会失败。

  • 旧代码中存在大量违反eslint规则的状况,咱们在代码注释中使用特定的eslint-disable 规则进行了注解。看到这些代码的读者,他们都该知道,这些代码不符合咱们当前的编码实践。

  • 咱们建立了一个拉请求机器人,当有人试图添加新的eslint-disable规则时,会对拉取请求留下评论。这样咱们就能够尽早参与代码评审,并提出替代方案。

  • 不少旧代码使用了pjax和facebox插件,因此咱们在保持它们的接口几乎不变的同时,在内部使用JS从新实现它们的逻辑。静态类型检查有助于提高咱们进行重构的信心。

  • 不少旧代码与rails-behavior发生交互,咱们的Ruby on Rails适配器几乎是“不显眼的”JS,它们将 AJAX 生命周期处理器附加到某些表单上:

// 旧方法
  $(document).on('ajaxSuccess', 'form.js-widget', function(event, xhr, settings, data) {
    // 将响应数据插入到 DOM 中
  })
  • 咱们选择触发假的ajax*生命周期事件,并保持这些表单像之前同样异步提交内容,而不是当即重写全部调用,只是会在内部使用fetch()。

  • 咱们本身维护了jQuery的一个版本,每当发现咱们再也不须要jQuery的某个模块的时候,就会将它从自定义版本中删除,并发布更轻量的版本。例如,在移除了jQuery的CSS伪选择器以后(如:visible 或:checkbox)咱们就能够移除Sizzle模块了,当全部的$.ajax调用都被 fetch()替换时,就能够移除AJAX模块。这样作有两个目的:加快JavaScript执行速度,同时确保不会有新代码试图使用已移除的功能。

  • 咱们根据网站的分析结果尽快放弃对旧版本Internet Explorer的支持。每当某个 IE 版本的使用率低于某个阈值时,咱们就会中止向它提供JavaScript支持,并专一支持更现代的浏览器。尽早放弃对IE 8和IE 9的支持对于咱们来讲意味着能够采用不少原生的浏览器功能,不然的话有些功能很难经过polyfill来实现。

  • 做为GitHub.com前端功能开发新方法的一部分,咱们专一于尽量多地使用常规HTML,而且逐步添加JavaScript行为做为渐进式加强。所以,那些使用JS加强的Web表单和其余UI元素一般也能够在禁用JavaScript的浏览器上正常运行。在某些状况下,咱们能够彻底删除某些遗留的代码,而不须要使用JS重写它们。

通过多年的努力,咱们逐渐减小对jQuery的依赖,直到没有一行代码引用它为止。

自定义元素

近年来一直在炒做一项新技术,即自定义元素——浏览器原生的组件库,这意味着用户无需下载、解析和编译额外的字节。

从 2014 年开始,咱们已经基于 v0 规范建立了一些自定义元素。然而,因为标准仍然在不断变化,咱们并无投入太多精力。直到 2017 年,Web Components v1 规范发布,而且 Chrome 和 Safari 实现了这一规范,咱们才开始更普遍地采用自定义元素。

在移除 jQuery 期间,咱们也在寻找用于提取自定义元素的模式。例如,咱们将用于显示模态对话框的 facebox 转换为<details-dialog>元素(https://github.com/github/details-dialog-element)。

咱们的渐进式加强理念也延伸到了自定义元素上。这意味着咱们将尽量多地保留标记内容,而后再标记上添加行为。例如,<local-time>默认显示原始时间戳,它被升级成能够将时间转换为本地时区,而对于<details-dialog>,当它被嵌在 <details>元素中时,能够在不使用 JavaScript 的状况下具有交互性,它被升级成具备辅助加强功能。

如下是实现<local-time>自定义元素的示例:

// local-time 根据用户的当前时区显示时间。
//
// 例如:
//   <local-time datetime="2018-09-06T08:22:49Z">Sep 6, 2018</local-time>
//
class LocalTimeElement extends HTMLElement {
  static get observedAttributes() {
    return ['datetime']
  }

  attributeChangedCallback(attrName, oldValue, newValue) {
    if (attrName === 'datetime') {
      const date = new Date(newValue)
      this.textContent = date.toLocaleString()
    }
  }
}

if (!window.customElements.get('local-time')) {
  window.LocalTimeElement = LocalTimeElement
  window.customElements.define('local-time', LocalTimeElement)
}

咱们很期待 Web 组件的 Shadow DOM。Shadow DOM 的强大功能为 Web 带来了不少可能性,但也让 polyfill 变得更加困难。由于使用 polyfill 会致使性能损失,所以在生产环境中使用它们是不可行的。

参考

关于Fundebug

Fundebug专一于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了7亿+错误事件,获得了Google、360、金山软件、百姓网等众多知名用户的承认。欢迎免费试用!

版权声明

转载时请注明做者Fundebug以及本文地址: https://blog.fundebug.com/2018/11/23/removing-jquery-from-github-frontend/

相关文章
相关标签/搜索