Open
Description
问题
用了webpack有一段时间了,其实对webpack打包出来的bundle.js里面到底是什么,怎么实现的不了解,只是知道里面有一坨东西。恰好有同事研究到了这个,觉得非常有意思,所以自己也来研究一下。
一个入口,一个文件
// webpack.config.js
module.exports = {
entry:'./index.js',
output:{
filename:'bundle.js'
}
};
// index.js
console.log('index');
// bundle.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] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = 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;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports) {
console.log('index');
/***/ }
/******/ ]);
分析:
1、 整个bundle.js其实是一个自执行表达式,传入参数是一个数组,数组的第一项是一个function,function里面是原先index.js里面真正的内容。
2、 IIFE里面有闭包,__webpack_require_是模块加载函数,接收模块id(对,webpack中每个模块都会有一个独一无二的id,其实也就是在IIFE传参数组中的索引值(0,1,2.....)
3、真正执行module index里面语句的是个调用
// Execute the module function
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
我们下面来看看webpack这么做是什么意思。
一个入口,两个文件,A依赖B
// a.js
var b = require('./b.js');
console.log('a');
b.b1();
// b.js
exports.b1 = function () {
console.log('b1')
};
exports.b2 = function () {
console.log('b2')
};
// bundle.js
/******/ (function(modules) { // webpackBootstrap
// 省略一大段...........
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
var b = __webpack_require__(1);
console.log('a');
b.b1();
/***/ },
/* 1 */
/***/ function(module, exports) {
exports.b1 = function () {
console.log('b1')
};
exports.b2 = function () {
console.log('b2')
};
/***/ }
/******/ ]);
分析:
- 由于有两个文件,所以IIFE得参数为长度是2的数组,并按照require的顺序排列。
- IIFE函数体部分是一模一样的,所以在这儿就先省略了。
- module a发生了变化。因为a依赖b,所以在a中调用webpack加载模块的函数
// 1是模块b的id
var b = __webpack_require__(1);
4.我们再来分析一下
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
使用call是因为为了确保每个module中的this指向的是module本身。然后给它传__webpack_require函数是想让module有加载其他module的能力。
两个入口,两个出口
下面我们讨论:A包含B和C,D包含C。
我们看看最后build出来的两个bundle.js有什么不同。
// bundle.a.js
// 省略相同的部分
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
var b = __webpack_require__(1);
var c = __webpack_require__(2);
b.b1();
console.log('a');
/***/ },
/* 1 */
/***/ function(module, exports) {
exports.b1 = function () {
console.log('b1')
};
exports.b2 = function () {
console.log('b2')
};
/***/ },
/* 2 */
/***/ function(module, exports) {
exports.c1 = function () {
console.log('c1')
};
exports.c2 = function () {
console.log('c2')
};
/***/ }
/******/ ]);
// bundle.b.js
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
var c = __webpack_require__(2);
c.c2();
console.log('d');
/***/ },
/* 1 */,
/* 2 */
/***/ function(module, exports) {
exports.c1 = function () {
console.log('c1')
};
exports.c2 = function () {
console.log('c2')
};
/***/ }
/******/ ]);
分析:
- 我们从这儿可以看到,两个入口文件a和d的module id都是0,所以可以猜测每个入口文件对应的module id都是0。
- bundle.b.js没有id为1的module,为什么呢?因为每个module id在全局都是唯一的,从上面的图片我们可以看到,id为1的是moduleb,而modulec不包含b,所以1那儿就是空的。
问题:这种情况下有个问题,那就是module c在两个bundle.js被重复包含了,怎么提取出来呢?
// 未完待续