首先要知道webpack-dev-server和webpack-dev-middleware這兩個依賴庫的主要區別。
webpack-dev-server主要負責項目的服務啟動和一些前置工作(比如生成webpack編譯主引擎(compile實例))。
webpack-dev-middleware主要提供的是本地文件操作方面相關的服務,比如文件的編譯,輸出(setFs())和監聽(compile.watch());
當執行npm start的時候:
- webpack-dev-server就開始生成編譯引擎(也就是compiler實例)
- 生成完實例以后,緊接着啟動Server服務,而且可以看到,Server.js主要使用的是express框架
- 啟動了本地服務以后,又緊接着啟動了websocket服務
- Server.js還做了一件事情,就是修改了webpack.config.js的entry配置,主要實現的步驟是:
- 調用了updateCompiler方法,updateCompiler中又調用了addEntries方法,addEntries方法中有 2 段很關鍵的代碼

- addEntries方法執行以后,會改變entry入口的配置
-
{ entry: { index: [ '../node_modules/webpack-dev-server/client/index.js', '../node_modules/webpack/hot/dev-server.js', './src/index.js' ], }, } - 新增websocket文件的原因,是因為上面的webpack-dev-server啟動的websocket服務目前服務端(webpack項目)代碼已經有了,但是瀏覽器的代碼還沒有,總不能webpack通知瀏覽器要更新代碼了,但是瀏覽器怎么接收消息並觸發更新事件呢?所以肯定要把這部分代碼給到瀏覽器。而第二個文件主要是用於檢查更新邏輯的
- 調用了updateCompiler方法,updateCompiler中又調用了addEntries方法,addEntries方法中有 2 段很關鍵的代碼
- Server.js調用了updateCompiler方法實現了入口文件配置的修改以后,又緊接着做了一件事,就是調用了setupHooks方法,這個方法主要是用來監聽每次
webpack編譯完成的。 - 上面主要就是Server.js做的事情,下面看看文件的監聽是怎么做的
- 文件的監聽主要是在webpack-dev-middleware中做的

- 監聽文件的變化主要是通過文件的生成時間是否有變動來實現的。
- 現在,文件的監聽以及websocket通知已經做好了,下面看看瀏覽器收到通知以后具體做了哪些事情
- 剛才Server.js調用updateCompiler方法把websocket的客戶端代碼配置到了entry入口中,所以現在看看那段代碼做了什么
- 剛才Server.js調用updateCompiler方法把websocket的客戶端代碼配置到了entry入口中,所以現在看看那段代碼做了什么
- 現在,Server.js通過updateCompiler方法添加到entry中的第一個文件作用已經說清楚了,添加的第二個文件,也就是webpack/hot/dev-server的作用還沒說

- 補充一點,
check方法是是HotModuleReplacementPlugin插件搞的,把代碼注入到了bundle.js中 - check方法的源碼在webpack/lib/HotModuleReplacement.runtime.js(簡稱HMR runtime)中
- check方法中會利用 到webpack/lib/web/JsonpMainTemplate.runtime(簡稱Jsonp runtime)中的兩個方法hotDownloadManifest和hotDownloadUpdateChunk

- hotDownloadManifest的主要作用是發送{hash}.hot-update.json的ajax請求,獲取更新清單以及獲取下次熱更新的Hash 標識
- hotDownloadUpdateChunk主要作用是通過得到上面的更新清單去發送{hash}.hot-update.js 請求下載相應的更新塊,而且是通過JSONP的方式
- 通過上面一系列的文件監聽、socket通信、瀏覽器收到通信並請求到新文件這些操作以后,就看是如何進行熱更新的。打開hot-update.js文件以后,會發現一個webpackHotUpdate的方法。

- 源碼中這個方法有一個callback,會執行hotAddUpdateChunk方法,
- hotAddUpdateChunk接收兩個參數,一個是chunkId(對應hot-update.js響應體中的webpackHotUpdate函數中的“main”),一個是moreModules(對應hot-update.js響應體中的webpackHotUpdate函數中的那個對象);拿到需要更新的模塊以后,hotAddUpdateChunk會用for in的形式遍歷模塊對象,並且賦值給全局全量hotUpdate。然后執行hotUpdateDownloaded方法
- 來看下hotUpdateDownloaded做了什么事,當執行hotUpdateDownloaded的時候,也就意味着熱更新的前期工作已經全部做完了(webpack監聽變更文件、Browser請求變更文件、處理變更文件)。所以hotUpdateDownloaded會把runtime狀態置為“ready”,然后執行hotApply准備開始應用。
- 上面的所有的操作全部處於准備階段,接下的hotApply才是正式應用module到頁面中
- hotApply主要調用了hotApplyInternal這個方法。應用新模塊主要分為了三個階段
- 第一階段,找出所有過期的依賴和模塊
- 第二階段,刪除緩存中的依賴要替換的模塊,
- 將runtime的狀態置為“apply”並將新的模塊添加到modules中
- 到此,所有的新模塊已經全部在module中了,代碼下次調用__webpack_require__的時候,就是最新模塊













