webpack打包文件解析


/**

  * 對於沒有代碼分割的,webpack會打包生成main.js一個大的自執行函數

  * 函數參數是一個對象,鍵值分別是路徑和模塊的函數

  * 函數內部定義了一些方法,包括__webpack_require__

  * 函數內部執行邏輯會從一個入口開始進行webpackrequire按內部依賴的邏輯來執行函數

  *

  */

 

 

 

 

/*

  對於有代碼分割的內容,webpack除了main.js還會生成0.js,1.js...等

 

 

20191026補充注:

此分析時,使用了dynamic-import-webpack插件,實際webpack4可以不引入這個插件,不引入的話,動態import('xx.js').then(中直接拿到的是module,而不是下面分析中直接拿到的可執行函數名,后文整個分析流程和動態包的加載邏輯沒有變化。 

 

 

 

原始代碼:

index.js:

show.js:

 

 

sb.js:

 

 

show-child.js:

 

 

 

打包生成的main.js里的大自執行函數的函數參數是這樣的:

 

(./src/index.js是入口)

 

 

下面的自執行函數是這樣的:

 

 

被轉換成了

 

 

先執行__webpack_require__.e然后在then里面resolve(__webpack_require__(‘./src/show.js))

 

 

__webpack_require__.e是干什么的:

 

 

webpack_require__.e內部聲明了一個空數組promises

 

功能:

 

1.該函數會修改在大自執行函數中定義的installedChunks (顯示安裝chunk的狀態)

 

 

 

2.創建了一個installedChunkData對象 是installedChunks[chunkId]

  對象的結構是[resolve,reject,promise]

 

3.如果正在加載

  會執行

promises.push(installedChunkData[2]);   <- - -這里的[2]就是promise對象

         否則 創建一個新promise對象

 

 

 

  4.創建script標簽:

 

 

 

 

__webpack_require__.e函數創建了一個script標簽,引入0.js..等 插入到head標簽的后面

 

返回一個promise,promise.then里面可以拿到一個數組,[]數組中內容是           ( return Promise.all(promises)    // Promise {<pending>}

 

 

__webpack_require__.e函數最終返回的是一個promise     (  這個promise后面then的調用時機是——promises數組里所有promise對象都確定了完成狀態

 

 

 

總結:  __webpack_require__.e是創建一個script標簽,然后異步加載, 函數最后返回一個promise ,當promise被resolve或reject的時候(即,require__.e創建的promises數組里所有元素都有了確定狀態時)可以被后面的.then接收到

 

 

 當創建的script標簽加載完成了,promise就會被resolve或reject,

看一下創建的標簽的內容:

 

2.js內容:

創建的這個script標簽(異步加載)的內容是什么呢,拿2.js來分析一下:

 

window.webpackJsonp數組 中使用push方法 : [[2],{‘….’:{  }}]

 

 

此時的push方法已經被改寫了:

 

 

 

window下jsonpArray的push方法是webpackJsonpCallback

於是調用 webpackJsonpCallback([[2],{‘…’{}}]

 

執行:

 

 

 

 

該方法會將chunk們的加載狀態記錄管理,將moreModules裝載到modules中

 

后面的resolves.shift()()會導致_webpack_require__.e里產生的promise對象resolve出來,

到這里一個chunk加載完成,將會執行_webpack_require__.e.then后面的邏輯

 

 

 

流程:創建script標簽加載chunk

   chunk 指一個要異步加載的大數據塊 在這個例子中0.js,1.js,2.js就是chunk

 

  然后chunk里面一般是這樣的 然后調用被改寫過的window.webpackJsonp.push方法進行加載,將chunk們的加載狀態記錄管理,將moreModules裝載到modules中

 

 

 

總結:__webpack_require__.e 會創建script標簽src地址是依賴的js文件,將這個script標簽插入到head標簽后面,最終返回一個promise對象

 

被創建好的script標簽內容是一段會被立即執行的表達式,使用window.webpackJsonp.push(被改寫過的一個方法)方法來裝載管理chunk安裝狀態,並將moremodules插入 到modules中。 還調用到了__webpack_require__.e中創建的promise的resolve()方法 ,當resolve結束后,__webpack_require__.e 的promise對象的.then方法也會被觸發。(因為__webpack_require__.e中最終返回的是Promise.all([…]))

 

 

 

倉庫地址 https://github.com/eret9616/webpack-bundle.js

分支 asyncloading syncloading  

直接以dist目錄啟動服務

 

 

 

附:

webpack_require__.r  將這個module標記為esModule ,重寫Symbol.toStringTag接口,添加__esModule屬性 (Symbol.toStringTag是什么:普通對象的toString是'object Object',修改Symbol.toStringTag接口后,toString可以變成'object xxxx')

webpack_require__.t  當import('...xxx.js')動態引入一個commonjs模塊的時候,會創建一個對象,將這個對象標記為esModule,將commonjs模塊轉換得到等價的esModule的內容輸出


免責聲明!

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



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