webpack的模块化实现

源文件:a.js, b.js, c.js, d.js, index.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
// a.js
const a = {
x: 1
}
module.exports = a

// b.js
const b = {
x: 1
}
export default b

// c.js
export default {
x: 1
}

// d.js
const d = {
x: 1
}
export { d }

// index.js
import b from './b'
import c from './c'
import { d } from './d'
const a = require('./a')

console.log('a:', a)
console.log('b:', b)
console.log('c:', c)
console.log('d:', d)

就是在 index.js  中引入 [a, b, c, d]  等使用不同模块化方式的模块, 来看看 webpack 是怎么处理模块引用的

下面是 webpack 打包出来的 bundle.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
(function (modules) {
// 代码模块缓存, 将执行过的代码模块缓存起来
var installedModules = {};

// 实现模块化代码的主要函数, 通过以文件名为模块id(moduleId)递归调用
function __webpack_require__(moduleId) {
// 若模块已缓存, 则直接调用
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
// 创建新的模块代码, 并把模块缓存
var module = (installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {},
});

// 执行对应模块id的代码, 并将模块对象和方法绑定到当前module上
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

// 将模块已加载标识置为true
module.l = true;

// 返回模块对外暴露方法
return module.exports;
}

// 模块化处理函数: 用于 export { aaa, bbb } , import { aaa } from './*
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter });
}
};

// 挂载 _esModule 属性到 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 });
};

// 封装了 Object.prototype.hasOwnProperty.call
__webpack_require__.o = function (object, property) {
return Object.prototype.hasOwnProperty.call(object, property);
};

// 代码启动, 传入入口文件的模块id
return __webpack_require__((__webpack_require__.s = './src/index.js'));
})({
'./src/a.js': function (module, exports) {
/**
* commonjs 模块
* 直接将导出的对象赋值为 module.exports
*/
eval('const a = {\n x: 1\n}\n\nmodule.exports = a\n\n//# sourceURL=webpack:///./src/a.js?');
},

'./src/b.js': function (module, __webpack_exports__, __webpack_require__) {
/**
* es6 默认导出模块 export default
* 会在 module.exports 属性挂载属性 _esModule = true
* 然后将导出对象挂载到 module.exports.default 上
*/
'use strict';
eval(
'__webpack_require__.r(__webpack_exports__);\nconst b = {\n x: 1\n}\n\n/* harmony default export */ __webpack_exports__["default"] = (b);\n\n//# sourceURL=webpack:///./src/b.js?'
);
},

'./src/c.js': function (module, __webpack_exports__, __webpack_require__) {
/**
* es6 模块
* 同 模块b
*/
'use strict';
eval(
'__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = ({\n x: 1\n});\n\n//# sourceURL=webpack:///./src/c.js?'
);
},

'./src/d.js': function (module, __webpack_exports__, __webpack_require__) {
/**
* es6 命名导出模块 export const d = {}
* 会在 module.exports 属性挂载属性 _esModule = true
* 通过 getter 在访问 module.exports[name] 时返回导出对象
*/
'use strict';
eval(
'__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "d", function() { return d; });\nconst d = {\n x: 1\n}\n\n\n\n//# sourceURL=webpack:///./src/d.js?'
);
},

'./src/index.js': function (module, __webpack_exports__, __webpack_require__) {
/**
* 入口文件
* 通过 _webpack_require__() 得到导入对象,即 编译后的 module.exports 属性
* 对不同的模块化方式做不同的引入处理
*/
'use strict';
eval(
'__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _b__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./b */ "./src/b.js");\n/* harmony import */ var _c__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./c */ "./src/c.js");\n/* harmony import */ var _d__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./d */ "./src/d.js");\n\n\n\nconst a = __webpack_require__(/*! ./a */ "./src/a.js")\n\nconsole.log(\'a\', a)\nconsole.log(\'b\', _b__WEBPACK_IMPORTED_MODULE_0__["default"], _b__WEBPACK_IMPORTED_MODULE_0__)\nconsole.log(\'c\', _c__WEBPACK_IMPORTED_MODULE_1__["default"], _c__WEBPACK_IMPORTED_MODULE_1__)\nconsole.log(\'d\', _d__WEBPACK_IMPORTED_MODULE_2__["d"], _d__WEBPACK_IMPORTED_MODULE_2__)\n\n//# sourceURL=webpack:///./src/index.js?'
);
},
});

整体代码流程就是创建一个自执行函数, 根据文件名称递归调用内部函数 __webpack_require__(moduleId) , 从而把代码模块化

作者

大下坡

发布于

2020-11-10

更新于

2020-11-10

许可协议