摘要: 技術債清理流程指南。javascript
最近,咱們將jQuery 徹底從 GitHub.com 的前端代碼中移除了,這標誌着咱們數年來逐步移除 jQuery這個漸進式的過程終於結束了,這對咱們來講是一件里程碑式的事件。這篇文章將介紹過去咱們是如何依賴上jQuery的,隨着時間地推移,咱們意識到再也不須要它,但到最後咱們並無使用另外一個庫或框架取代它,而是使用標準的瀏覽器API實現了咱們所須要的一切。前端
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前端的基礎構建塊:pjax和facebox。git
咱們將永遠不會忘記John Resig和jQuery貢獻者建立和維護的這樣一個有用的基本庫。github
多年來,GitHub成長爲一家擁有數百名工程師的公司,並逐漸成立了一個專門的團隊,負責 JavaScript代碼的規模和質量。咱們一直在排除技術債務,有時技術債務會隨着依賴項的增多而增加,這些依賴項在一開始會爲咱們帶來必定的價值,但這些價值也隨着時間的推移而降低。ajax
咱們能夠將jQuery與現代瀏覽器支持的Web標準的快速演化進行比較:小程序
另外,鏈式語法不能知足咱們想要的編寫代碼的方式。例如:微信小程序
$('.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。爲了方便自動化,咱們建立了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專一於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/