这是一个极简版的 Webpack 打包原理演示。
为了让你一眼看懂,我去掉了所有复杂的缓存检查、异步加载和辅助函数,只保留最核心的 "模块注册表" 和 "require 函数" 。
🎯 核心逻辑:Webpack 是如何工作的?
Webpack 打包后的本质就是一个 自执行函数(IIFE) ,它做了两件事:
- 把所有文件代码存进一个对象里(键是文件名,值是函数)。
- 实现一个简单的
require函数,用来从这个对象里取代码并执行。
💻 简化版 Demo 代码
假设这是 dist/bundle.js 的核心内容:
javascript
// ==========================================
// 1. Webpack 启动引导 (Bootstrap)
// ==========================================
(function(modules) {
// modules 参数就是下面那个巨大的对象,包含所有文件代码
// 【核心】模拟 require 函数
function __webpack_require__(moduleId) {
// 1. 检查模块是否已经执行过 (缓存),这里简化省略缓存逻辑
// 2. 从 modules 对象中取出对应的模块函数
var module = modules[moduleId];
// 3. 创建一个空的 exports 对象,用于接收模块导出的内容
var exports = {};
// 4. 执行模块函数!
// 把 exports 和 __webpack_require__ 传进去
// 模块内部通过操作 exports 来导出变量
module(exports, __webpack_require__);
// 5. 返回导出的内容
return exports;
}
// 【启动】执行入口文件 (假设 index.js 的 ID 是 './src/index.js')
__webpack_require__('./src/index.js');
})({
// ==========================================
// 2. 模块注册表 (所有源文件都在这里)
// ==========================================
'./src/a.js': function(exports, __webpack_require__) {
// --- 原始代码: export function sayHelloA() ... ---
// Webpack 将 export 转换为对 exports 对象的赋值
exports.sayHelloA = function() {
console.log("Hello from A");
};
},
'./src/b.js': function(exports, __webpack_require__) {
// --- 原始代码: export function sayHelloB() ... ---
exports.sayHelloB = function() {
console.log("Hello from B");
};
},
'./src/index.js': function(exports, __webpack_require__) {
// --- 原始代码: import { sayHelloA } from './a.js' ---
// Webpack 将 import 转换为调用 __webpack_require__
var a = __webpack_require__('./src/a.js');
var b = __webpack_require__('./src/b.js');
// 调用导入的函数
a.sayHelloA();
b.sayHelloB();
console.log("App Finished");
}
});
🔍 原理解析 (3 步走)
第一步:包裹 (Wrap)
Webpack 把你的每个文件 (a.js, b.js, index.js) 都塞进一个函数里。
这个函数接收两个参数:
exports: 用来存放你要导出的东西。__webpack_require__: 用来引入别的文件。
第二步:收集 (Collect)
所有包裹好的函数,被放进一个大对象 modules 里。
- Key: 文件路径 (如
'./src/a.js') - Value: 包裹后的函数
第三步:执行 (Execute)
-
Webpack 立即调用最外层的函数,传入
modules对象。 -
它调用
__webpack_require__('./src/index.js')启动程序。 -
index.js运行到require('./src/a.js')时:- 去
modules对象里找到'./src/a.js'对应的函数。 - 创建一个空对象
{}作为exports。 - 执行 该函数,此时
exports被填入了sayHelloA。 - 把填好的
exports返回给index.js。
- 去
-
最终,所有依赖按顺序执行完毕。
🚀 总结
Webpack 并没有真的让浏览器支持 import/export,它是通过闭包和对象映射,在浏览器里"模拟"了一套 CommonJS 风格的模块系统。
- 源码 :
import a from './a' - 打包后 :
var a = __webpack_require__('./src/a.js')
这就是模块化打包的魔法所在。