Part2-2-5 webpack 源码解析
Posted 沿着路走到底
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Part2-2-5 webpack 源码解析相关的知识,希望对你有一定的参考价值。
打包后源码分析
CommonJS模块打包
webpack.config.js
const path = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
devtool: 'none',
mode: 'development',
entry: './src/index.js',
output: {
filename: 'built.js',
path: path.resolve('dist')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
}
login.js
// 01 采用 commonjs
module.exports = '拉勾教育'
// 02 采用 esmodule 导出内容
export default 'zcegg'
export const age = 18
index.js
// commonjs
let name = require('./login.js')
console.log('index.js内容执行了')
console.log(name)
// commonjs 接收 es module 导出内容
let obj = require('./login.js')
console.log('index.js内容执行了')
console.log(obj.default, '---->', obj.age)
commonjs 规范导出内容,commonjs 规范接收导出内容
built.js
(function (modules) { // webpackBootstrap
// The module cache
// 定义对象用于缓存已加载过的模块
// 缓存当前已经被加载过的模块
// 如果将来需要导入某个模块,发现这个模块已经被缓存了,则不再需要导入,直接用缓存里的
var installedModules = {};
// The require function
// webpack 自定义的一个加载方法,核心功能就是返回被加载模块中导出的内容(具体内部是如何实现的,后续再分析)
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
// 递归执行依赖模块
// 执行完后,入口模块的导出内容会被添加进 module.exports
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;
}
// expose the modules object (__webpack_modules__)
// 将模块定义保存一份,通过 m 属性挂载到自定义的方法身上
__webpack_require__.m = modules;
// expose the module cache
// 挂载缓存
__webpack_require__.c = installedModules;
// Object.prototype.hasOwnProperty.call
// 判断被传入的对象 obj 身上是否具有指定的属性 **** ,如果有则返回 true
__webpack_require__.o = function (object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
// define getter function for harmony exports
__webpack_require__.d = function (exports, name, getter) {
// 如果当前 exports 身上不具备 name 属性,则条件成立
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter });
}
};
// define __esModule on exports
__webpack_require__.r = function (exports) {
// 下面的条件如果成立就说明是一个 esModule
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
// Object.prototype.toString.call(exports)
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
// 如果条件不成立,我们也直接在 exports 对象的身上添加一个 __esModule 属性,它的值就是true
Object.defineProperty(exports, '__esModule', { value: true });
};
// create a fake namespace object
// mode & 1: value is a module id, require it
// mode & 2: merge all properties of value into the ns
// mode & 4: return value when already ns object
// mode & 8|1: behave like require
__webpack_require__.t = function (value, mode) {
// 01 调用 t 方法之后,我们会拿到被加载模块中的内容 value
// 02 对于 value 来说我们可能会直接返回,也可能会处理之后再返回
if (mode & 1) value = __webpack_require__(value);
if (mode & 8) return value;
if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
var ns = Object.create(null);
__webpack_require__.r(ns);
Object.defineProperty(ns, 'default', { enumerable: true, value: value });
if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key, function (key) { return value[key]; }.bind(null, key));
return ns;
};
// getDefaultExport function for compatibility with non-harmony modules
__webpack_require__.n = function (module) {
var getter = module && module.__esModule ?
function getDefault() { return module['default']; } :
function getModuleExports() { return module; };
__webpack_require__.d(getter, 'a', getter);
return getter;
};
// __webpack_public_path__
// 提供公网访问路径
__webpack_require__.p = "";
// Load entry module and return exports
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
/************************************************************************/
({
"./src/index.js":
/*! no static exports found */
(function (module, exports, __webpack_require__) {
let name = __webpack_require__(/*! ./login.js */ "./src/login.js")
console.log('index.js内容执行了')
console.log(name)
}),
"./src/login.js":
/*! no static exports found */
(function (module, exports) {
module.exports = '拉勾教育'
})
});
/**
* 01 打包后的文件就是一个函数自调用,当前函数调用时传入一个对象
* 02 这个对象我们为了方便将之称为是模块定义,它就是一个键值对
* 03 这个键名就是当前被加载模块的文件名与某个目录的拼接()
* 04 这个键值就是一个函数,和 node.js 里的模块加载有一些类似,会将被加载模块中的内容包裹于一个函数中
* 05 这个函数在将来某个时间点上会被调用,同时会接收到一定的参数,利用这些参数就可以实现模块的加载操作
*
* 06 针对于上述的代码就相当于是将 {}(模块定义) 传递给了 modules
*/
esModule 规范导出内容,commonjs 规范接收导出内容
(function (modules) { // webpackBootstrap
// The module cache
var installedModules = {};
// 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;
}
// expose the modules object (__webpack_modules__)
__webpack_require__.m = modules;
// expose the module cache
__webpack_require__.c = installedModules;
// define getter function for harmony exports
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter });
}
};
// define __esModule on exports
__webpack_require__.r = function (exports) {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};
// create a fake namespace object
// mode & 1: value is a module id, require it
// mode & 2: merge all properties of value into the ns
// mode & 4: return value when already ns object
// mode & 8|1: behave like require
__webpack_require__.t = function (value, mode) {
if (mode & 1) value = __webpack_require__(value);
if (mode & 8) return value;
if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
var ns = Object.create(null);
__webpack_require__.r(ns);
Object.defineProperty(ns, 'default', { enumerable: true, value: value });
if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key, function (key) { return value[key]; }.bind(null, key));
return ns;
};
// getDefaultExport function for compatibility with non-harmony modules
__webpack_require__.n = function (module) {
var getter = module && module.__esModule ?
function getDefault() { return module['default']; } :
function getModuleExports() { return module; };
__webpack_require__.d(getter, 'a', getter);
return getter;
};
// Object.prototype.hasOwnProperty.call
__webpack_require__.o = function (object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
// __webpack_public_path__
__webpack_require__.p = "";
// Load entry module and return exports
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
/************************************************************************/
({
"./src/index.js":
(function (module, exports, __webpack_require__) {
let obj = __webpack_require__(/*! ./login.js */ "./src/login.js")
console.log('index.js内容执行了')
console.log(obj.default, '---->', obj.age)
}),
"./src/login.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, "age", function () { return age; });
__webpack_exports__["default"] = ('zcegg');
const age = 18
})
});
esModule模块打包
login.js ESModule 规范导出
// 01 采用 cms 导出模块内容
// module.exports = 'zce'
// 02 采用 esModule 导出模块
export default '拉勾教育'
export const age = 100
index.js 改成 ESModule 规范导入
import name, { age } from './login.js'
console.log('index.js内容加载了')
console.log(name, '---->', age)
built.js
(function (modules) { // webpackBootstrap
// The module cache
var installedModules = {};
// 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;
}
// expose the modules object (__webpack_modules__)
__webpack_require__.m = modules;
// expose the module cache
__webpack_require__.c = installedModules;
// define getter function for harmony exports
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter });
}
};
// define __esModule on exports
__webpack_require__.r = function (exports) {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};
// create a fake namespace object
// mode & 1: value is a module id, require it
// mode & 2: merge all properties of value into the ns
// mode & 4: return value when already ns object
// mode & 8|1: behave like require
__webpack_require__.t = function (value, mode) {
if (mode & 1) value = __webpack_require__(value);
if (mode & 8) return value;
if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
var ns = Object.create(null);
__webpack_require__.r(ns);
Object.defineProperty(ns, 'default', { enumerable: true, value: value });
if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key, function (key) { return value[key]; }.bind(null, key));
return ns;
};
// getDefaultExport function for compatibility with non-harmony modules
__webpack_require__.n = function (module) {
var getter = module && module.__esModule ?
function getDefault() { return module['default']; } :
function getModuleExports() { return module; };
__webpack_require__.d(getter, 'a', getter);
return getter;
};
// Object.prototype.hasOwnProperty.call
__webpack_require__.o = function (object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
// __webpack_public_path__
__webpack_require__.p = "";
// Load entry module and return exports
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
/************************************************************************/
({
"./src/index.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
var _login_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./login.js */ "./src/login.js");
console.log('index.js内容加载了')
console.log(_login_js__WEBPACK_IMPORTED_MODULE_0__["default"], '---->', _login_js__WEBPACK_IMPORTED_MODULE_0__["age"])
}),
"./src/login.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, "age", function () { return age; });
__webpack_exports__["default"] = ('拉勾教育');
const age = 100
})
});
懒加载
t方法
login.js
module.exports = "懒加载导出内容"
index.js
let oBtn = document.getElementById('btn')
oBtn.addEventListener('click', function () {
import(/*webpackChunkName: "login"*/'./login.js').then((login) => {
console.log(login)
})
})
console.log('index.js执行了')
built.js
(function (modules) { // webpackBootstrap
// install a JSONP callback for chunk loading
// webpackJsonpCallback 方法实现:1、合并模块定义 2、改变 promise 状态执行后续行为
function webpackJsonpCallback(data) {
// 获取需要被动态加载的模块 Id
var chunkIds = data[0];
// 获取需要被动态加载的模块依赖关系对象
var moreModules = data[1];
// add "moreModules" to the modules object,
// then flag all "chunkIds" as loaded and fire callback
// 循环判断 chunkIds 里对应的模块内容是否已经完成了加载
var moduleId, chunkId, i = 0, resolves = [];
for (; i < chunkIds.length; i++) {
chunkId = chunkIds[i];
if (Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
resolves.push(installedChunks[chunkId][0]);
}
// 更新当前的 chunk 状态
installedChunks[chunkId] = 0;
}
// 模块合并
for (moduleId in moreModules) {
if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
modules[moduleId] = moreModules[moduleId];
}
}
if (parentJsonpFunction) parentJsonpFunction(data);
while (resolves.length) {
resolves.shift()();
}
};
// The module cache
var installedModules = {};
// object to store loaded and loading chunks
// undefined = chunk not loaded, null = chunk preloaded/prefetched
// Promise = chunk loading, 0 = chunk loaded
// 定义 installedChunks 用于标识某个 ChunkId 对应的 chunk 是否完成了加载
var installedChunks = {
"main": 0 // 0 代表已经加载过了,Promise 代表正在加载,undefined、null 代表还没有加载
};
// script path function
// 定义 jsonpScriptSrc 实现 src 的处理
function jsonpScriptSrc(chunkId) {
return __webpack_require__.p + "" + chunkId + ".built.js"
}
// 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
// e 方法用于实现 1、实现 jsonp 来加载内容 2、利用 promise 来实现异步加载操作
__webpack_require__.e = function requireEnsure(chunkId) {
// 定义一个数组用于存放 promise
var promises = [];
// JSONP chunk loading for javascript
// 获取 chunkId 对应的 chunk 是否已经完成了加载
var installedChunkData = installedChunks[chunkId];
// 依据当前是否已完成加载的状态来执行后续的逻辑
if (installedChunkData !== 0) { // 0 means "already installed".
// 不为0 代表还没有加载完成
// a Promise means "currently loading".
if (installedChunkData) {
// installedChunkData 为真 说明是一个 promise,代表正在加载
promises.push(installedChunkData[2]);
} else {
// setup Promise in chunk cache
var promise = new Promise(function (resolve, reject) {
installedChunkData = installedChunks[chunkId] = [resolve, reject];
});
promises.push(installedChunkData[2] = promise);
// start chunk loading
// 创建 script 标签
var script = document.createElement('script');
var onScriptComplete;
script.charset = 'utf-8';
script.timeout = 120;
if (__webpack_require__.nc) {
script.setAttribute("nonce", __webpack_require__.nc);
}
script.src = jsonpScriptSrc(chunkId);
// create error before stack unwound to get useful stacktrace later
var error = new Error();
onScriptComplete = function (event) {
// avoid mem leaks in IE.
script.onerror = script.onload = null;
clearTimeout(timeout);
var chunk = installedChunks[chunkId];
if (chunk !== 0) {
if (chunk) {
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;
chunk[1](error);
}
installedChunks[chunkId] = undefined;
}
};
var timeout = setTimeout(function () {
onScriptComplete({ type: 'timeout', target: script });
}, 120000);
script.onerror = script.onload = onScriptComplete;
document.head.appendChild(script);
}
}
// 执行 promise
return Promise.all(promises);
};
// expose the modules object (__webpack_modules__)
__webpack_require__.m = modules;
// expose the module cache
__webpack_require__.c = installedModules;
// define getter function for harmony exports
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter });
}
};
// define __esModule on exports
__webpack_require__.r = function (exports) {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};
// create a fake namespace object
// mode & 1: value is a module id, require it
// mode & 2: merge all properties of value into the ns
// mode & 4: return value when already ns object
// mode & 8|1: behave like require
/**
* 01 接收二个参数,一个是 value 一般用于表示被加载的模块id ,第二个值 mode 是一个二进制的数值
* 02 t 方法内部做的第一件事情就是调用自定义的 require 方法加载value 对应的模块导出,重新赋值给 value
* 03 当获取到了这个 value 值之后余下的 8 4 ns 2 都是对当前的内容进行加工处理,然后返回使用
* 04 当mode & 8 成立是直接将 value 返回 ( 如果mode & 1 和 mode & 8 都成立,说明加载的是 commonJS规范 )
* 05 当 mode & 4 成立时直接将 value 返回(esModule)
* 06 如果上述条件都不成立,还是要继续处理 value ,定义一个 ns {}
* 6-1 如果拿到的 value 是一个可以直接使用的内容,例如是一个字符串,将它挂载到 ns 的 default 属性上
* 6-2 如果返回的不是简单数据类型,遍历对象,给每一个键值对提供getter
*/
// 11 定义 t 方法,用于加载指定 value 的模块内容,之后对内容进行处理再返回
__webpack_require__.t = function (value, mode) {
// 01 加载 value 对应的模块内容( value 一般就是模块 id )
// 加载之后的内容又重新赋值给 value 变量
if (mode & 1) value = __webpack_require__(value);
// 加载了可以直接返回使用的内容
if (mode & 8) return value;
// 如果条件成立,说明是 esModule 导出内容
if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
// 以上条件都不成立,说明既不是CommonJS规范,也不是ESModule规范,将 value 挂到自定义的 default属性上
// 如果 8 和 4 都没有成立则需要自定义 ns 来通过 default 属性返回内容
var ns = Object.create(null);
__webpack_require__.r(ns);
Object.defineProperty(ns, 'default', { enumerable: true, value: value });
if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key, function (key) { return value[key]; }.bind(null, key));
return ns;
};
// getDefaultExport function for compatibility with non-harmony modules
__webpack_require__.n = function (module) {
var getter = module && module.__esModule ?
function getDefault() { return module['default']; } :
function getModuleExports() { return module; };
__webpack_require__.d(getter, 'a', getter);
return getter;
};
// Object.prototype.hasOwnProperty.call
__webpack_require__.o = function (object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
// __webpack_public_path__
__webpack_require__.p = "";
// on error function for async loading
__webpack_require__.oe = function (err) { console.error(err); throw err; };
// 定义变量存放数组
var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
// 保存原生的 push 方法
var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
// 重写原生的 push 方法
jsonpArray.push = webpackJsonpCallback;
jsonpArray = jsonpArray.slice();
for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
var parentJsonpFunction = oldJsonpFunction;
// Load entry module and return exports
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
/************************************************************************/
({
"./src/index.js":
(function (module, exports, __webpack_require__) {
let oBtn = document.getElementById('btn')
oBtn.addEventListener('click', function () {
__webpack_require__.e(/*! import() | login */ "login").then(__webpack_require__.t.bind(null, /*! ./login.js */ "./src/login.js", 7)).then((login) => {
console.log(login)
})
})
console.log('index.js执行了')
})
});
/**
import() 可以实现指定模块的懒加载操作
当前懒加载的核心原理就是 jsonp
t 方法可以针对于内容进行不同的处理,(处理方式取决于传入的数值 8 6 7 3 2 1)
**/
总结
commonjs 规范导出内容,commonjs 规范接收导出内容,不会触发 __webpack_require__ 绑定的方法
(function (modules) { // webpackBootstrap
})
/************************************************************************/
({
"./src/index.js":
/*! no static exports found */
(function (module, exports, __webpack_require__) {
let name = __webpack_require__(/*! ./login.js */ "./src/login.js")
console.log('index.js内容执行了')
console.log(name)
}),
"./src/login.js":
/*! no static exports found */
(function (module, exports) {
module.exports = '拉勾教育'
})
});
esModule 规范导出内容,commonjs 规范接收导出内容,会触发 __webpack_require__ 绑定的 r 方法、d方法
(function (modules) {
// define getter function for harmony exports
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter });
}
};
// define __esModule on exports
__webpack_require__.r = function (exports) {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};
})
/************************************************************************/
({
"./src/index.js":
(function (module, exports, __webpack_require__) {
let obj = __webpack_require__(/*! ./login.js */ "./src/login.js")
console.log('index.js内容执行了')
console.log(obj.default, '---->', obj.age)
}),
"./src/login.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, "age", function () { return age; });
__webpack_exports__["default"] = ('zcegg');
const age = 18
})
});
esModule 规范导出内容,esModule 规范接收导出内容,会触发 __webpack_require__ 绑定的 r 方法、d方法
(function (modules) {
// define getter function for harmony exports
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter });
}
};
// define __esModule on exports
__webpack_require__.r = function (exports) {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};
})
/************************************************************************/
({
"./src/index.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
var _login_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./login.js */ "./src/login.js");
console.log('index.js内容加载了')
console.log(_login_js__WEBPACK_IMPORTED_MODULE_0__["default"], '---->', _login_js__WEBPACK_IMPORTED_MODULE_0__["age"])
}),
"./src/login.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, "age", function () { return age; });
__webpack_exports__["default"] = ('拉勾教育');
const age = 100
})
});
懒加载时,会触发 __webpack_require__ 绑定的 e方法、t方法
index.js
let oBtn = document.getElementById('btn')
oBtn.addEventListener('click', function () {
import(/*webpackChunkName: "login"*/'./login.js').then((login) => {
console.log(login)
})
})
console.log('index.js执行了')
built.js
(function (modules) { // webpackBootstrap
// install a JSONP callback for chunk loading
function webpackJsonpCallback(data) {
var chunkIds = data[0];
var moreModules = data[1];
// add "moreModules" to the modules object,
// then flag all "chunkIds" as loaded and fire callback
var moduleId, chunkId, i = 0, resolves = [];
for (; i < chunkIds.length; i++) {
chunkId = chunkIds[i];
if (Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && 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(data);
while (resolves.length) {
resolves.shift()();
}
};
// The module cache
var installedModules = {};
// object to store loaded and loading chunks
// undefined = chunk not loaded, null = chunk preloaded/prefetched
// Promise = chunk loading, 0 = chunk loaded
var installedChunks = {
"main": 0
};
// script path function
function jsonpScriptSrc(chunkId) {
return __webpack_require__.p + "" + chunkId + ".built.js"
}
// 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 promises = [];
// JSONP chunk loading for javascript
var installedChunkData = installedChunks[chunkId];
if (installedChunkData !== 0) { // 0 means "already installed".
// a Promise means "currently loading".
if (installedChunkData) {
promises.push(installedChunkData[2]);
} else {
// setup Promise in chunk cache
var promise = new Promise(function (resolve, reject) {
installedChunkData = installedChunks[chunkId] = [resolve, reject];
});
promises.push(installedChunkData[2] = promise);
// start chunk loading
var script = document.createElement('script');
var onScriptComplete;
script.charset = 'utf-8';
script.timeout = 120;
if (__webpack_require__.nc) {
script.setAttribute("nonce", __webpack_require__.nc);
}
script.src = jsonpScriptSrc(chunkId);
// create error before stack unwound to get useful stacktrace later
var error = new Error();
onScriptComplete = function (event) {
// avoid mem leaks in IE.
script.onerror = script.onload = null;
clearTimeout(timeout);
var chunk = installedChunks[chunkId];
if (chunk !== 0) {
if (chunk) {
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;
chunk[1](error);
}
installedChunks[chunkId] = undefined;
}
};
var timeout = setTimeout(function () {
onScriptComplete({ type: 'timeout', target: script });
}, 120000);
script.onerror = script.onload = onScriptComplete;
document.head.appendChild(script);
}
}
return Promise.all(promises);
};
// expose the modules object (__webpack_modules__)
__webpack_require__.m = modules;
// expose the module cache
__webpack_require__.c = installedModules;
// define getter function for harmony exports
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter });
}
};
// define __esModule on exports
__webpack_require__.r = function (exports) {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};
// create a fake namespace object
// mode & 1: value is a module id, require it
// mode & 2: merge all properties of value into the ns
// mode & 4: return value when already ns object
// mode & 8|1: behave like require
__webpack_require__.t = function (value, mode) {
if (mode & 1) value = __webpack_require__(value);
if (mode & 8) return value;
if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
var ns = Object.create(null);
__webpack_require__.r(ns);
Object.defineProperty(ns, 'default', { enumerable: true, value: value });
if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key, function (key) { return value[key]; }.bind(null, key));
return ns;
};
// getDefaultExport function for compatibility with non-harmony modules
__webpack_require__.n = function (module) {
var getter = module && module.__esModule ?
function getDefault() { return module['default']; } :
function getModuleExports() { return module; };
__webpack_require__.d(getter, 'a', getter);
return getter;
};
// Object.prototype.hasOwnProperty.call
__webpack_require__.o = function (object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
// __webpack_public_path__
__webpack_require__.p = "";
// on error function for async loading
__webpack_require__.oe = function (err) { console.error(err); throw err; };
var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
jsonpArray.push = webpackJsonpCallback;
jsonpArray = jsonpArray.slice();
for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
var parentJsonpFunction = oldJsonpFunction;
// Load entry module and return exports
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
/************************************************************************/
({
"./src/index.js":
(function (module, exports, __webpack_require__) {
let oBtn = document.getElementById('btn')
oBtn.addEventListener('click', function () {
__webpack_require__.e(/*! import() | login */ "login").then(__webpack_require__.t.bind(null, /*! ./login.js */ "./src/login.js", 7)).then((login) => {
console.log(login)
})
})
console.log('index.js执行了')
})
});
/**
import() 可以实现指定模块的懒加载操作
当前懒加载的核心原理就是 jsonp
t 方法可以针对于内容进行不同的处理,(处理方式取决于传入的数值 8 6 7 3 2 1)
**/
点击按钮后,html会加载 login.built.js
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["login"], {
"./src/login.js":
(function (module, exports) {
module.exports = "懒加载导出内容"
})
}]);
webpack.js 源码分析
执行 npx webpack 打包命令时,会执行 shell 脚本:node_modules\\.bin\\webpack.cmd
webpack.cmd
cmd 文件核心的作用就组装了 node *****/webpack/bin/webpack.js
@ECHO off
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\\node.exe" (
SET "_prog=%dp0%\\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
"%_prog%" "%dp0%\\..\\webpack\\bin\\webpack.js" %*
ENDLOCAL
EXIT /b %errorlevel%
:find_dp0
SET dp0=%~dp0
EXIT /b
webpack.js
webpack.js 中核心的操作就是 require 了 node_modules/webpack-cli/bin/cli.js
cli.js
01 当前文件一般有二个操作,处理参数,将参数交给不同的逻辑(分发业务)
02 options
03 complier
04 complier.run( 至于run 里面做了什么,后续再看,当前只关注代码入口点 )
1
以上是关于Part2-2-5 webpack 源码解析的主要内容,如果未能解决你的问题,请参考以下文章
MyCAT 源码解析 —— 分片结果合并(使用unsaferow)
> vue-init@1.0.0 dev C:CodeSpaceCode-For-paperusevue2222examvue > webpack-dev-server --inline --(代码片