GitHub:我们为什么会弃用jQuery?

栏目: jQuery · 发布时间: 7年前

内容简介:我们最近完成了一个里程碑,将jQuery完全从GitHub.com的前端代码中移除。这标志着我们数年来逐步移除jQuery这个渐进式的过程终于结束了,我们现在已经完全移除了这个库。这篇文章将介绍我们是如何依赖上jQuery的,以及后来我们意识到不再需要它,到最后我们并没有使用另一个库或框架取代它,而是使用标准的浏览器API实现了我们所需要的一切。GitHub.com在2007年底开始使用jQuery 1.2.1。那是谷歌发布Chrome浏览器的前一年。当时还没有通过CSS选择器来查询DOM元素的标准方法,

我们最近完成了一个里程碑,将jQuery完全从GitHub.com的前端代码中移除。这标志着我们数年来逐步移除jQuery这个渐进式的过程终于结束了,我们现在已经完全移除了这个库。这篇文章将介绍我们是如何依赖上jQuery的,以及后来我们意识到不再需要它,到最后我们并没有使用另一个库或框架取代它,而是使用标准的浏览器API实现了我们所需要的一切。

为什么在早期jQuery对我们来说是有意义的

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

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

基于jQuery简单的接口所构建的扩展库也成为GitHub.com前端的基础构建块:pjax( https://github.com/defunkt/jquery-pjax )和facebox( https://github.com/defunkt/facebox )。

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

后来的Web标准

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

我们可以将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的比率,并监控指标走势随时间变化的情况,确保它保持不变或下降,而不是上升。

    GitHub:我们为什么会弃用jQuery?

  • 我们不鼓励在任何新代码中导入jQuery。为了方便自动化,我们创建了eslint-plugin-jquery( https://github.com/dgraham/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会导致性能损失,因此在生产环境中使用它们是不可行的。

英文原文: https://githubengineering.com/removing-jquery-from-github-frontend/

感谢覃云对本文的审校。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Two Scoops of Django

Two Scoops of Django

Daniel Greenfeld、Audrey M. Roy / CreateSpace Independent Publishing Platform / 2013-4-16 / USD 29.95

Two Scoops of Django: Best Practices For Django 1.5 is chock-full of material that will help you with your Django projects. We'll introduce you to various tips, tricks, patterns, code snippets, and......一起来看看 《Two Scoops of Django》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具