skip to content
天真笔录

webpack打包原理分析

/ 4 min read

webpack将代码打包后是什么样的

准备工作(CommonJS为例)

// src/index.js
const { sayHello } = require("./hello");
console.log(sayHello("tianzhen"));
// hello.js
function sayHello(name) {
	console.log("hello" + name);
}
module.exports = {
	sayHello,
};

运行 npx webpack —mode none

分析

/******/ (() => {
	// webpackBootstrap
	/******/ var __webpack_modules__ = [
		,
		/* 0 */ /* 1 */
		/***/ (module) => {
			function sayHello(params) {
				return "hello" + params;
			}
			module.exports = {
				sayHello,
			};
			/***/
		},
		/******/
	];
	/************************************************************************/
	/******/ // The module cache
	/******/ var __webpack_module_cache__ = {};
	/******/
	/******/ // The require function
	/******/ function __webpack_require__(moduleId) {
		/******/ // Check if module is in cache
		/******/ var cachedModule = __webpack_module_cache__[moduleId];
		/******/ if (cachedModule !== undefined) {
			/******/ return cachedModule.exports;
			/******/
		}
		/******/ // Create a new module (and put it into the cache)
		/******/ 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;
		/******/
	}
	/******/
	/************************************************************************/
	var __webpack_exports__ = {};
	// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
	(() => {
		const { sayHello } = __webpack_require__(1);

		console.log(sayHello("tianzhen"));
	})();

	/******/
})();

最外层是一个立即执行函数

(() => {})();

入口

(() => {
	const { sayHello } = __webpack_require__(1);

	console.log(sayHello("tianzhen"));
})();

最下面有一个立即执行函数,这里就是入口所在

webpack_require

上面执行了__webpack_require__(1)

function __webpack_require__(moduleId) {
	// Check if module is in cache
	var cachedModule = __webpack_module_cache__[moduleId];
	if (cachedModule !== undefined) {
		return cachedModule.exports;
	}
	// Create a new module (and put it into the cache)
	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;
}
  1. 接受一个参数moduleId
  2. 检查__webpack_module_cache__中是否存在
    • 存在则返回module.exports
    • 由于第一次执行,cachedModule为undefined
  3. __webpack_module_cache__[moduleId]定义对象并赋值给module
  4. 执行 __webpack_modules__[moduleId](module, module.exports, __webpack_require__)
    • 传入参数module module.exports __webpack_require__

webpack_modules

var __webpack_modules__ = [
	,
	/* 0 */ /* 1 */
	/***/ (module) => {
		function sayHello(params) {
			return "hello" + params;
		}
		module.exports = {
			sayHello,
		};
		/***/
	},
];
  1. __webpack_modules__是一个数组,里面按顺序存放了模块依赖的js
  2. 由于上面传入的moduleId为1,则找到第二个位置,可以看到是hello.js的内容
  3. 执行__webpack_modules__[moduleId](module, module.exports, __webpack_require__)
(module) => {
	function sayHello(params) {
		return "hello" + params;
	}
	module.exports = {
		sayHello,
	};
	/***/
};
  1. 可以看到通过传入的参数module,最后通过module.exports覆盖了之前的exports

回到入口

// 通过上面的分析得出 __webpack_require__ 执行后返回了module.exports
// 而__webpack_modules__[moduleId](module, module.exports, __webpack_require__)在执行后,为module.exports赋值了一个新对象,这个对象中含有sayHello函数
// const { sayHello }  = __webpack_require__(1)
const { sayHello } = { sayHello: sayHello }

console.log(sayHello('tianzhen'))
})();

所以最后解构出sayHello,然后执行

webpack_module_cache

var __webpack_module_cache__ = {};

__webpack_module_cache__ 是缓存module用的,再次导入模块时,会直接命中缓存