执行文件分析

同步模块加载流程

webpack4 和 webpack5 同步模块加载流程基本相同

  1. 默认执行入口文件
  2. 查找模块缓存
  3. 如果没有缓存创建缓存对象,否则直接返回
  4. 创建模块后执行模块
  5. 通过__webpack_require__.r为模块添加module标识
  6. 如果有模块依赖通过__webpack_require__重新执行步骤 (1)
  7. 把导出结果添加到__webpack_exports__ ,default 属性上
  8. 导出到下一个模块使用

webpack4 通过闭包以参数的形式导入,webpack5 则是直接写在作用于内部

webpack4 模块的返回值直接添加到exprots对象中,webpack5的返回值则是通过函数,类似注入的形式添加

webapck4 同步模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
(function(modules) { // webpackBootstrap
// 模块的缓存
var installedModules = {};

// 核心require方法
function __webpack_require__(moduleId) {
// 如果存在缓存直接返回
if(installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
// 创建一个新的module并放入的缓存中
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};

// 执行模块函数
// 导出的对象会被添加到module.exports对象中
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

// 标识为loading状态
module.l = true;

// 返回模块中导出的对象
return module.exports;
}


// expose the modules object (__webpack_modules__)
// 所有的模块对象
__webpack_require__.m = modules;

// expose the module cache
// 被缓存的模块对象
__webpack_require__.c = installedModules;


// 在导出对象上定义 __esModule 属性,es6模块化规范
__webpack_require__.r = function(exports) {
if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};

// 加载入口文件并导出
// __webpack_require_方法上添加一个静态属性s,标识入口文件模块索引
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
/************************************************************************/
({
"./src/app.js":
(function(module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
console.log('app')
function App(){};
__webpack_exports__["default"] = (App)
}),

"./src/index.js":
(function(module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
var _app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/app.js");
Object(_app__WEBPACK_IMPORTED_MODULE_0__["default"])();
console.log("index.js");
})
});

webpack5 同步模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
(() => {
"use strict";
// 类似react hooks的写法,直接在内部作用域中定义并执行
var __webpack_modules__ = ({
"./src/app.js":
((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

__webpack_require__.r(__webpack_exports__);

// 在指定的对象上面添加属性
__webpack_require__.d(__webpack_exports__, {
// 定义一个函数不会使用到未初始化的变量
"default": () => (__WEBPACK_DEFAULT_EXPORT__)
});
console.log('app');
function App(){}
const __WEBPACK_DEFAULT_EXPORT__ = (App);
}),
"./src/index.js":
((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
var _app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/app.js");
// ???????
(0,_app__WEBPACK_IMPORTED_MODULE_0__.default)();
console.log("index.js");
})
});
// 模块缓存
var __webpack_module_cache__ = {};

// __webpack_require__没有变化
function __webpack_require__(moduleId) {
// Check if module is in cache
if(__webpack_module_cache__[moduleId]) {
return __webpack_module_cache__[moduleId].exports;
}

var module = __webpack_module_cache__[moduleId] = {
// no module.id needed
// no module.loaded needed
exports: {}
};

// Execute the module function
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);

// Return the exports of the module
return module.exports;
}

(() => {
// define getter functions for harmony(和谐) exports
//
__webpack_require__.d = (exports, definition) => {
for(var key in definition) {
// 如果exports没有想添加的属性时
if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
// 在exports上添加注入的属性
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
}
}
};
})();

// hasOwnProperty简写
(() => {
__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
})();

// 添加Module标识
(() => {
__webpack_require__.r = (exports) => {
if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};
})();


// startup
// Load entry module and return exports
// This entry module can't be inlined because the eval devtool is used.
var __webpack_exports__ = __webpack_require__("./src/index.js");

})()
;

webpack4异步模块加载过程

  • 定义全局的变量 webpackJsonp用于接受异步的chunk,重写了webpackJsonp.push方法,在异步chunkpush的时候会调用 webpackJsonpCallback

  • __webpack_require__(__webpack_require__.s = "./src/index.js"); 执行入口文件

    • 在缓存中能查到直接返回
    • 创建一个初始化的模块对象,并加入到缓存中
    • 执行模块对应的函数 –> 进入下面环节
    • 执行结束后模块加载状态标记为以完成
  • 如果文件中依赖了异步的chunk,会通过 __webpack_require__.e(chunk名称)方法引入

    • __webpack_require__.e 创建promises[]用于保存异步模块创建的Promise
    • 如果缓存中有正在pending中的模块,则把 Promise 对象添加到数组中
    • 创建Promise对象 保存 [resolve, reject, Promise]
    • 创建script标签appendhead标签中, (pending中,执行入口文件后面的方法)
    • 异步模块加载完成后自动执行,调用 window[“webpackJsonp”] push 方法,执行webpackJsonpCallback函数
    • 把异步chunk创建prosmie对象时的resolve函数添加到resolves数组中
    • 在缓存中把异步chunk标记为完成(0)
    • 在模块集合中添加新加载的异步模块
    • 在全局的数组webpackJsonp添加异步加载的模块
    • 循环执行resolve方法,全部执行后执行Promise.allthen方法
  • __webpack_require__.bind(null, "./src/app.js")加载刚刚添加到模块集合中的异步模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
(function(modules) {
// 加载异步模块成功后的回调函数
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]) {
// 把模块请求promise的resolve函数添加到数组中
resolves.push(installedChunks[chunkId][0]);
}
// 标记模块已经加载完成
installedChunks[chunkId] = 0;
}

//在模块集合中添加异步请求的模块
for(moduleId in moreModules) {
if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
modules[moduleId] = moreModules[moduleId];
}
}

// 异步模块的信息添加到全局的jsonpArray中
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
// 标识模块加载的4个状态
var installedChunks = {
"main": 0
};

// script path function
function jsonpScriptSrc(chunkId) {
return __webpack_require__.p + "" + ({}[chunkId]||chunkId) + ".js"
}

// require方法无变化
function __webpack_require__(moduleId) {
if(installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
module.l = true;
return module.exports;
}

// 这个文件只包含入口chunk
// 额外的chunks使用chunk loading函数
__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".
// 4个状态中只有Promise为真
if(installedChunkData) {
promises.push(installedChunkData[2]);
} else {
// setup Promise in chunk cache
var promise = new Promise(function(resolve, reject) {
installedChunkData = installedChunks[chunkId] = [resolve, reject];
});
// installedChunkData = [resolve, reject,Promise]
promises.push(installedChunkData[2] = promise);

// 开始加载异步模块
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.
// 避免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 __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 });
};

// __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);
// push方法会调用webpackJsonpCallback
jsonpArray.push = webpackJsonpCallback;
jsonpArray = jsonpArray.slice();
for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
var parentJsonpFunction = oldJsonpFunction;


// 加载入口模块
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
/************************************************************************/
({
"./src/index.js":
(function(module, exports, __webpack_require__) {
__webpack_require__.e(0)
.then(__webpack_require__.bind(null, "./src/app.js"))
.then(module=>{(module.default)()});
console.log("index.js");
})

});

/0.js

1
2
3
4
5
6
7
8
9
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0],{
"./src/app.js":
(function(module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
console.log('app');
function App(){};
__webpack_exports__["default"] = (App);
})
}]);
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2015-2025 SunZhiqi

此时无声胜有声!

支付宝
微信