GitHub:我們為什麼會棄用jQuery?
我們將 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 貢獻者建立和維護的這樣一個有用的基本庫。
如果你也是一個前端黨,無論是在學習前端開發,還是已經工作的,這裡推薦一下我們的前端學習交流群:731771211 ,這裡是把夢想照亮的地方,同為了生活而拼搏奮鬥,大家互相幫助。新手加入即可獲得經過整理的最前沿的前端技術資料,不定時更新技術,與企業需求同步。好友都在裡面交流,每天都會有大牛定時講解前端技術!知識改變命運
點選: 加入
後來的 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 的比率,並監控指標走勢隨時間變化的情況,確保它保持不變或下降,而不是上升。
-
我們不鼓勵在任何新程式碼中匯入 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 會導致效能損失,因此在生產環境中使用它們是不可行的。
如果你也是一個前端黨,無論是在學習前端開發,還是已經工作的,這裡推薦一下我們的前端學習交流群:731771211 ,這裡是把夢想照亮的地方,同為了生活而拼搏奮鬥,大家互相幫助。新手加入即可獲得經過整理的最前沿的前端技術資料,不定時更新技術,與企業需求同步。好友都在裡面交流,每天都會有大牛定時講解前端技術!知識改變命運
點選: 加入
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69901074/viewspace-2375632/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 為什麼放棄jQueryjQuery
- 因果迷境:為什麼我們會問“為什麼”?
- 《後來的我們》,為什麼我們會錯過彼此?
- 為什麼我們放棄了 Vue?Vue 和 React 深度對比VueReact
- Jquery會死嗎?我為什麼不用vue寫富文字!jQueryVue
- 2019 為什麼我們還會繼續使用 PHP ?PHP
- 我們為什麼會喜歡挖礦遊戲?遊戲
- 為什麼我們需要 VuexVue
- 我們為什麼要用RedisRedis
- 我們為什麼而工作
- 我們為什麼需要CDP?
- 為什麼我們放棄使用Kafka Streams實現全部的事件溯源?-MateuszKafka事件
- 為什麼量子計算會對我們產生威脅?
- 我們為什麼會刪除不了叢集的 Namespace?namespace
- 為什麼我們要選用 Elasticsearch 而不用 SolrElasticsearchSolr
- Kubernetes為什麼將會棄用Docker支援? - Dixie3FlatlineDocker
- 我們為什麼需要async/await ?AI
- 到底為什麼我們需要 Clickhouse?
- 我們為什麼需要雲原生?
- 我為什麼放棄MySQL?選擇了MongoDBMySqlMongoDB
- 為什麼我在2019年仍在使用jQuery?jQuery
- GC是什麼?為什麼我們要去使用它GC
- 什麼是Web workers?為什麼我們需要他Web
- 我們為什麼要用英文寫文件?
- 我們為什麼需要 lock 檔案
- [譯] 為什麼我們需要 Web 3.0Web
- 為什麼springcloud值得我們學習?SpringGCCloud
- 為什麼我們不使用GraphQL? - Wundergraph
- 為什麼我們要新增 super(props) ?
- 我們為什麼要學豐田?
- GitHub 上的大佬們打完招呼,會聊些什麼?Github
- 我們為什麼會玩以日常生活為題材的遊戲?遊戲
- 為什麼越來越少的人用jQueryjQuery
- [譯] 2019 年了,為什麼我還在用 jQuery?jQuery
- 為什麼我們越來越不喜歡用網站?網站
- 為什麼我們放棄 Python 而選擇 Go?(getstream.io 的架構變遷)PythonGo架構
- 我們用代理IP可以做什麼?
- 為什麼我們無法避免複雜?