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