webpack如何实现的懒加载

2024-8-11 1,004 8/11

从打包之后的代码,看一下webpack如何实现的懒加载

懒加载的本质,代码分离,按需加载

这里使用的是最常用的import

先看一下懒加载效果

首次进入
webpack如何实现的懒加载

点击div元素后加载module

webpack如何实现的懒加载

webpack如何实现的懒加载

test代码

export default ()=>{
    console.log('%c +>>><<<<+','color:blue')
    console.log('懒加载测试')
}
const com = require('./com')
console.log('模块导出测试')
emodule.export =  {
    name:'ljt'
}
const click =async ()=>{
  const mod =  await import('./com')
  console.dir(mod)
}

const div = document.querySelector('#root')
document.addEventListener('click',click,div)
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>test</title>
  </head>
  <body>
    <div id="root">
      点击
    </div>
    <script src="./dist/main.js"></script>
  </body>
</html>

 

打包之后的代码

main

/******/ (() => {
  /******/ var __webpack_modules__ = {};
  /******/ var __webpack_module_cache__ = {};
  /******/ function __webpack_require__(moduleId) {
    /******/ var cachedModule = __webpack_module_cache__[moduleId];
    /******/ if (cachedModule !== undefined) {
      /******/ return cachedModule.exports;
    }
    /******/ var module = (__webpack_module_cache__[moduleId] = {
      /******/ exports: {},
    });
    /******/ __webpack_modules__[moduleId](
      module,
      module.exports,
      __webpack_require__
    );
    /******/ return module.exports;
  }
  /******/ __webpack_require__.m = __webpack_modules__;
  /******/ (() => {
    /******/ __webpack_require__.d = (exports, definition) => {
      /******/ for (var key in definition) {
        /******/ if (
          __webpack_require__.o(definition, key) &&
          !__webpack_require__.o(exports, key)
        ) {
          /******/ Object.defineProperty(exports, key, {
          enumerable: true,
          get: definition[key],
        });
        }
      }
    };
  })();
  /******/ (() => {
    /******/ __webpack_require__.f = {};
    /******/ __webpack_require__.e = (chunkId) => {
      /******/ return Promise.all(
    Object.keys(__webpack_require__.f).reduce((promises, key) => {
          /******/ __webpack_require__.f[key](chunkId, promises);
          /******/ return promises;
    }, [])
  );
    };
  })();
  /******/ (() => {
    /******/ __webpack_require__.u = (chunkId) => {
      /******/ return "" + chunkId + ".main.js";
    };
  })();
  /******/ (() => {
    /******/ __webpack_require__.g = (function () {
      /******/ if (typeof globalThis === "object") return globalThis;
      /******/ try {
        /******/ return this || new Function("return this")();
      } catch (e) {
        /******/ if (typeof window === "object") return window;
      }
    })();
  })();
  /******/ (() => {
    /******/ __webpack_require__.o = (obj, prop) =>
      Object.prototype.hasOwnProperty.call(obj, prop);
    /******/
  })();
  /******/ (() => {
    /******/ var inProgress = {};
    /******/ var dataWebpackPrefix = "test:";
    /******/ __webpack_require__.l = (url, done, key, chunkId) => {
      /******/ if (inProgress[url]) {
        inProgress[url].push(done);
        return;
      }
      /******/ var script, needAttach;
      /******/ if (key !== undefined) {
        /******/ var scripts = document.getElementsByTagName("script");
        /******/ for (var i = 0; i < scripts.length; i++) {
          /******/ var s = scripts[i];
          /******/ if (
            s.getAttribute("src") == url ||
            s.getAttribute("data-webpack") == dataWebpackPrefix + key
          ) {
            script = s;
            break;
          }
        }
      }
      /******/ if (!script) {
        /******/ needAttach = true;
        /******/ script = document.createElement("script");
        /******/ script.charset = "utf-8";
        /******/ script.timeout = 120;
        /******/ if (__webpack_require__.nc) {
          /******/ script.setAttribute("nonce", __webpack_require__.nc);
          /******/
        }
        /******/ script.setAttribute("data-webpack", dataWebpackPrefix + key);
        /******/ script.src = url;
      }
      /******/ inProgress[url] = [done];
      /******/ var onScriptComplete = (prev, event) => {
        /******/ script.onerror = script.onload = null;
        /******/ clearTimeout(timeout);
        /******/ var doneFns = inProgress[url];
        /******/ delete inProgress[url];
        /******/ script.parentNode && script.parentNode.removeChild(script);
        /******/ doneFns && doneFns.forEach((fn) => fn(event));
        /******/ if (prev) return prev(event);
        /******/
      };
      /******/ var timeout = setTimeout(
        onScriptComplete.bind(null, undefined, {
          type: "timeout",
          target: script,
        }),
        120000
      );
      /******/ script.onerror = onScriptComplete.bind(null, script.onerror);
      /******/ script.onload = onScriptComplete.bind(null, script.onload);
      /******/ needAttach && document.head.appendChild(script);
    };
  })();
  /******/ (() => {
    /******/ __webpack_require__.r = (exports) => {
      /******/ if (typeof Symbol !== "undefined" && Symbol.toStringTag) {
        /******/ Object.defineProperty(exports, Symbol.toStringTag, {
    value: "Module",
  });
      }
      /******/ Object.defineProperty(exports, "__esModule", { value: true });
    };
  })();
  /******/ (() => {
    /******/ var scriptUrl;
    /******/ if (__webpack_require__.g.importScripts)
      scriptUrl = __webpack_require__.g.location + "";
    /******/ var document = __webpack_require__.g.document;
    /******/ if (!scriptUrl && document) {
      /******/ if (document.currentScript)
        /******/ scriptUrl = document.currentScript.src;
      /******/ if (!scriptUrl) {
        /******/ var scripts = document.getElementsByTagName("script");
        /******/ if (scripts.length) {
          /******/ var i = scripts.length - 1;
          /******/ while (
            i > -1 &&
            (!scriptUrl || !/^http(s?):/.test(scriptUrl))
          )
            scriptUrl = scripts[i--].src;
        }
      }
    }
    /******/ if (!scriptUrl)
      throw new Error("Automatic publicPath is not supported in this browser");
    /******/ scriptUrl = scriptUrl
      .replace(/#.*$/, "")
      .replace(/\?.*$/, "")
      .replace(/\/[^\/]+$/, "/");
    /******/ __webpack_require__.p = scriptUrl;
    /******/
  })();
  /******/ (() => {
    /******/ var installedChunks = {
      /******/ main: 0,
    };
    /******/ __webpack_require__.f.j = (chunkId, promises) => {
      /******/ var installedChunkData = __webpack_require__.o(
      installedChunks,
      chunkId
    )
        ? installedChunks[chunkId]
        : undefined;
      /******/ if (installedChunkData !== 0) {
        /******/ if (installedChunkData) {
          /******/ promises.push(installedChunkData[2]);
        } else {
          /******/ if (true) {
            /******/ var promise = new Promise(
          (resolve, reject) =>
          (installedChunkData = installedChunks[chunkId] =
            [resolve, reject])
        );
            /******/ promises.push((installedChunkData[2] = promise));
            /******/ var url =
              __webpack_require__.p + __webpack_require__.u(chunkId);
            /******/ var error = new Error();
            /******/ var loadingEnded = (event) => {
              /******/ if (__webpack_require__.o(installedChunks, chunkId)) {
                /******/ installedChunkData = installedChunks[chunkId];
                /******/ if (installedChunkData !== 0)
                  installedChunks[chunkId] = undefined;
                /******/ if (installedChunkData) {
                  /******/ var errorType =
                    event && (event.type === "load" ? "missing" : event.type);
                  /******/ var realSrc =
                    event && event.target && event.target.src;
                  /******/ error.message =
                    "Loading chunk " +
                    chunkId +
                    " failed.\n(" +
                    errorType +
                    ": " +
                    realSrc +
                    ")";
                  /******/ error.name = "ChunkLoadError";
                  /******/ error.type = errorType;
                  /******/ error.request = realSrc;
                  /******/ installedChunkData[1](error);
                }
              }
            };
            /******/ __webpack_require__.l(
              url,
              loadingEnded,
              "chunk-" + chunkId,
              chunkId
            );
          }
        }
      }
    };
    /******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
      /******/ var [chunkIds, moreModules, runtime] = data;
      /******/ var moduleId,
        chunkId,
        i = 0;
      /******/ if (chunkIds.some((id) => installedChunks[id] !== 0)) {
        /******/ for (moduleId in moreModules) {
          /******/ if (__webpack_require__.o(moreModules, moduleId)) {
            /******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
          }
        }
        /******/ if (runtime) var result = runtime(__webpack_require__);
      }
      /******/ if (parentChunkLoadingFunction) parentChunkLoadingFunction(data);
      /******/ for (; i < chunkIds.length; i++) {
        /******/ chunkId = chunkIds[i];
        /******/ if (
          __webpack_require__.o(installedChunks, chunkId) &&
          installedChunks[chunkId]
        ) {
          /******/ installedChunks[chunkId][0]();
        }
        /******/ installedChunks[chunkId] = 0;
      }
    };
    /******/ var chunkLoadingGlobal = (self["webpackChunktest"] =
      self["webpackChunktest"] || []);
    /******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
    /******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(
        null,
        chunkLoadingGlobal.push.bind(chunkLoadingGlobal)
      );
    /******/
  })();
  var __webpack_exports__ = {};
  const click = async () => {
    const mod = await __webpack_require__
      .e(/*! import() */ "src_com_js")
      .then(
        __webpack_require__.bind(
          __webpack_require__,
          /*! ./com */ "./src/com.js"
        )
      );
    console.dir(mod);
  };
  const div = document.querySelector("#root");
  document.addEventListener("click", click, div);
})();

test

"use strict";
(self["webpackChunktest"] = self["webpackChunktest"] || []).push([["src_com_js"],{

/***/ "./src/com.js":
/*!********************!*\
  !*** ./src/com.js ***!
  \********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (()=>{
    console.log('%c +>>><<<<+','color:blue')
    console.log('懒加载测试')
});

/***/ })

}]);

首先就是 en 是如何去加载异步模块的, 最开始 我也是认为是通过cdn,拿到js文件,然后通过script的onLoad事件去做的实现,但是并没有按照这种方式去实现

拿测试代码来说,首先就是我们点击后,触发了click,

首先会通过jsonp的方式去加载test文件

加载回来后,执行,然后加模块定义合并到modules中去,

最后在走的require。

 

看一下具体的代码

首先就是

__webpack_require__
.e(/*! import() */ "src_com_js")方法,这一步主要做了什么,主要是根据chunid去加载test文件,当然,这里其实使用了变量

installedChunks

去记录了我们哪一些模块是已经加载了的和loading中的,0 代表着已经加载完成了的

加载回来之后,需要执行此js,并合并到modules中去,这一步做的很巧妙

  /******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
      /******/ var [chunkIds, moreModules, runtime] = data;
      /******/ // add "moreModules" to the modules object,
      /******/ // then flag all "chunkIds" as loaded and fire callback
      /******/ var moduleId,
        chunkId,
        i = 0;
      /******/ if (chunkIds.some((id) => installedChunks[id] !== 0)) {
        /******/ for (moduleId in moreModules) {
          /******/ if (__webpack_require__.o(moreModules, moduleId)) {
            /******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
            /******/
          }
          /******/
        }
        /******/ if (runtime) var result = runtime(__webpack_require__);
        /******/
      }
      /******/ if (parentChunkLoadingFunction) parentChunkLoadingFunction(data);
      /******/ for (; i < chunkIds.length; i++) {
        /******/ chunkId = chunkIds[i];
        /******/ if (
          __webpack_require__.o(installedChunks, chunkId) &&
          installedChunks[chunkId]
        ) {
          /******/ installedChunks[chunkId][0]();
          /******/
        }
        /******/ installedChunks[chunkId] = 0;
        /******/
      }
      /******/
      /******/
    };
    /******/
    /******/ var chunkLoadingGlobal = (self["webpackChunktest"] =
      self["webpackChunktest"] || []);
    /******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
    /******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(
        null,
        chunkLoadingGlobal.push.bind(chunkLoadingGlobal)
      );
    /******/

这里绑定了push方法,在结合test文件看一下

"use strict";
(self["webpackChunktest"] = self["webpackChunktest"] || []).push([["src_com_js"],{

/***/ "./src/com.js":
/*!********************!*\
  !*** ./src/com.js ***!
  \********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (()=>{
    console.log('%c +>>><<<<+','color:blue')
    console.log('懒加载测试')
});

/***/ })

}]);

这里的self就是window

合并完之后,去加载这个模块

const mod = await __webpack_require__
  .e(/*! import() */ "src_com_js")
  .then(
    __webpack_require__.bind(
      __webpack_require__,
      /*! ./com */ "./src/com.js"
    )
  );

还是通过require去做的加载,但是require里也没有用到this,所以我想__webpack_require__.bind只是为了快速生成then的回调函数

 

- THE END -
0

非特殊说明,本博所有文章均为博主原创。

共有 0 条评论