準備編譯的代碼資源
一共四個文件資源
// index.js
import { varA, varB } from './mod1'
import m2 from './mod2'
let b = 'bbb'
console.log(varA, varB, m2)
// mod1.js
export const varA = 'aaa'
export const varB = 'bbb'
// mod2.js
import { c } from './modc.js'
export default {
m1: 'm1',
m2: 'm2'
}
// modc.js
export const c = 'cccc'
webpack 資源加載 - 主流程
1.Compiler.js - run,在 run 方法中執(zhí)行 this.compile()

2.Compiler.js - compile,生成 Compiltaion 實例執(zhí)行 make hooks

make hooks 的實現(xiàn)在 SingleEntryPlugin 插件里,生成 SingleEntryDependency 調用 compilation 實例的 addEntry 方法.


3.Compilation.js - addEntry - 處理入口 entry 執(zhí)行 _addModuleChain
addEntry 中把 SingleEntryPlugin 生成的 dep 也就是 entry 傳入執(zhí)行 _addModuleChain,發(fā)現(xiàn)執(zhí)行的 _addModuleChain 回調有在 this.entries 中 push 一個 module 的線索

4.Compilation.js - _addModuleChain - factory 創(chuàng)建 module - addModule 到 this.modules
_addModuleChain 創(chuàng)建 module,此時第一個 module 出現(xiàn),這個 module 是以為 entry 創(chuàng)建的

5.Compilation.js - _addModuleChain - addModule 把 module push 到 this.modules 中


5.Compilation.js - _addModuleChain - buildModule - 對 entry 的 module 進行 Loader 處理
buildModule 由 NormalModule.js 實現(xiàn),對遠嗎執(zhí)行 loader 并收集依賴

此時 compilation 實例中 enties 和 modules 各自有一個 module , 這個 module 都是 entry 入口文件生成的。

此時 entry 的 module 已經分析出了 import 導入的模塊語法

entry 的 module 的源碼也被 babel-loader 處理成了 ES5 的代碼

6.Compilation.js - _addModuleChain - afterBuild - 主入口 module 處理完畢
在 processModuleDependencies 中對 entry 的 module 的依賴進行遞歸調用 buildModule,分析出所有的 module 放入到 this.modules 中最后進入 seal 階段。此時 modues 已經不止 entry 的 module 了,把所有 import 語句導入的 module 都收集完畢。

Compilation.js - _addModuleChain 做了什么
1.傳入 entry 信息
2.moduleFactory 創(chuàng)建 entry 的 module, 添加到 this.modules 和 this.enties 中
3.調用 buildModule,對 entry 的 module 進行 loader 調用、分析 entry 源碼中的 import 導入模塊語句分析出依賴信息。
4.執(zhí)行 afterBuild 在 processModuleDependencies 中處理 entry module 的依賴文件,處理成 module 放入 this.modules 中,完成資源加載
buildModule
buildModule 中執(zhí)行當前 module 類型的 module.build

進入 NormalModule.js 的 doBuild 執(zhí)行 LoaderRunner.js 文件 runLoaders

這里遇到 LOADER_EXECUTION 函數(shù),里面 的 fn 就是 loader, args 是 loader 處理前的源碼

到這一步中間就在 loader 中執(zhí)行,經過 loader 出來后的代碼就是 arguments, 這里已經轉譯成 ES5 了, 執(zhí)行的 callback 是 doBuild 的回調

帶著 loader 處理后的源碼回到 doBuild 回調中走this.parser.parse 中

帶著 loader 處理后的源碼進入 parse 出來 ast 對象

通過 acorn 三方模塊對源碼分析出 ast ,描述源碼的語義

parse 最后就是返回一個 state,這時 state 中 module.dependencies 還是空的

源碼生成的 ast 經過 walker 的處理,在 state 上分析出了所有 import 文件的信息

用這種語法徹底描述出源碼中的依賴關系

此時 entry 文件的就處理完了,此時 compilation 實例上的 this.modules 仍然只有一個 entry module,但是現(xiàn)在 webpack 已經通過 ast 解析出了所有 entry module 中的依賴模塊的信息,后面就根據(jù)這些依賴信息生成各個模塊
資源遞歸收集依賴
對依賴進行處理,發(fā)現(xiàn)是 import 語義的依賴才進行處理

處理收集 import 的依賴調用 addModuleDependencies,方法里與 buildModule 類似,工廠生成 module,addModule 加入到 this.modules 中,進行 loader 處理源碼

最后進入 afterBuild 判斷當前處理的 module 結果是否繼續(xù)有依賴進行遞歸處理

總結
1.Compiler.js - compiler.run 執(zhí)行 this.compile()
2.Compiler.js - compile,生成 Compiltaion 實例執(zhí)行 make hooks
3.Compilation.js - addEntry - 處理入口 entry 執(zhí)行 _addModuleChain
4._addModuleChain 使用工廠函數(shù)創(chuàng)建 module,使用 module 自己的 build
5.build 在 NormalModule 中執(zhí)行 doBuild 調用 LoaderRunner.js 的 runLoaders 使用 loader 處理源碼
6.loader 處理完源碼回到 doBuild 回調調用 Parser 的 parse
7.使用 acorn 分析源碼成 ast ,給 module.dependencies 添加依賴關系
8.根據(jù)依賴關系在 afterBuild 中調用 processModuleDependencies 遞歸處理依賴文件
9.最后把所有處理好的 module 都放入 compilation 實例的 this.modules 中進入 seal 階段