最近,我們將jQuery 完全從GitHub.com 的前端程式碼中移除了,這標誌著我們數年來逐步移除jQuery 這個漸進式的過程終於結束了,這對我們來說是一件里程碑式的事件。這篇文章將介紹過去我們是如何依賴上jQuery 的,隨著時間地推移,我們意識到不再需要它,但到最後我們並沒有使用另一個庫或框架取代它,而是使用標準的瀏覽器API 實現了我們所需要的一切。
早期,jQuery 對我們意義重大
GitHub.com 在 2007 年底開始使用 jQuery 1.2.1,那是Google發布 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 是不可行的。這種匆匆忙忙的做法可能會導致網站功能回歸。相反,我們採取了以下的策略:
1. 设定指标,跟踪整一行代码调用 jQuery 的比率,并监控指标走势随时间变化的情况,确保它保持不变或下降,而不是上升。
2. 我们不鼓励在任何新代码中导入 jQuery。为了方便自动化,我们创建了 eslint-plugin-jquery(https://github.com/dgraham/eslint-plugin-jquery),如果有人试图使用 jQuery 功能,例如 $.ajax,CI 检查将会失败。
3. 旧代码中存在大量违反 eslint 规则的情况,我们在代码注释中使用特定的 eslint-disable 规则进行了注解。看到这些代码的读者,他们都该知道,这些代码不符合我们当前的编码实践。
4. 我们创建了一个拉请求机器人,当有人试图添加新的 eslint-disable 规则时,会对拉取请求留下评论。这样我们就可以尽早参与代码评审,并提出替代方案。
5. 很多旧代码使用了 pjax 和 facebox 插件,所以我们在保持它们的接口几乎不变的同时,在内部使用 JS 重新实现它们的逻辑。静态类型检查有助于提升我们进行重构的信心。
6. 很多旧代码与 rails-behavior 发生交互,我们的 Ruby on Rails 适配器几乎是“不显眼的”JS,它们将 AJAX 生命周期处理器附加到某些表单上:
// 旧方法 $(document).on('ajaxSuccess', 'form.js-widget', function(event, xhr, settings, data) { // 将响应数据插入到 DOM 中 })
7. 我们选择触发假的 ajax* 生命周期事件,并保持这些表单像以前一样异步提交内容,而不是立即重写所有调用,只是会在内部使用 fetch()。
8. 我们自己维护了 jQuery 的一个版本,每当发现我们不再需要 jQuery 的某个模块的时候,就会将它从自定义版本中删除,并发布更轻量的版本。例如,在移除了 jQuery 的 CSS 伪选择器之后(如:visible 或:checkbox)我们就可以移除 Sizzle 模块了,当所有的 $.ajax 调用都被 fetch() 替换时,就可以移除 AJAX 模块。
这样做有两个目的:加快 JavaScript 执行速度,同时确保不会有新代码试图使用已移除的功能。
9. 我们根据网站的分析结果尽快放弃对旧版本 Internet Explorer 的支持。每当某个 IE 版本的使用率低于某个阈值时,我们就会停止向它提供 JavaScript 支持,并专注支持更现代的浏览器。尽早放弃对 IE 8 和 IE 9 的支持对于我们来说意味着可以采用很多原生的浏览器功能,否则的话有些功能很难通过 polyfill 来实现。
10. 作为 GitHub.com 前端功能开发新方法的一部分,我们专注于尽可能多地使用常规 HTML,并且逐步添加 JavaScript 行为作为渐进式增强。因此,那些使用 JS 增强的 Web 表单和其他 UI 元素通常也可以在禁用 JavaScript 的浏览器上正常运行。在某些情况下,我们可以完全删除某些遗留的代码,而不需要使用 JS 重写它们。
经过多年的努力,我们逐渐减少对 jQuery 的依赖,直到没有一行代码引用它为止。
自定义元素
近年来一直在炒作一项新技术,即自定义元素——浏览器原生的组件库,这意味着用户无需下载、解析和编译额外的字节。
从 2014 年开始,我们已经基于 v0 规范创建了一些自定义元素。然而,由于标准仍然在不断变化,我们并没有投入太多精力。直到 2017 年,Web Components v1 规范发布,并且 Chrome 和 Safari 实现了这一规范,我们才开始更广泛地采用自定义元素。
在移除 jQuery 期间,我们也在寻找用于提取自定义元素的模式。例如,我们将用于显示模态对话框的 facebox 转换为
我们的渐进式增强理念也延伸到了自定义元素上。这意味着我们将尽可能多地保留标记内容,然后再标记上添加行为。例如,
以下是实现
// 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 会导致性能损失,因此在生产环境中使用它们是不可行的。
以上是GitHub:我們為什麼會棄用jQuery?的詳細內容。更多資訊請關注PHP中文網其他相關文章!