/**
* 對於沒有代碼分割的,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的內容輸出