webpack打包后的文件如何异步加载模块

一起探索最真实的世界

上一篇我们探讨了 webpack打包后的文件如何在浏览器中运行 涉及到了同步模块的加载
本次我们对main.js进行修改

main.js

// 异步加载 show.js
import('./show').then((show) => {
  // 执行 show 函数
  show('Webpack');
});

webpack

打包后的文件

| -- dist
| ---- bundle.js
| ---- 0.bundle.js

这边如果还是使用之前的webpack配置,会出现一个问题,加载0.bundle.js时会出现加载失败的问题,我们可以看下我们之前配置
webpack.config.js

const path = require('path');

module.exports = {
  // JS 执行入口文件
  entry: './main.js',
  output: {
    // 把所有依赖的模块合并输出到一个 bundle.js 文件
    filename: 'bundle.js',
    // 输出文件都放到 dist 目录下
    path: path.resolve(__dirname, './dist'),
  }
};

我们把所有的模块都输出到当前目录的dist路径下,在bundle文件中有一行代码是

script.src = __webpack_require__.p + "" + chunkId + ".bundle.js";
// **
// __webpack_public_path__
__webpack_require__.p = "";

我们可以看到我们去加载0.bundle.js时是直接加载index.html文件的同级目录下的0.bundle.js,这肯定会加载失败,那我们怎么去改变这个webpack_require_.p呢,从注释我们可以看到这个定义的是publicPath,webpack配置中就有publicPath

const path = require('path');

module.exports = {
  // JS 执行入口文件
  entry: './main.js',
  output: {
    // 把所有依赖的模块合并输出到一个 bundle.js 文件
    filename: 'bundle.js',
   // 配置publicPath
    publicPath: './dist/',
    // 输出文件都放到 dist 目录下
    path: path.resolve(__dirname, './dist'),
  }
};

此时重新

webpack

bundle.js

    (function (modules) { // webpackBootstrap
      // install a JSONP callback for chunk loading
      var parentJsonpFunction = window["webpackJsonp"];
      window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
        // 把moreModules加入到modules中,
        // then flag all "chunkIds" as loaded and fire callback
        var moduleId, chunkId, i = 0,
          resolves = [],
          result;
        for (; i < chunkIds.length; i++) {
          chunkId = chunkIds[i];
          if (installedChunks[chunkId]) {
            resolves.push(installedChunks[chunkId][0]);
          }
          installedChunks[chunkId] = 0;
        }
        for (moduleId in moreModules) {
          if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
            modules[moduleId] = moreModules[moduleId];
          }
        }
        if (parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);
        while (resolves.length) {
          resolves.shift()();
        }
    
      };
    
      // The module cache
      var installedModules = {};
    
      // objects to store loaded and loading chunks
      var installedChunks = {
        1: 0
      };
    
      // The require function
      function __webpack_require__(moduleId) {
    
        // Check if module is in cache
        if (installedModules[moduleId]) {
          return installedModules[moduleId].exports;
        }
        // Create a new module (and put it into the cache)
        var module = installedModules[moduleId] = {
          i: moduleId,
          l: false,
          exports: {}
        };
    
        // Execute the module function
        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    
        // Flag the module as loaded
        module.l = true;
    
        // Return the exports of the module
        return module.exports;
      }
    
      // This file contains only the entry chunk.
      // The chunk loading function for additional chunks
      __webpack_require__.e = function requireEnsure(chunkId) {
        var installedChunkData = installedChunks[chunkId];
        // 如果installedChunkData 为0 那代表这个模块已经被加载直接返回Promise,并resolve
        if (installedChunkData === 0) {
          return new Promise(function (resolve) {
            resolve();
          });
        }
    
        // 如果installedChunkData非空且非0,那代表现在正在请求中,返回请求的promise
        if (installedChunkData) {
          return installedChunkData[2];
        }
    
        // setup Promise in chunk cache
        var promise = new Promise(function (resolve, reject) {
          installedChunkData = installedChunks[chunkId] = [resolve, reject];
        });
        installedChunkData[2] = promise;
    
        // start chunk loading
        var head = document.getElementsByTagName('head')[0];
        var script = document.createElement('script');
        script.type = "text/javascript";
        script.charset = 'utf-8';
        script.async = true;
        script.timeout = 120000;
    
        if (__webpack_require__.nc) {
          script.setAttribute("nonce", __webpack_require__.nc);
        }
        script.src = __webpack_require__.p + "" + chunkId + ".bundle.js";
        var timeout = setTimeout(onScriptComplete, 120000);
        script.onerror = script.onload = onScriptComplete;
    
        function onScriptComplete() {
          // avoid mem leaks in IE.
          script.onerror = script.onload = null;
          clearTimeout(timeout);
          var chunk = installedChunks[chunkId];
          if (chunk !== 0) {
            if (chunk) {
              chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));
            }
            installedChunks[chunkId] = undefined;
          }
        };
        head.appendChild(script);
    
        return promise;
      };
    
      // __webpack_public_path__
      __webpack_require__.p = "./dist/";
    
      // Load entry module and return exports
      return __webpack_require__(__webpack_require__.s = 0);
    })
    /************************************************************************/
    ([
      /* 0 */
      /***/
      (function (module, exports, __webpack_require__) {
    
        // 异步加载 show.js
        __webpack_require__.e /* import() */ (0).then(__webpack_require__.bind(null, 1)).then((show) => {
          // 执行 show 函数
          show('Webpack');
        });
      })
    ]);

可以看到,webpack异步加载模块是通过jsonp的方式,我们看到入口模块函数中,先去调用 webpack_require.e(0) 加载模块0.bundle.js
0.bundle.js

webpackJsonp([0],[
/* 0 */,
/* 1 */
/***/ (function(module, exports) {
function show(content) {
  window.document.getElementById('app').innerText = 'Hello,' + content;
}
// 通过 CommonJS 规范导出 show 函数
module.exports = show;
/***/ })
]);

一旦通过动态创建的script加载0.bundle.js后,就会执行webapckJsonp··

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 版权声明:本文为博主原创文章,未经博主允许不得转载。 webpack介绍和使用 一、webpack介绍 1、由来 ...
    it筱竹阅读 13,850评论 0 21
  • GitChat技术杂谈 前言 本文较长,为了节省你的阅读时间,在文前列写作思路如下: 什么是 webpack,它要...
    萧玄辞阅读 14,336评论 7 110
  • 无意中看到zhangwnag大佬分享的webpack教程感觉受益匪浅,特此分享以备自己日后查看,也希望更多的人看到...
    小小字符阅读 12,548评论 7 35
  • 这样的生活状态让我越来越不喜欢北方的冬天,每一次的忍让只会让人得寸进尺,人的自私真是不可估量。
    小小越前阅读 962评论 0 0
  • 天冷啦,简单的晚餐
    左家半亩闲田阅读 1,053评论 0 0