webpack源码打包文件分析-异步加载

打包前文件

index.js文件

import('./bundle/a').then((add) => {
    console.log('add---')
})

a.js文件

const add = function (a, b) {
  return a + b
}

export default add

使用webpack的mode为development打包

第一步

加载

__webpack_require__(__webpack_require__.s = "./index.js")
__webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./bundle/a */ \"./bundle/a.js\")).then((add) => {\n    console.log('add---')\n  })")

webpack_require.e 函数

/******/ 	// 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);
/******/ 	};

installedChunkData 有三种状态 为0 代表已加载,undefined代表未加载,promise代表加载中

此时,新建一个promise对象,将当前的installedChunkData状态为[resolve, reject, promise],

新建script标签,src通过 jsonpScriptSrc函数获取,在事件script.onerror 、 script.onload 中添加回调函数

/******/ 				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;
/******/ 					}
/******/ 				};

回调函数 onScriptComplete 是处理文件加载失败,调用 chunk1; 即installedChunkData 中的reject函数

问题:成功的回调函数在哪里?

第一次执行时:在window[“webpackJsonp”]中添加一个push回调函数

/******/ 	var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
/******/ 	var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
/******/ 	jsonpArray.push = webpackJsonpCallback;

当 script文件加载完毕时

(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0],{

/***/ "./bundle/a.js":
/*!*********************!*\
  !*** ./bundle/a.js ***!
  \*********************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);const add = function (a, b) {\n  return a + b\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (add);\n\n//# sourceURL=webpack:///./bundle/a.js?");

/***/ })

}]);

可知0.build.js文件是一个立即执行函数,window[“webpackJsonp”]调用push函数,即上文中的

webpackJsonpCallback回调函数

/******/ 	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()();
/******/ 		}
/******/
/******/ 	};

其中installedChunks[chunkId][0] 即指resolve函数

__webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./bundle/a */ \"./bundle/a.js\"))

这步就很简单了,使用__webpack_require__ 执行./bundle/a.js 文件里的内容

Webpack的基础原理是将项目中所有的模块都视为一个依赖关系图,然后根据入口文件进行递归分析,将所有的依赖模块打包成一个或多个打包后的文件Webpack打包过程主要包括以下几个步骤: 1. 解析模块:Webpack会解析所有的模块,包括模块的依赖关系、模块类型等。 2. 执行loader:Webpack会根据模块的类型执行相应的loader,将模块转换成一个可执行的JavaScript代码。 3. 分析依赖:Webpack分析每个模块的依赖关系,确定模块的依赖关系图。 4. 打包模块:Webpack会将所有的模块打包成一个或多个文件,同时生成打包后的代码和资源文件打包后的文件解读: Webpack打包后的文件主要包括两个部分:运行时代码和打包后的模块代码。 运行时代码是Webpack在运行时需要的一些代码,例如模块加载函数、模块缓存等等。 打包后的模块代码是Webpack根据依赖关系图打包后的模块代码,这些代码可能被压缩、合并、优化等处理过。每个模块都被包装在一个函数中,这个函数可以接受其他模块作为参数,同时也可以导出自己的API供其他模块使用。打包后的模块代码的顺序和结构都是由Webpack根据依赖关系图自动决定的。 总之,Webpack打包后的文件是一个可执行的JavaScript文件,包含了项目中所有的模块和资源,并且可以在浏览器或Node.js环境中运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值