webpack hmr 流程总结

338 阅读1分钟

webpack hmr 流程总结

  • webpack-dev-middleware:
    • 主要读取静态资源文件返回给浏览器
  • webpack-hot-middleware:
    • 主要处理匹配/webpack_hmr路由之后返回Content-type为 text/event-stream;charset=utf-8的响应
  • webpack-hot-middleware/client.js:new EventSource('/webpack_hmr')监听服务器主动推送的消息,如打包完成之后hash值,改变的模块等交由./process-update.js处理
  • webpack-hot-middleware/process-update.js:执行module.hot.check(),等同于调用HotModuleReplacement.runtime 的hotCheck();接着调用hotDownloadManifest获取json文件上一次的hash.hot-update.json,返回的内容为
{"h":"fb3e9ba6fcd4f92f416c","c":{"app":true}}
// bundle.js 中定义了一些函数
function hotDownloadManifest(requestTimeout) {
    /******/
    requestTimeout = requestTimeout || 10000;
    /******/
    return new Promise(function (resolve, reject) {
      /******/
      if (typeof XMLHttpRequest === "undefined") {
        /******/
        return reject(new Error("No browser support"));
        /******/
      }
      /******/
      try {
        /******/
        var request = new XMLHttpRequest();
        /******/
        var requestPath = __webpack_require__.p + "" + hotCurrentHash + ".hot-update.json";
        /******/
        request.open("GET", requestPath, true);
        /******/
        request.timeout = requestTimeout;
        /******/
        request.send(null);
        /******/
      } catch (err) {
        /******/
        return reject(err);
        /******/
      }
      /******/
      request.onreadystatechange = function () {
        /******/
        if (request.readyState !== 4)
          return;
        /******/
        if (request.status === 0) {
          /******/
          // timeout
          /******/
          reject(/******/
            new Error("Manifest request to " + requestPath + " timed out.")/******/
          );
          /******/
        } else if (request.status === 404) {
          /******/
          // no update available
          /******/
          resolve();
          /******/
        } else if (request.status !== 200 && request.status !== 304) {
          /******/
          // other failure
          /******/
          reject(new Error("Manifest request to " + requestPath + " failed."));
          /******/
        } else {
          /******/
          // success
          /******/
          try {
            /******/
            var update = JSON.parse(request.responseText);
            /******/
          } catch (e) {
            /******/
            reject(e);
            /******/
            return;
            /******/
          }
          /******/
          resolve(update);
          /******/
        }
        /******/
      }
        ;
      /******/
    }
    );
    /******/
  }
  
  

接着调用hotEnsureUpdateChunk()->hotDownloadUpdateChunk() 请求上一次的hash.hot-update.js返回一个jsonp立即执行函数

// bundler.js

function hotEnsureUpdateChunk(chunkId) {
    /******/
    if (!hotAvailableFilesMap[chunkId]) {
      /******/
      hotWaitingFilesMap[chunkId] = true;
      /******/
    } else {
      /******/
      hotRequestedFilesMap[chunkId] = true;
      /******/
      hotWaitingFiles++;
      /******/
      hotDownloadUpdateChunk(chunkId);
      /******/
    }
    /******/
  }
  
 function hotDownloadUpdateChunk(chunkId) {
    /******/
    var script = document.createElement("script");
    /******/
    script.charset = "utf-8";
    /******/
    script.src = __webpack_require__.p + "" + chunkId + "." + hotCurrentHash + ".hot-update.js";
    /******/
    if (null)
      script.crossOrigin = null;
    /******/
    document.head.appendChild(script);
    /******/
  }
// app.e75837e14d1a14baef6f.hot-update.js

webpackHotUpdate("app", {

    /***/
    "./node_modules/_vue-loader@14.2.4@vue-loader/lib/template-compiler/index.js?{\"id\":\"data-v-4a0103ec\",\"hasScoped\":true,\"optionsId\":\"0\",\"buble\":{\"transforms\":{}}}!./node_modules/_vue-loader@14.2.4@vue-loader/lib/selector.js?type=template&index=0!./example/pages/button.vue": /*!****************************************************************************************************************************************************************************************************************************************************************************!*\
  !*** ./node_modules/_vue-loader@14.2.4@vue-loader/lib/template-compiler?{"id":"data-v-4a0103ec","hasScoped":true,"optionsId":"0","buble":{"transforms":{}}}!./node_modules/_vue-loader@14.2.4@vue-loader/lib/selector.js?type=template&index=0!./example/pages/button.vue ***!
  \****************************************************************************************************************************************************************************************************************************************************************************/
    /*! exports provided: render, staticRenderFns */
    /***/
    (function(module, __webpack_exports__, __webpack_require__) {

        "use strict";
        __webpack_require__.r(__webpack_exports__);
        /* harmony export (binding) */
        __webpack_require__.d(__webpack_exports__, "render", function() {
            return render;
        });
        /* harmony export (binding) */
        __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() {
            return staticRenderFns;
        });
        var render = function() {
            var _vm = this
            var _h = _vm.$createElement
            var _c = _vm._self._c || _h
            return _c("div", [_vm._v("3")])
        }
        var staticRenderFns = []
        render._withStripped = true

        if (true) {
            module.hot.accept()
            if (module.hot.data) {
                __webpack_require__(/*! vue-loader/node_modules/vue-hot-reload-api */
                "./node_modules/_vue-hot-reload-api@2.3.4@vue-hot-reload-api/dist/index.js").rerender("data-v-4a0103ec", {
                    render: render,
                    staticRenderFns: staticRenderFns
                })
            }
        }

        /***/
    }
    )

})


// bundle.js
 var parentHotUpdateCallback = window["webpackHotUpdate"];
  /******/
  window["webpackHotUpdate"] = // eslint-disable-next-line no-unused-vars
    /******/
    function webpackHotUpdateCallback(chunkId, moreModules) {
      /******/
      hotAddUpdateChunk(chunkId, moreModules);
      /******/
      if (parentHotUpdateCallback)
        parentHotUpdateCallback(chunkId, moreModules);
      /******/
    }