Webpack catalog

  1. The core configuration of webpack5
  2. Webpack5 modularity principle
  3. Webpackage 5 with Babel/ESlint/ browser compatibility
  4. Webpack5 performance optimization
  5. Webpack5 Loader and Plugin implementation
  6. Webpack5 core source code analysis

Principle of modularity

In Webpackage 5, we can use both CommonJS and ES Module, and support other modular rules such as AMD, CMD, UMD, etc. So how does WebPack implement this modularity? Let’s talk about the two modularization principles of CommonJS and ES Module, which are the mainstream at present. We can divide them into four export and introduction methods and find the corresponding implementation mechanism.

  • CommonJSModular Implementation Principle
  • ES ModuleRealize the principle of
  • CommonJSloadingES ModuleThe principle of
  • ES ModuleloadingCommonJSThe principle of

Currently we have two export files dateformat.js exported through CommonJS and priceformat.js exported through ES Module.

// dateFormat.js
const dateNow = () = > {  
  const date = new Date(a)return date.toLocaleString()
}
module.exports = {  
  dateNow
}
Copy the code
// priceFormat.js
const add = (a, b) = > {
  return a + b
}
const minus = (a, b) = > {
  return a - b
}
export {
  add,
  minus
}
Copy the code

CommonJS modular implementation principle

We introduce dateform.js in the entry file main.js.

// main.js
const { dateNow } = require('./js/dateFormat')
console.log(dateNow())
Copy the code

Because we also need to be able to view the webPack source code, we also need to do the following configuration

module.exports = {
  / /...
  mode: 'development'.devtool: 'source-map'
  / /...
}
Copy the code

After repackaging, we can look at the bundle.js source code and remove some invalid comments.

var __webpack_modules__ = ({
  "./src/js/dateFormat.js": (function (module) {
    const dateNow = () = > {
      const date = new Date(a)return date.toLocaleString()
    }
    module.exports = {
      dateNow
    }
  })
});

// The module cache
var __webpack_module_cache__ = {};

// The require function
function __webpack_require__(moduleId) {
  // Check if module is in cache
  var cachedModule = __webpack_module_cache__[moduleId];
  if(cachedModule ! = =undefined) { 
    return cachedModule.exports;
  }
  // Create a new module (and put it into the cache)
  var module = __webpack_module_cache__[moduleId] = {
    // no module.id needed
    // no module.loaded needed
    exports: {}};// Execute the module function
  __webpack_modules__[moduleId](module.module.exports, __webpack_require__);
  // Return the exports of the module
  return module.exports;
}

var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
!function () {
  const { dateNow } = __webpack_require__(/ *! ./js/dateFormat */ "./src/js/dateFormat.js")
  console.log(dateNow())
}();
//# sourceMappingURL=bundle.js.map
Copy the code

Remove comments after the source code has been very simple, you can learn that the first will define all module __webpack_modules__, where key is the module path, value is the module function, which stores the corresponding execution function. The second step defines an empty cache object __webpack_module_cache__. The third step defines a reference to the module method __webpack_require__, and the last step is to actually execute the method. Const {dateNow} = __webpack_require__(/*! /js/dateFormat */ “./ SRC /js/ dateformat.js “), calls the reference method and passes in the module path, The __webpack_require__ reference method evaluates the cache object __webpack_module_cache__ first, and returns cachedModule.exports if there is a cache, otherwise the key is: Module path and value: {exports: Module.exports = {dateNow}. Exports = {dateNow}. Exports = {dateNow}. Module.exports is returned, __webpack_require__ is returned and the dateNow is deconstructed and printed.

Make a summary:

  1. Generate module objects__webpack_modules__
  2. The declaration module caches the object__webpack_module_cache__
  3. Declare module reference functions__webpack_require__
  4. Execute module reference functions from__webpack_modules__Returns the method inside the module object and returns the property method object after execution

ES Module Implementation principle

Now revamp main.js to introduce priceform.js.

// main.js
import { add, minus } from './js/priceFormat'console.log(add(2.3))
console.log(minus(5.3))
Copy the code

It can be seen after repackaging and removing some of the distracting gaze

var __webpack_modules__ = ({ "./src/js/priceFormat.js": (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) {    __webpack_require__.r(__webpack_exports__);    __webpack_require__.d(__webpack_exports__, {      "add": function () { return /* binding */ add; },      "minus": function () { return /* binding */minus; }});const add = (a, b) = > {      return a + b    }    const minus = (a, b) = > {      return a - b    }  })});// The module cachevar __webpack_module_cache__ = {}; // The require functionfunction __webpack_require__(moduleId) { // Check if module is in cache var cachedModule = __webpack_module_cache__[moduleId]; if (cachedModule ! == undefined) { return cachedModule.exports; } // Create a new module (and put it into the cache) var module = __webpack_module_cache__[moduleId] = { // no module.id  needed // no module.loaded needed exports: {} }; // Execute the module function __webpack_modules__[moduleId](module, module.exports, __webpack_require__); // Return the exports of the module return module.exports; }/* webpack/runtime/define property getters */! function () { // define getter functions for harmony exports __webpack_require__.d = function (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/runtime/hasOwnProperty shorthand */! function () { __webpack_require__.o = function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }} (); /* webpack/runtime/make namespace object */! function () { // 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 }); }; } (); var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.! function () { /*! * * * * * * * * * * * * * * * * * * * * *! * \! *** ./src/main.js ***! *********************/ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _js_priceFormat__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./js/priceFormat */ "./src/js/priceFormat.js"); console.log((0, _js_priceFormat__WEBPACK_IMPORTED_MODULE_0__.add)(2, 3)) console.log((0, _js_priceFormat__WEBPACK_IMPORTED_MODULE_0__.minus)(5, 3))}(); //# sourceMappingURL=bundle.js.map
Copy the code

__webpack_modules__, which holds the./ SRC /js/ priceformat. js Module. Define a __webpack_module_cache__ cache object, and the third step defines a reference to the module function __webpack_require__. D, __webpack_require__. O, __webpack_require__. R, and __webpack_require__. These functions will be executed later, after which __webpack_exports__ is defined as an empty object. It’s only in the last execution function that we actually start executing the code we need. You can see that the __webpack_require__.r(__webpack_exports__) method is called first. The __webpack_require__.r attribute is used to indicate that the ES Module is the exports Module because main.js imports the ES Module Module. / SRC /js/ priceformat.js, which is called by __webpack_require__. The reference method takes the function __webpack_modules__ corresponding to the module path and calls it. Module. exports is identified as ES module module, and then __webpack_require__.d is called. Exports, definition: {“add”: function () {return add; }, “minus”: function () { return minus; }}); This object, you can see that this is an exported method named key, and value is a function that returns that exported method. What does __webpack_require__.d do? First, it iterates through definition’s key and calls __webpack_require__.o to determine if the key is passed in as a property of the object itself. This property is not found on the module.exports passed in. Object. DefineProperty (exports, key, {enumerable: true, get:}} Object. Definition [key]}), which is fetched from the Definition object when we access the property method on Module.exports.

Summary:

  1. Generate module objects__webpack_modules__
  2. The declaration module caches the object__webpack_module_cache__
  3. Declare module reference functions__webpack_require__
  4. statement__webpack_require__.d ,__webpack_require__.o ,__webpack_require__.r
  5. Execute module reference functions from__webpack_modules__The module object returns a method and executes it
  6. __webpack_modules__The method that gets it is called first__webpack_require__.rDefinition module__esModuleProperty, representing the ES Module Module.
  7. We then define an object whose attribute method is key, value is a function, and returns that attribute methoddefinition 和 module.exportsAlong with the incoming__webpack_require__.dMethods the inside
  8. __webpack_require__.dThe first thing that’s going to happen in the method is pairdefinition 和 module.exportsthrough__webpack_require__.oMethod To judge the attribution of attributes
  9. Perform the operation when the conditions are metObject.defineProperty(exports, key, { enumerable: true, get: definition[key] }) 对 module.exportsDo a layer of proxy when we accessmodule.exportsOn the property method, it will be fromdefinitionObject.

For CommonJS, __webpack_modules__ is fetched directly from __webpack_modules__. For ES Module, there is a layer of proxy for property methods. When we access modules introduced by ES Module, we proxy on the proxy object to fetch.