當前位置:
首頁 > 科技 > GitHub:為什麼我們最終選擇放棄了 jQuery

GitHub:為什麼我們最終選擇放棄了 jQuery

【CSDN編者按】7月17日,GitHub改版並放棄了jQuery, 這對於GitHub來說,絕對是一件可以載入公司史冊的大事。

今天的文章中,四位參與改版和棄用JQuery的GitHub工程師,將介紹最初GitHub使用jQuery的歷史背景、和後來不再需要jQuery的原因,並講解GitHub如何在不引入其他庫、或框架的情況下,通過標準瀏覽器API,來實現他們需要的功能的。

為什麼最初需要jQuery

我們最近剛剛完成了一個里程碑,成功地從GitHub.com的前端代碼的依賴中去掉了jQuery。這標誌著這項一點一滴持續了多年的jQuery解耦合工作的完成,以及我們終於可以完全刪除這個庫了。

GitHub.com在2007年末引入了jQuery 1.2.1作為依賴。當時距離Google發布Chrome瀏覽器的第一版,還有一年的時間。

當時沒有什麼標準的方法,通過CSS選擇器,來查詢DOM元素,也沒有標準的方式,來實現元素的視覺動畫,而由Internet Explorer倡導的XMLHttpRequest介面,也像許多其他API一樣,在各種瀏覽器上的實現不一致。

而jQuery使得操作DOM、定義動畫和實現「AJAX」請求,變得十分簡單。簡單來說,它使得Web開發者可以創建更現代、更動態的效果。

最重要的是,通過jQuery在一種瀏覽器上實現的功能,基本上也能在其他瀏覽器上運行。

在GitHub的早期,許多功能才剛剛起步,有了jQuery,我們的小團隊才能迅速地建立原型、並推出新功能,而不需要為每種Web瀏覽器調整代碼。

我們還把jQuery簡單的介面,作為藍圖來構建擴展庫,這些庫(pjax, https://github.com/defunkt/jquery-pjax和Facebox,https://github.com/defunkt/facebox),後來成了GitHub.com前端的其他部分的組成部分。

我們會永遠感謝John Resig和其他jQuery貢獻者們,創建並維護了這個十分有用、並且在歷史上十分重要的庫。

後來的Web標準

多年以後,GitHub成長為擁有數百名工程師的公司,還逐漸組成了一個獨立的團隊,專門負責我們發送到瀏覽器上的JavaScript代碼的尺寸和質量。

我們一直在監視技術債務,而有些技術債務的原因,是那些曾經有價值、但後來隨著時間的發展而失去了價值的依賴。

而對於jQuery,我們將它與現代瀏覽器中迅速發展的Web標準做了比較,結果發現:

$(selector) 可以簡單地用querySelectorAll()替換;

CSS類名切換,可以通過Element.classList實現;

CSS現在支持在樣式表中定義視覺動畫,無需使用JavaScript;

$.ajax請求可以用Fetch標準實現;

addEventListener()介面已經十分穩定,足以跨平台使用;

我們可以用一個輕量級的庫,來封裝事件代理模式;

jQuery提供的一些語法糖,已隨著JavaScript語言的發展,而變得多餘。

而且,鏈式語法並不能滿足我們直觀地書寫代碼的需要。例如:

$(".js-widget")

.addClass("is-loading")

.show()

這種語法很容易編寫,但以我們的標準來看,它並不能很好地傳達作者的意圖。作者希望頁面上只有一個JS-Widget元素、還是有多個?

而且,如果我們修改網頁代碼時,一不小心刪掉了JS-Widget類名,瀏覽器會產生異常並告訴我們發生了錯誤嗎?

默認情況下,如果類名不匹配,jQuery會靜默地忽略整個表達式,但在我們看來,這種行為與其說是功能,不如說是個Bug。

最後一點,我們想使用Flow(https://flow.org/)進行標註,從而在構建時實現靜態類型檢查。

但我們得出結論,鏈式語法並不能很好地適應靜態分析,因為幾乎所有jQuery的函數的返回值,都是同一種類型。

我們選擇Flow、而不是其他庫的原因是因為當時像@flow weak模式等特性可以讓我們逐漸地、有效地給大量幾乎沒有任何類型的代碼添加類型。

總的來說,jQuery解耦合,意味著我們可以更依賴於Web標準,將MDN Web文檔,作為事實上的前端開發標準,方便以後維持代碼的靈活性,並最終從打包文件中,去掉一個30KB的依賴,提高頁面載入速度、和JavaScript的執行時間。

增量解耦合

即使確定了最終目標,我們也不能簡單地,把所有資源都花在,使用原生JS重寫jQuery的事情上。

一旦發生什麼事情,這種急功近利,會導致許多網站功能倒退,從而不得不花更多時間去解決。我們必須要這樣做:

設定好度量標準,跟蹤jQuery調用次數和全部代碼行數的比例,並隨時監視該度量,保證它不變或減小,而不會增加。

我們不鼓勵在任何新代碼中使用jQuery。為了使用自動化減輕工作量,我們創建了eslint-plugin-jquery(https://github.com/dgraham/eslint-plugin-jquery#readme),如果任何人嘗試使用jQuery功能(如$.ajax),它就會造成CI檢查失敗。

舊代碼中有大量的ESLint規則違反,這些違反我們都使用eslint-disable規則在代碼注釋中標註出來了。這樣就能儘快進行代碼審查、並集思廣益。

許多舊代碼顯式地耦合了Pjax和Facebox這兩個jQuery插件的外部介面,因此我們在使用原生JS,替換這兩者的實現時,儘力保持介面不變。靜態檢查讓我們能更信心地進行重構。

許多就代碼都與rails-behaviors(http://josh.github.io/rails-behaviors/)有介面,後者是我們在Ruby on Rails和JS之間的適配器。這種介面會為特定的表單,添加一個AJAX生命周期處理函數。

// LEGACY APPROACH

$(document).on("ajaxSuccess","form.js-widget",function(event, xhr, settings, data){

// insert response data somewhere into the DOM

})

為避免不得不用新方法,一次性重寫整個網站,我們採用了觸發偽「*AJAX*」生命周期事件的方式,使這些表單,能像以前一樣繼續非同步提交內容,只不過內部使用的是fetch()。

我們定製了一個jQuery,一旦我們認為某個模塊不再需要,就把它從定製版本中刪掉,使jQuery更靈巧。

例如,在刪除最後一個jQuery專用的CSS偽類(:visible、:CheckBox等),我們就刪掉了Sizzle模塊(https://sizzlejs.com/);在使用fetch()替換了最後一個$.ajax調用之後,就刪掉了AJAX模塊。

這樣做有兩個目的,一是加快JavaScript執行速度,一是確保新功能不會使用被刪掉的功能。

根據網站訪問分析的結果,只要有可能,我們就會刪掉支持舊Internet Explorer版本的部分。當某個IE版本的使用率,降到某個閾值之下,我們就不會再為其提供JavaScript,從而得以專註於,支持更多現代瀏覽器。

提早去掉IE8~9的支持,使得我們可以使用更多的原生瀏覽器功能,不用再勉強進行Polyfill。

作為構建GitHub.com前端的新方法的一部分,我們儘可能採用基礎的HTML來實現功能,只把JavaScript用作漸進式增強。

這樣,即使Web表單和其他UI元素上使用了JS,它們也能在禁用了JavaScript的瀏覽器中運行。一些情況下,我們可以刪掉整箇舊有行為,不用再使用原生JS重寫。

通過這些方法(以及多年來積累的其他方法),我們得以逐漸地減小對jQuery的依賴,直到沒有一行代碼使用它。

自定義元素

近幾年人們談論得最多的一項技術就是自定義元素,它是個瀏覽器原生的組件庫,也就是說用戶無需下載、解析或編譯任何框架。

我們從2014年起,就根據v0規格,建立了一些自定義元素。但是,由於當時的Web標準依然不明確,所以我們並沒有深入研究。

直到2017年,Web組件的v1規格發布,而且Chrome和Safari都開始支持,我們才開始在大範圍內使用自定義元素。

在jQuery遷移過程中,我們尋找適合提取成自定義元素的部分。例如,我們將使用Facebox顯示對話框的代碼,改成了元素。

漸進式增強的思想,也應用到了自定義元素中。就是說,我們儘可能保持標籤的內容,僅在標籤不能實現的地方,添加新的行為。

例如,默認會顯示原始的時間戳,然後增強翻譯成本地時區內的時間;而如果嵌入到元素中,那麼即使沒有JavaScript,本身也是互動式的,但會利用提高可用性的功能進行增強。

下面是實現自定義元素的例子。

// The local-time element displays time in the user"s current timezone

// and locale.

//

// Example:

// Sep 6, 2018

//

classLocalTimeElementextendsHTMLElement{

staticgetobservedAttributes() {

return["datetime"]

}

attributeChangedCallback(attrName, oldValue, newValue) {

if(attrName ==="datetime") {

constdate =newDate(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方式,會給那些操縱與Web組件無關的DOM的代碼,也造成大量性能損失,所以還不適合在生產環境中使用。

Polyfill

我們在轉換成標準瀏覽器功能的過程中,使用了下面這些polyfill。我們盡量僅在絕對必須時——即需要兼容舊版本瀏覽器時——才使用polyfill。

github/eventlistener-polyfill;

github/fetch;

github/form-data-entries;

iamdustan/smoothscroll;

javan/details-element-polyfill;

jonathantneal/closest;

kumarharsh/custom-event-polyfill;

marvinhagemeister/request-idle-polyfill;

mathiasbynens/Array.from;

mathiasbynens/String.prototype.codePointAt;

mathiasbynens/String.prototype.endsWith;

mathiasbynens/String.prototype.startsWith;

medikoo/es6-symbol;

nicjansma/usertiming.js;

rubennorte/es6-object-assign;

stefanpenner/es6-promise;

webcomponents/template;

webcomponents/URL;

webcomponents/webcomponentsjs;

WebReflection/url-search-params;

yola/classlist-polyfill。

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

作者:mislav, koddsson, muan, keithamus

譯者:彎月,責編:胡巍巍


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 CSDN 的精彩文章:

不要做一個只會面向搜索編程的程序員!
程序員該敬畏每一行代碼?填好每一個坑才是!

TAG:CSDN |