jQuery2.x源碼解析(構建篇)


jQuery2.x源碼解析(構建篇) 

jQuery2.x源碼解析(設計篇) 

jQuery2.x源碼解析(回調篇) 

jQuery2.x源碼解析(緩存篇) 

 

筆者閱讀了園友艾倫 Aaron的系列博客《jQuery源碼分析系列》,跑艾倫的部分代碼后,感覺仍然不夠解渴,對jQuery依舊一知半解,產生了很多問題。閱讀源碼博客已經無法解決這些問題,所以筆者決定親自查看jQuery源碼,解除心中的疑問。閱讀的形式屬於自問自答,筆者會提出疑問,然后親自解答(吐槽:感覺有點像一休哥和將軍大人>_<)。

問題的來源主要有3種:

1.在閱讀園友艾倫博客后產生的疑問

2.以前就有疑問,艾倫博客卻沒有解答或者解釋不夠明白

3.閱讀源碼的過程中產生的疑問

所以這個jQuery源碼解析系列並非教程,而是筆者的學習jQuery源碼的筆記,因此才會采取問答這種不系統的形式。如果大家想系統學習jQuery源碼,還請仔細閱讀艾倫 Aaron的博客;或是直接閱讀jQuery在gitbub上的源碼(目前的master版本是2.2-stable,筆者閱讀的也是這個版本的代碼)。如果在閱讀后也和筆者一樣,對一些內容存在疑問,可以看看筆者的系列博客,看看你有沒有你疑惑的問題;如果沒有就發問給我,我們一起思考答案。


提問:如何構建jQuery的源碼

在我開始閱讀jQuery的源碼時,發現源代碼本身是有模塊化的,而艾倫 Aaron閱讀的版本沒有,他是直接閱讀的dist后的代碼。那么jQuery是如何構建源代碼的呢?

答:閱讀jQuery在github上的README.md文件,里面已經說得非常清楚了。先安裝git客戶端和nodejs及npm。然后將github上的資源克隆到本地,找一個目錄,然后打開命令行,輸入git的clone命令:

git clone git://github.com/jquery/jquery.git

本地就會克隆出jQuery的源代碼:

然后進入該目錄下,在命令行上運行如下命令,jQuery就會自動安裝npm模塊,並構建jQuery了。

npm run build

最后在dist目錄中,會構建出我們想要的jQuery文件了。


提問:git上的jQuery目錄結構是怎樣的

答:具體目錄結構可以看上圖,這里逐個介紹一下各個目錄和文件的作用:

.github git相關目錄
build 構建相關的腳本文件,筆者大概閱讀了一下,主要是創建兩個Grunt任務,負責構建(bulid)和輸出(dist)
dist 輸出構建后的文件,主要是jquery.js和jquery.min.js,以及jquery.min.map。這些就是我們最終使用的js文件了
external 放依賴的第三方代碼,jQuery中最重的第三方庫sizzle就在這里
node_modules nodejs的模塊文件,構建時候安裝的node非全局模塊都放在這里,屬性nodejs的小伙伴應該很清楚了
src jQuery自身的源代碼的目錄,這就是我們主要閱讀的部分
test 單元測試用例
.babelrc Babel的配置文件
.editorconfig editorconfig的配置文件,editorconfig是幫助開發者在不同的編輯器和IDE之間定義和維護一致的代碼風格的配置,很多ide都支持editorconfig的插件,使用這個就可以使各種ide下都能自動將代碼顯示成editorconfig約定的格式
.eslintignore eslint相關文件,配置不用於eslint語法檢測的文件目錄
.eslintrc.json eslint的配置文件。eslint和jshint比較像,可以認為是jshint的升級版,都是用來做語法檢測的。
.gitattributes git相關文件,用於設置文件的對比方式
.gitignore git的配置文件,配置用於配置不需要加入版本管理的文件
.mailmap 貌似是一個郵件地址列表
.npmignore npm相關文件,配置哪些文件不需要被發布到npmjs.org
.npmrc npm的配置文件
.travis.yml Tarvis-CI的配置文件,持續集成用的,github整合了持續集成服務travis,每一次push之后,travis就會定時執行“npm test”來測試項目
AUTHORS.txt 貢獻者名錄
CONTRIBUTING.md 貢獻代碼指引
Gruntfile.js Grunt的配置文件
LICENSE.txt 授權協議
README.md github項目的說明文檔
package.json npm的包文件

幾個地方值得注意一下:

1.jQuery是用RequireJs做模塊化工具的,所以jQuery的源代碼是用AMD規范。AMD這個模塊化規范主要活躍於基於瀏覽器的js模塊管理,他有着異步加載、依賴前置等非常好的特性,當然用來做后端的代碼模塊管理也可以,但是筆者終究認為這里用AMD有點“大材小用”了。jQuery用AMD規范做模塊化管理,可能是歷史原因的影響,早些年模塊化工具不像如今這么成熟。

2.jQuery是用Grunt構建的,jQuery自己做了構建的Grunt任務,具體代碼可以參考build目錄下的Grunt任務和Grunt的配置文件Gruntfile.js。基於Grunt,jQuery完成測試、構建、合並代碼、壓縮等工作,最終把構建好的文件拷貝到dist目錄里面。

3.jQuery配置了npm包相關的配置,說明jQuery本身也被發布到了npmjs.org上,我們可以直接用npm安裝jQuery。

4.jQuery有Babel的配置文件,那源代碼是不是用ES6的語法呢?


提問:jQuery有Babel的配置文件,難道jQuery的源代碼使用了ES6的語法?

答:答案是沒有的,我們先不看Babel在Grunt里面的配置,直接試一下能不能在源代碼中使用ES6。

先將源代碼里面添加一條ES6的語法,然后執行構建。這時我們會發現構建的時候會報錯,而且構建好的jQuery.js文件中ES6的語法也沒有被轉換為ES5的語法。這說明構建源代碼的時候並沒有啟用Babel。

我們在來看Babel在Grunt里面的配置

babel: {
    options: {
        sourceMap: "inline",
        retainLines: true
    },
    nodeSmokeTests: {
        files: {
            "test/node_smoke_tests/lib/ensure_iterability.js":
            "test/node_smoke_tests/lib/ensure_iterability_es6.js"
        }
    }
},

可以看出,Babel僅是將測試用例中的冒煙測試用例做了轉換,而源代碼則不在被轉換列表中。


提問:jQuery的源代碼用的是AMD規范做模塊化,為什么最終構建好的代碼卻沒有AMD的語句呢?

閱讀jQuery的源代碼,我們可以很清楚的看到AMD規范的語句。

然后在dist里面的構建好的文件中,我們卻找不到AMD規范語句的影子,jQuery是如何去掉了這些AMD語句呢?

答:起初筆者認為是用了一些Grunt上的插件,后來閱讀了build里面的代碼才發現,是在build里面使用正則將AMD語句去除。jQuery雖然是用的AMD做模塊化,但是具體的代碼結構還是有自己的一套策略,這個應該就是為了最后構建代碼而考慮的。

src的根目錄下,共有20多個js文件,很多js文件都有同名的目錄與之對應。目錄之中最特別的目錄就是var目錄,因為var目錄並不存在與之對應的名為var.js的文件。

var這個名字和js的關鍵字var相同,這和這個目錄這樣命名肯定是有關系的。沒錯,jQuery在去除AMD語句的時候,發現如果是var目錄里的文件的話,就會將其轉換為“var 文件名 = AMD輸出的對象”的形式。如下圖:

define( 'var/arr',[],function() {
    "use strict";

    return [];
} );

define( 'var/document',[],function() {
    "use strict";

    return window.document;
} );

define( 'var/getProto',[],function() {
    "use strict";

    return Object.getPrototypeOf;
} );

......

源代碼的這幾個模塊最終會把構建為:

var arr = [];
var document = window.document;
var getProto = Object.getPrototypeOf;
......

而對於非“var”目錄下的模塊,jQuery會將define關鍵字等AMD相關的語句直接移除。其中sizzle模塊更為特殊,jQuery在構建的時候還做了更多的操作,這里就不再細究了。

分析到這大家也能看出,jQuery這樣構建是會破壞AMD各個模塊的作用域的。我們之所以需要模塊化我們的代碼,一點是不希望我們把我們的內部(私有)變量聲明到全局作用域中,而JavaScript是一種函數級作用域的語言,jQuery在構建的時候去掉了AMD的函數形式,這樣所有模塊的代碼構建后的都會在同一個作用域里,所以在修改jQuery源代碼的時候一定要小心,不要在作用域里面隨意創建相同名稱的變量,防止造成模塊間的沖突。

以上就是jQuery去除AMD的過程。 


提問:源碼中經常有(#xxxx)這樣的注釋,他們是什么?

很多地方的注釋,都有(#xxxx)的字樣,如下:

// Use the original fragment for the last item
// instead of the first because it can end up
// being emptied incorrectly in certain situations (#8070).

答:這些是使用者提出的bug,jQuery的作者們根據bug修復的補丁。jQuery的源碼在github上,bug大多都被提到了github上的issues里面,里面的每個bug都有個編號,就是#后面的幾個數字,地址“https://github.com/jquery/jquery/issues/”加上這個編號就是bug所在的url了。進入這個url可以查看具體的bug說明和jQuery的作者們對於這個bug的修復情況。除了github的issues,jQuery在其官網也有一個buglist(“https://bugs.jquery.com/ticket/”),不過現在好像訪問不了了,這個網站的后面同樣有一串數字,#xxxx也有可能指的是這個網址里面bug的id。

 

了解了jQuery的構建過程后,我們就可以輕松愉快地瀏覽jQuery的源代碼了。事實上如果jQuery構建的時候采用webpack這樣的工具就簡單多了。jQuery沒有采用這樣的工具可能也是歷史原因,或者是出於進一步優化代碼的目的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM