解析webpackv5.68.0编译后的main文件

webpack根据entry入口文件,生成一个main.js的主文件,此文件运用闭包立即调用的机制

main文件的四块逻辑

  1. 初始化全局的module内容,仅包含同步文件的代码
  2. 模块的缓存以及加载模块函数
  3. webpack各种运行时的函数方法
  4. 加载入口文件代码

关于更多的weboack运行时函数,可看webpack/lib/RuntimeGlobals.js文件

  1. // 闭包形式
  2. (() => {
  3. // 第一个逻辑: 初始化全局的module内容,仅包含同步文件的代码
  4. var webpack = ({
  5. 'xxx.js': ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
  6. // 文件内容...
  7. }),
  8. // ....等
  9. });
  10. /************************************************************************/
  11. // 第二个逻辑: 模块的加载存储对象和存储函数
  12. var __webpack_module_cache__ = {};
  13. // 获取模块对象的函数
  14. function __webpack_require__(moduleId) {};
  15. __webpack_require__.m = __webpack_modules__;
  16. /************************************************************************/
  17. // 第三个逻辑: webpack各种运行时的函数方法,全都已闭包自执行的方式运行
  18. /* webpack/runtime/define property getters */
  19. (() => {
  20. __webpack_require__.d = (exports, definition) => {}
  21. })();
  22. (() => {
  23. __webpack_require__.r = (exports) => {}
  24. })();
  25. // ...等运行时函数
  26. /************************************************************************/
  27. // 第四个逻辑: 加载入口文件代码
  28. var __webpack_exports__ = {};
  29. (() => {
  30. __webpack_require__.r(__webpack_exports__);
  31. __webpack_require__.r(__webpack_exports__);
  32. __webpack_require__.d(__webpack_exports__, {
  33. "testField": () => (/* binding */ 'testField')}
  34. );
  35. __webpack_require__(/*! ./remote */ "xxx.js");
  36. })();
  37. })();

script load function

  1. // js 文件的加载方法
  2. // __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);
  3. // url: js路径
  4. // loadingEnded: js 文件加载失败时的回调方法
  5. // "chunk-" + chunkId: js + chunk合并的js路径名称
  6. // chunkId: 编译后的文件对应的chunkId名称
  7. /* webpack/runtime/load script */
  8. (() => {
  9. var inProgress = {};
  10. var dataWebpackPrefix = "webpack-app:";
  11. __webpack_require__.l = (url, done, key, chunkId) => {
  12. // 如果正在加载js文件,就等待
  13. if(inProgress[url]) { inProgress[url].push(done); return; }
  14. var script, needAttach;
  15. if(key !== undefined) {
  16. // 遍历查找,查看js文件是否已经加载完成
  17. var scripts = document.getElementsByTagName("script");
  18. for(var i = 0; i < scripts.length; i++) {
  19. var s = scripts[i];
  20. if(s.getAttribute("src") == url || s.getAttribute("data-webpack") == dataWebpackPrefix + key) { script = s; break; }
  21. }
  22. }
  23. // 资源未加载的情况下,创建资源加载
  24. if(!script) {
  25. needAttach = true;
  26. script = document.createElement('script');
  27. script.charset = 'utf-8';
  28. script.timeout = 120;
  29. if (__webpack_require__.nc) {
  30. script.setAttribute("nonce", __webpack_require__.nc);
  31. }
  32. script.setAttribute("data-webpack", dataWebpackPrefix + key);
  33. script.src = url;
  34. }
  35. inProgress[url] = [done];
  36. // script资源完成的情况
  37. var onScriptComplete = (prev, event) => {
  38. script.onerror = script.onload = null;
  39. clearTimeout(timeout);
  40. var doneFns = inProgress[url];
  41. delete inProgress[url];
  42. script.parentNode && script.parentNode.removeChild(script);
  43. doneFns && doneFns.forEach((fn) => (fn(event)));
  44. if(prev) return prev(event);
  45. }
  46. // script资源加载超时
  47. var timeout = setTimeout(
  48. onScriptComplete.bind(
  49. null,
  50. undefined,
  51. { type: 'timeout', target: script }),
  52. 120000
  53. );
  54. // script资源的事件监听
  55. script.onerror = onScriptComplete.bind(null, script.onerror);
  56. script.onload = onScriptComplete.bind(null, script.onload);
  57. needAttach && document.head.appendChild(script);
  58. };
  59. })();