Let’s write a simple demo, webpack build and watch the bundle output to see how Webpack implements JS modularity
Test the environment WebPack5
Write a simple demo
//index.js
import * as d from "./demo/demo";
import * as d2 from "./demo/demo2";
console.log(d.a);
console.log(d2.a);
Copy the code
//demo.js
import * as d from "./demo2";
export let a = d;
Copy the code
//demo2.js
export let a = { a: 1 };
Copy the code
webpack build
Webpack build generates bundle.js with the following code snippet
/ * * * * * * / (() = > { // webpackBootstrap
/ * * * * * * / "use strict";
/ * * * * * * / var __webpack_modules__ = ({
/ * * * / "./src/demo/demo.ts":
/ *! * * * * * * * * * * * * * * * * * * * * * * * * * *! * \! *** ./src/demo/demo.ts ***! A \ * * * * * * * * * * * * * * * * * * * * * * * * * * /
/ * * * / ((__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "a": () = > (/* binding */ a)
/* harmony export */ });
/* harmony import */ var _demo2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/ *! ./demo2 */ "./src/demo/demo2.ts");
let a = _demo2__WEBPACK_IMPORTED_MODULE_0__;
/ * * /
/ * * * / }),
/ * * * / "./src/demo/demo2.ts":
/ *! * * * * * * * * * * * * * * * * * * * * * * * * * * *! * \! *** ./src/demo/demo2.ts ***! A \ * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/ * * * / ((__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "a": () = > (/* binding */ a)
/* harmony export */ });
let a = { a: 1}; .Copy the code
Too many comments affect readability. Write a regular expression to remove the comments
/. *? A \ */|//. * | /\*(.|\r\n|\n)*? A \ * /Copy the code
Let’s go ahead and format the code, which now looks like this
(() = > {
"use strict";
var __webpack_modules__ = {
"./src/demo/demo.ts": (__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
a: () = > a,
});
var _demo2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
"./src/demo/demo2.ts"
);
let a = _demo2__WEBPACK_IMPORTED_MODULE_0__;
},
"./src/demo/demo2.ts": (__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
a: () = > a,
});
let a = { a: 1}; }}; e;var __webpack_module_cache__ = {};
function __webpack_require__(moduleId) {
var cachedModule = __webpack_module_cache__[moduleId];
if(cachedModule ! = =undefined) {
return cachedModule.exports;
}
var module = (__webpack_module_cache__[moduleId] = {
exports: {},}); __webpack_modules__[moduleId](module.module.exports, __webpack_require__);
return module.exports;
}
(() = > {
__webpack_require__.d = (exports, definition) = > {
for (var key in definition) {
if( __webpack_require__.o(definition, key) && ! __webpack_require__.o(exports, key)
) {
Object.defineProperty(exports, key, {
enumerable: true.get: definition[key], }); }}}; }) (); (() = > {
__webpack_require__.o = (obj, prop) = >
Object.prototype.hasOwnProperty.call(obj, prop); }) (); (() = > {
__webpack_require__.r = (exports) = > {
if (typeof Symbol! = ="undefined" && Symbol.toStringTag) {
Object.defineProperty(exports.Symbol.toStringTag, { value: "Module" });
}
Object.defineProperty(exports."__esModule", { value: true}); }; }) ();var __webpack_exports__ = {};
(() = > {
__webpack_require__.r(__webpack_exports__);
var _demo_demo__WEBPACK_IMPORTED_MODULE_0__ =
__webpack_require__("./src/demo/demo.ts");
var _demo_demo2__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
"./src/demo/demo2.ts"
);
console.log(_demo_demo__WEBPACK_IMPORTED_MODULE_0__.a);
console.log(_demo_demo2__WEBPACK_IMPORTED_MODULE_1__.a); }) (); }) ();Copy the code
Webpack module implementation explanation
If the above code is analyzed, the code functions in the bundle are divided into three parts, respectively
- __webpack_modules__ variable
- __webpack_require__ function
- Index code execution
We’ll explain the code in the order of execution of webpack_require,webpack_modules, and index
webpack_require
Let’s look at __webpack_require__.r(), which passes the export object and marks it as a module
(() = > {
__webpack_require__.r = (exports) = > {
if (typeof Symbol! = ="undefined" && Symbol.toStringTag) {
Object.defineProperty(exports.Symbol.toStringTag, { value: "Module" });
}
Object.defineProperty(exports."__esModule", { value: true}); }; }) ();Copy the code
__webpack_require__.o() is just a wrapper around hasOwnProperty
(() = > {
__webpack_require__.o = (obj, prop) = >
Object.prototype.hasOwnProperty.call(obj, prop); }) ();Copy the code
Let’s look at __webpack_require__.d(), the defintion object is shallowly copied to the exports object and set to read-only and traversable
(() = > {
__webpack_require__.d = (exports, definition) = > {
for (var key in definition) {
if( __webpack_require__.o(definition, key) && ! __webpack_require__.o(exports, key)
) {
Object.defineProperty(exports, key, {
enumerable: true.get: definition[key], }); }}}; }) ();Copy the code
Finally, __webpack_require__(), the id passed in is cached, and the module is cached from exports. If it is not, the module is fetched from __webpack_modules__ and initialized, and stored in __webpack_modules__
var __webpack_module_cache__ = {};
function __webpack_require__(moduleId) {
var cachedModule = __webpack_module_cache__[moduleId];
if(cachedModule ! = =undefined) {
return cachedModule.exports;
}
var module = (__webpack_module_cache__[moduleId] = {
exports: {},}); __webpack_modules__[moduleId](module.module.exports, __webpack_require__);
return module.exports;
}
Copy the code
webpack_modules
The __webpack_modules__ object holds the demo.js and demo2.js files, indexed by the file name, followed by the function. This function is executed when the module is initialized
Let’s start with the code logic
- The code logic is to declare __webpack_exports__ as a module
- Copy the export field from the code to __webpack_exports__
- Execute the code logic in the file
var __webpack_modules__ = {
"./src/demo/demo.ts": (__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
a: () = > a,
});
var _demo2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
"./src/demo/demo2.ts"
);
let a = _demo2__WEBPACK_IMPORTED_MODULE_0__;
},
"./src/demo/demo2.ts": (__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
a: () = > a,
});
let a = { a: 1}; }};Copy the code
See parameters
The argument comes from __webpack_require__, which you can look at below
//__webpack_require__
var module = (__webpack_module_cache__[moduleId] = {
exports: {},}); __webpack_modules__[moduleId](module.module.exports, __webpack_require__);
Copy the code
Index code execution
We understand __webpack_modules__ and __webpack_require__ and it’s not hard to see the initialization logic. So only the source code is listed and the explanation is skipped
var __webpack_exports__ = {};
(() = > {
__webpack_require__.r(__webpack_exports__);
var _demo_demo__WEBPACK_IMPORTED_MODULE_0__ =
__webpack_require__("./src/demo/demo.ts");
var _demo_demo2__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
"./src/demo/demo2.ts"
);
console.log(_demo_demo__WEBPACK_IMPORTED_MODULE_0__.a);
console.log(_demo_demo2__WEBPACK_IMPORTED_MODULE_1__.a); }) ();Copy the code
conclusion
Webpack to achieve the principle of JS modular use is through the various files in the code function closure to achieve. After each JS file is closed, it is stored as key-value in the __webpack_modules__ object and is read from __webpack_require__ exports to avoid variables affecting the global scope