一起探索最真實(shí)的世界
上一篇我們探討了 webpack打包后的文件如何在瀏覽器中運(yùn)行 涉及到了同步模塊的加載
本次我們對(duì)main.js進(jìn)行修改
main.js
// 異步加載 show.js
import('./show').then((show) => {
// 執(zhí)行 show 函數(shù)
show('Webpack');
});
webpack
打包后的文件
| -- dist
| ---- bundle.js
| ---- 0.bundle.js
這邊如果還是使用之前的webpack配置,會(huì)出現(xiàn)一個(gè)問(wèn)題,加載0.bundle.js時(shí)會(huì)出現(xiàn)加載失敗的問(wèn)題,我們可以看下我們之前配置
webpack.config.js
const path = require('path');
module.exports = {
// JS 執(zhí)行入口文件
entry: './main.js',
output: {
// 把所有依賴(lài)的模塊合并輸出到一個(gè) bundle.js 文件
filename: 'bundle.js',
// 輸出文件都放到 dist 目錄下
path: path.resolve(__dirname, './dist'),
}
};
我們把所有的模塊都輸出到當(dāng)前目錄的dist路徑下,在bundle文件中有一行代碼是
script.src = __webpack_require__.p + "" + chunkId + ".bundle.js";
// **
// __webpack_public_path__
__webpack_require__.p = "";
我們可以看到我們?nèi)ゼ虞d0.bundle.js時(shí)是直接加載index.html文件的同級(jí)目錄下的0.bundle.js,這肯定會(huì)加載失敗,那我們?cè)趺慈ジ淖冞@個(gè)webpack_require_.p呢,從注釋我們可以看到這個(gè)定義的是publicPath,webpack配置中就有publicPath
const path = require('path');
module.exports = {
// JS 執(zhí)行入口文件
entry: './main.js',
output: {
// 把所有依賴(lài)的模塊合并輸出到一個(gè) bundle.js 文件
filename: 'bundle.js',
// 配置publicPath
publicPath: './dist/',
// 輸出文件都放到 dist 目錄下
path: path.resolve(__dirname, './dist'),
}
};
此時(shí)重新
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 那代表這個(gè)模塊已經(jīng)被加載直接返回Promise,并resolve
if (installedChunkData === 0) {
return new Promise(function (resolve) {
resolve();
});
}
// 如果installedChunkData非空且非0,那代表現(xiàn)在正在請(qǐng)求中,返回請(qǐng)求的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) => {
// 執(zhí)行 show 函數(shù)
show('Webpack');
});
})
]);
可以看到,webpack異步加載模塊是通過(guò)jsonp的方式,我們看到入口模塊函數(shù)中,先去調(diào)用 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;
}
// 通過(guò) CommonJS 規(guī)范導(dǎo)出 show 函數(shù)
module.exports = show;
/***/ })
]);
一旦通過(guò)動(dòng)態(tài)創(chuàng)建的script加載0.bundle.js后,就會(huì)執(zhí)行webapckJsonp··