commonjs
You can write both CommonJS modules and ES modules in Webpack, regardless of browser compatibility. Let’s look at how this works.
Commonjs modularize is a simple way to configure webPack, write two modules to compile and have a look:
webpack.config.js
module.exports = {
mode: "development".devtool: "none"
}
Copy the code
index.js
const a = require('./a')
console.log(a)
Copy the code
a.js
const a = 'a';
module.exports = a;
Copy the code
Compile the results
Looking at the compilation results, you can see that WebPack does what Node does for each module, placing each module in a function environment and passing in the necessary parameters. Webpack will form these modules into an object (the attribute name is the module path (module ID), the attribute value is the module content) into an immediate execution function, the immediate execution function defines a function __webpack_require__ similar to the Node require function, to achieve the function of importing modules.
With some comments and unwanted code removed from the package, it is clear that the key to commonJS modularity is the __webpack_require__ function, which passes in the module ID to get an export of the module.
The require function
An implementation of the __webpack_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] = {
i: moduleId,
l: false.exports: {}};// Execute the module function
modules[moduleId].call(module.exports, module.module.exports, __webpack_require__);
// Flag the module as loaded
module.l = true;
// Return the exports of the module
return module.exports;
}
Copy the code
This function should be easy to understand if you are familiar with Node:
- First check to see if the module has already been loaded, so you need a global variable
installedModules
Used to record all exports of loaded modules - A module that has not been loaded is constructed first
module
Object, the key is to have oneexports
attribute - Executes the module code and returns the module export value
The final step is to load the startup module, which is the last sentence of IIFE:
return __webpack_require__("./src/index.js");
Copy the code
ES Module
The es modular approach is implemented with __webpack_require__. Let’s look at some of the code that was just removed:
-
__webpack_require__.r
This function is used to identify the export of the ES module
// define __esModule on 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 }); }; Copy the code
-
__webpack_require__.d
Used to handle named exports of es modules
// define getter function for harmony exports __webpack_require__.d = function (exports, name, getter) { if(! __webpack_require__.o(exports, name)) { Object.defineProperty(exports, name, { enumerable: true.get: getter }); }};Copy the code
-
__webpack_require__.o
hasOwnPreperty
__webpack_require__.o = function (object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; Copy the code
Let’s change the Module code to see the compilation result of pure ES Module import/export:
index.js
import a, { test } from './a'
import b from './b'
console.log(a);
test();
console.log(b)
Copy the code
a.js
const a = 'a';
function test() {}export default a;
export { test }
Copy the code
b.js
const b = 'b';
export default b;
Copy the code
Compile the results
{
"./src/a.js": (function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */
__webpack_require__.d(__webpack_exports__, "test".function () { return test; });
const a = 'a';
function test() {}/* harmony default export */
__webpack_exports__["default"] = (a);
}),
"./src/b.js": (function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
const b = 'b';
/* harmony default export */
__webpack_exports__["default"] = (b);
}),
"./src/index.js": (function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */
var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/a.js");
/* harmony import */
var _b__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/b.js");
console.log(_a__WEBPACK_IMPORTED_MODULE_0__["default"])
Object(_a__WEBPACK_IMPORTED_MODULE_0__["test") ();console.log(_b__WEBPACK_IMPORTED_MODULE_1__["default"])})}Copy the code
__webpack_require__ is used as the core function. The difference is that es is modular. Exports objects are marked as es module first by __webpack_require__. R, which is the default property of exports, and __webpack_require__. The goal is to make these named exports readable and not modifiable outside the module (a feature of es Module).
The change of the v5
But why is default not handled by __webpack_require__.d? Originally, webpack 4 was used to package, and then changed webpack 5 to try, the result of webpack 5 is also processed default, this may be a small bug of Webpack 4.
Webpack5 compiles slightly differently, but the logic remains the same:
Two modular interactions
Webpack supports the coexistence of two types of modular code, although this is not recommended. First let’s take a look at what the import result looks like when they import each other:
Let’s take a look at how WebPack works by modifying the module:
index.js
const { a, test } = require('./a')
Copy the code
a.js
import b from './b'
import * as bbb from './b'
console.log(bbb)
console.log(b)
console.log(b.b)
const a = 'a';
function test() {}export default a;
export { test };
Copy the code
b.js
module.exports = {
b: () = >{},moduleName: 'b'
}
Copy the code
Compile the results
{
"./src/a.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */
__webpack_require__.d(__webpack_exports__, "test".function () { return test; });
/* harmony import */
var _b__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/b.js");
/* harmony import */
var _b__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_b__WEBPACK_IMPORTED_MODULE_0__);
console.log(_b__WEBPACK_IMPORTED_MODULE_0__)
console.log(_b__WEBPACK_IMPORTED_MODULE_0___default.a)
console.log(_b__WEBPACK_IMPORTED_MODULE_0___default.a.b)
const a = 'a';
function test() {}/* harmony default export */
__webpack_exports__["default"] = (a);
}),
"./src/b.js": (function (module.exports) {
module.exports = {
b: () = >{},moduleName: 'b'}}),"./src/index.js": (function (module.exports, __webpack_require__) {
const { a, test } = __webpack_require__("./src/a.js")})}Copy the code
It can be found that when importing a CommonJS module as an ES module, the imported module is wrapped with __webpack_require__.n, which should be compatible with import * as obj from ‘…. ‘such syntax.
The concrete implementation of this function:
__webpack_require__.n = function (module) {
var getter = module && module.__esModule
? function getDefault() { return module['default']; }
: function getModuleExports() { return module; };
__webpack_require__.d(getter, 'a', getter);
return getter;
}
Copy the code
conclusion
The core of modularity in Webpack is the __webpack_require__ function, which imports both commonJS modularity and ES modules. And the use of the immediate execution of the function characteristics to achieve the scope of the closed to avoid global variables pollution, very clever.