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··

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容

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