Webpack product analysis and Principle (including CJS/ESM/code separation/lazy loading)

It is strongly recommended that you compare rollup horizontally after reading this article, so that both packaging tools will have a fuller understanding of rollup packaging product analysis and principles (compared to WebPack).

The following conclusions are based on a step-by-step practical test and then analysis of the package to explain the principle

  • Start with something simple
  • First pure CJS, in pure ESM, in mixed use, in the analysis of third-party modules, analysis of dynamic introduction

Scope of test cases:

  • (After testing, many results are similar. For reasons of length, the following article introduces only typical ones.)

    Internal code

    1. Simplest package, entry file without export and import
    2. Import files are exported but not imported
    3. The import file is imported instead of exported
    4. Import file has export, has import
    5. Serial dependencies (Level 2)
    6. Parallel rely on
    7. Parallel dependencies have common dependencies

    External dependencies

    1. Static loading (CJS and ESM)
    2. Dynamic loading () => import(‘xx’) and code separation

Packaging principles for WebPack

(Test environment WebPack4 +)

Before you understand how packaging works, you need to understand the background, the background in which WebPack was born

  • Let’s take a look at the history of how JavaScript was used on the Web before packaging tools came along.

  • There are two ways to run JavaScript in a browser.

    • In the first way, reference scripts (script tags) to house each function. This solution is difficult to scale because loading too many scripts can cause network bottlenecks.
    • The second way, useA packageLarge with all project code.jsFiles, but this leads to problems with scope, file size, readability, and maintainability.
  • History of solution (can view the detail: webpack.docschina.org/concepts/wh…

    1. iife

    2. Commonjs – (Biggest issue: browsers don’t support CommonJS because commonJS is dynamically loaded at runtime, it’s synchronous, browsers sync too slowly)

    3. Esm-ecmascript module

      • Future official standards and mainstream. However, the browser version needs to be higher, for example, the Browser version 63 or higher, (ESM is static, you can analyze the corresponding dependencies at compile time, not like commonJS, can refer to my other article juejin.cn/post/695936…).

The background can be summarized as follows:

  1. Commonjs is good, NPM manages JavaScript module package, but browsers don’t support it
  2. Esm is better, and browsers support it, but only very new browsers support it. You can write esM modules in source code, and Webpack can help package them so that non-ESM-compatible browsers can also be compatible

Now that you know where WebPack came from, it’s easy to understand how webPack is packaged. The packaging principle of Webpack is divided into two cases

  1. Solution 1: Pack all content into a chunk package

    Without additional configuration, WebPack will generally pack all JS into one package. Implementation steps

    1. Read files, scan codes, arrange modules according to the loading sequence of modules, divided into module 1, module 2… , module n. Modules is an array, all modules are sorted in the order they’re loaded, indexed
    2. Webpack implements its own API (such as require), allowing the browser to support modular writing in the source code (such as: module.export, require, ESM slightly different see below).

    The same is true for packaging external dependencies

  2. Solution 2: Multiple Chunks? (for example: dynamic packaging ()=>import(‘xx’), code separation)

    See details below

Use a demo to better understand the processing method one (merge into a chunk) (Single chunk)

Single-chunk principle resolution

Example: Take the CommonJS module as an example

// import file main.js
const { b } = require('./test/b')
const a = 'I'm a';
console.log('print' + a + b);

// ./test/b
module.exports = { 
    b: 'I'm b' 
};
Copy the code

The code can be executed correctly directly on the browser terminal.

(function (modules) {
  var installedModules = {}; // Cache module

  // Webpack's own implementation of require method, source code will be replaced by this require
  function __webpack_require__(moduleId) {
    // The loaded module is returned directly to the cache
    if (installedModules[moduleId]) {
      return installedModules[moduleId].exports;
    }
    // Attention!! This module will be written by Webpack itself and then return, mimicking commonJS's module
    var module = installedModules[moduleId] = {
      i: moduleId,
      exports: {} // module.exports emulates CommonJS
    };

    // Attention!! This line executes module functions, which are the following /* 0 */ /* 1 */ (and passes in the module.exports that Webpack mimics)
    modules[moduleId].call(module.exports, module.module.exports, __webpack_require__);

    Module.exports // Return webpack mimics module.exports
    return module.exports;
  }
  // Start from /* 0 */ module
  return __webpack_require__(0); //  
})
  / * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
  ([
    /* 0 */  // import file main.js
    / * * * / (function (module, __webpack_exports__, __webpack_require__) {
       const { b } = __webpack_require__(1); // The require in the source code is changed to webpack mimicking __webpack_require__
       const a = 'I'm a';
       console.log('print' + a + b);
    }),
    / * 1 * /  // import file main.js dependencies./test/b
    / * * * / (function (module.exports, __webpack_require__) {
      module.exports = {
        b: 'I'm b'}; })]);Copy the code

Analyze the package, noting the comments on each line, and the structure of the code

  • The code structure is an IIFE, the pass parameter is an array, each item of the array, is the source code module code/* 0 */ is the main.js code, /* 1 */ is./test/b.js code

Conclusion:

  • The first idea of Webpack to solve the module problem is:All js dependencies, packaged into one file, and then implemented a set of require and Module.exports that browsers could execute the source code
    1. The require of the source code will be replaced__webpack_require__
    2. The module.exports of source code remains unchanged and is passed to the source code by Webpack as an argument to the function

extension

  • Careful friends may notice,Only pure CommonJS is considered here, so how does WebPack handle ESM?
    • Because of the length, this article first gives the conclusion, interested partners can go to test themselves

    • Other case 1: The modular approach is pure ESM

      • Webpack will do tree shaking, and the final product will be closer to the rollup product, with less webPack-injected compatibility code
      • The implementation idea is similar to rollup. Through the static feature of ESM, the corresponding dependencies can be analyzed at compile time
      • For example, in the example above, if you change to pure ESM, you get only one module/* 0 */
        /* 0 */
        const b = 'I'm b';
        const a = 'I'm a';
        console.log('print' + a + b);
        Copy the code
    • Other case 2: the module mode is a mixture of ESM + CommonJS

      • Webpack is very powerful and it supports mixed use!!
      • You can export module. Exports and import xx from xx
      • Exports {} exports, require imports
      • Module. Exports and provides the above simulation__webpack_require__The idea behind replacing require is similar,Webpack emulates esM exports objectsGet browser support
    • In addition, packaging third-party dependencies, as long as it is not dynamic packaging (such as ()=>import(‘xx’)) and not code separation, is handled in the same way as above. If you are interested, you can test it by yourself. If you have any questions, leave a comment

Three demos to better understand processing method two (multiple chunks)

Normally, webpack js files are only generated on a chunk, unless some additional configuration is done, or some shared dependencies are introduced, or they are loaded dynamically.

Multiple chunks can be named in the following three cases, for example:

Import ('./test/a').then(e => {console.log(e)}) console.log(111) 2. SplitChunksPlugin removes' CommonsChunkPlugin 'out of the box from webPack V4. Instead, 'optimization.splitchunks' is used. Webpack will automatically split chunks based on the following criteria: - New chunks can be shared, or modules can come from the 'node_modules' folder - new chunks are bigger than 20KB (before min+gz) - when loading chunks on demand, Maximum number of concurrent requests less than or equal to 30 - Maximum number of concurrent requests less than or equal to 30 when loading the initialization page When trying to meet the last two conditions, it is best to use larger chunks. {index: './ SRC /index.js', another: './ SRC /another-module.js',},Copy the code

Multi-chunk loading principle analysis

Each of the three approaches works slightly differently, in order from simple to complex (which happens to be the reverse of the above).

1. Multiple packing entrances.

  • This is actually quite easy to understand, packaging entry is different, will definitely separate multiple packages
    // webpack.config.js
    entry: {
      main: './src/main.js'.a_js: './src/test/a.js',},// './ SRC /main.js' (contents of main.js)
    console.log(1)
    
    // './ SRC /test/a.js' (a.js contents)
    console.log(2222)
    Copy the code

    Packing effect:

    Built at: 01/16/2022 11:31:52 AM Asset Size Names favicon. Ico 16.6 KiB [emitted] index.html 691 bytes [emitted] Even though it must be an absolute resolution of the resolution resolution of an existing document, it must be an absolute resolution of the resolution resolution of an existing document even though it is an absolute resolution of the resolution resolution resolution of an existing document. Dist js a_js.f67190e.js main.f09f871.js index.html contents of index.html<! DOCTYPEhtml>
        <html>
            <head>.</head>
            <body>
                <div id="app"></div>
                <script type="text/javascript" src="./js/main.f09f871.js"></script>
                <script type="text/javascript" src="./js/a_js.f67190e.js"></script>
            </body>
        </html>
    Copy the code
  • conclusion
    1. Multiple entries separate multiple packages and then generate multiple Script labels (in order of entry)
    2. Separate packages containing the same amount of mock code (webPack injected code)

2. Separating common dependencies(For example, both a and B files rely on AXIos to prevent AXIos from being repeatedly packaged into A and B.No lazy loading modules)

  • Use index.html to control, load venders first (common reliance on Axios), then main.js

    // webpack.config.js Webpack version v4.x
    entry: './src/main.js'.optimization: {
      splitChunks: {
        chunks: 'all'}}// './ SRC /main.js' (contents of main.js)
    import Axios from 'axios' // Co-introduced axios
    Axios.get()
    import {b} from './test/a'
    console.log(b)
    
    // './ SRC /test/a.js' (a.js contents)
    import Axios from 'axios' // Co-introduced axios
    Axios.get()
    export const b = 'xx'
    export const bbbbbbb = 'xx'
    Copy the code

    Package the result, the public dependencies axios will put into Venders

    Built at: 01/16/2022 11:43:59 AM Asset Size Names favicon.ico 16.6 KiB [emitted] index.html 699 bytes [emitted] Currently, js/main.48bf1d1.js 7.5 KiB 0 [emitted] [immutable] main js/vendors~main.4f0895a.js 41.9 KiB 1 [emitted] [immutable] Vendors ~main index.html content (controlled using index.html, venders loaded first (public dependencies))<! DOCTYPEhtml>
        <html>
        <body>
            <div id="app"></div>
            <script type="text/javascript" src="./js/vendors~main.4f0895a.js"></script>
            <script type="text/javascript" src="./js/main.48bf1d1.js"></script></body>
        </body>
        </html>
    Copy the code

    Vendors ~ main.4f0895A.js (loaded first) (this package will be abbreviated to Venders later, vendors~ main.4f0895A.js)

    The code, vendors~main.4f0895a.js, is pasted here, simplified and focuses on structure, with 26 small modules, each arranged by index (there are as many modules in the AXIos source code, and bundled together here in sequence)

    (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[1], [/* 0 */
        (function(module.exports, __webpack_require__) {... Simplification, mainly see structure}),/ * 1 * /
        (function(module.exports, __webpack_require__) {... Simplified, mainly look at structure}),... ./ * * / 25The axios library, there's a total of0to2526Small pieces])Copy the code

    We focus on the first line window [” webpackJsonp “] = window (” webpackJsonp “) | | []

    • The first line globally buries a webpackJsonp attribute, and the subsequent module accesses axios’s 26 “small” modules through window[“webpackJsonp”]. (If you’ve read this far, try opening a webPack project at will. As long as there are multiple chunk packages, check the console window attribute, will find the webpackJsonp attribute!! 😉)

    The followingAnalysis main.48bf1d1.js (later loaded by venders)

    • The code has been partially edited and commented to make it easier to understand.
    • The structure is the same as a single chunk package, a self-executing function(function(modules))({26: contents of main.js})(This index is 26 becauseThe first 0-25 are axios packages, placed in Venders, loaded firstThe main purpose here isPut modules in Venders and parse them normally)
    • !!!!! Pay attention to the comments, mainly look at the Chinese comments, according to the code execution order
    (function (modules) { // webpackBootstrap
      // Add the 26 axios modules, vendors~main.4f0895a.js, to modules (in the current scope, vendors~main.4f0895a.js has only one module, which is the following parameter {26: xx})
      function webpackJsonpCallback(data) {
        var chunkIds = data[0];
        var moreModules = data[1];
        var executeModules = data[2];
    
        // add "moreModules" to the modules object,
        // then flag all "chunkIds" as loaded and fire callback
        var moduleId, chunkId, i = 0;
        for (; i < chunkIds.length; i++) {
          chunkId = chunkIds[i];
          installedChunks[chunkId] = 0;
        }
        for (moduleId in moreModules) {
          if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { modules[moduleId] = moreModules[moduleId]; }}// add entry modules from loaded chunk to deferred list
        deferredModules.push.apply(deferredModules, executeModules || []);
    
        // run deferred modules when all chunks ready
        return checkDeferredModules();
      };
    
      // Detect modules loaded lazily (delay modules, can be seen as modules executed later than Venders, purpose: to add modules in the scope of venders first, into modules)
      function checkDeferredModules() {
        var result;
        for (var i = 0; i < deferredModules.length; i++) {
          var deferredModule = deferredModules[i];
          var fulfilled = true;
          for (var j = 1; j < deferredModule.length; j++) {
            var depId = deferredModule[j];
            if(installedChunks[depId] ! = =0) fulfilled = false;
          }
          if (fulfilled) {
            deferredModules.splice(i--, 1);
            result = __webpack_require__(__webpack_require__.s = deferredModule[0]); }}return result;
      }
    
      // The module cache
      var installedModules = {};
    
      // object to store loaded and loading chunks
      // undefined = chunk not loaded, null = chunk preloaded/prefetched
      // Promise = chunk loading, 0 = chunk loaded
      var installedChunks = {
        0: 0
      };
    
      var deferredModules = [];
    
      // Webpack emulates the require method, which is exactly the same as __webpack_require__ in a single chunk
      function __webpack_require__(moduleId) {}
    
      // Vendenrs package modules are placed in the global object window["webpackJsonp"], here, through window["webpackJsonp"]
      var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] | | [];for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
    
      // add entry module to deferred list
      deferredModules.push([26.1]); // Make the following {26: xx} modules run in __webpack_require__
      // run deferred modules when ready
      return checkDeferredModules(); // Trigger the defer module (a module executed later than Venders, with the purpose of first adding modules from Venders to this scope and putting them in modules)({}){26: xx} is the code inside main.js
    
      26: // Why start with index 26, because indexes from 0 to 25 are axios dependencies and are put into modules via webpackJsonpCallback
        (function (module, __webpack_exports__, __webpack_require__) {
    
          "use strict";
          // ESM COMPAT FLAG
          __webpack_require__.r(__webpack_exports__);
    
          / / EXTERNAL MODULE: / node_modules / _axios @ 0.18.1 @ axios/index, js
          var _axios_0_18_1_axios = __webpack_require__(1);
          var _axios_0_18_1_axios_default = /*#__PURE__*/__webpack_require__.n(_axios_0_18_1_axios);
    
          // CONCATENATED MODULE: ./src/test/a.js
          _axios_0_18_1_axios_default.a.get();
          const b = 'xx';
          const bbbbbbb = 'xx';
    
          // CONCATENATED MODULE: ./src/main.js
          _axios_0_18_1_axios_default.a.get();
          console.log(b); })});Copy the code

    Main.48bf1d1.js parsing summary

    1. The modules in the VendenRS package are placed in global objectswindow["webpackJsonp"]It’s inside, so it’ll pass firstwindow["webpackJsonp"]To get it. Here, for example, 26 axios modules,And then put it into modules(This parameter is visible on the first line).
    2. Single chunk means only one JS file, so all modules are already in modules.
    3. Here there are multiple chunks because there is no lazy chunk loading, so you just need to put the modules in venders loaded first into modules, and then it will be the same as single-chunk parsing

    Separation of common dependencies: Overall process summary

    1. ① Load the Venders package first (third-party public dependencies). This loading is not parsing code, but storing the third-party dependent modules in the global object Window [“webpackJsonp”] in a format that can be parsed by Webpack, which is convenient for subsequent code to access
    2. Import (xx) from main.48bf1d1.js (import(xx) from main.48bf1d1.js) Simply place modules on the Venders in the window[“webpackJsonp”] into modules in the main code’s scope, and it will be the same as single-chunk parsing

3. Import () dynamic loading (lazy loading)

  • Within Webpack, using the import() function, lazy loading of a module can be implemented asynchronously (the module is not loaded until the corresponding row is executed)

    // './ SRC /main.js' (contents of main.js)
    console.log('Do a lot of things')
    console.log('Do a lot of things')
    console.log('Do a lot of things')
    import('./test/a').then(e= > { // lazy loading: the './test/a' module will not be loaded until this line is executed
      console.log(e)
    })
    console.log(111)
    console.log('Do a lot of things')
    
    
    // './ SRC /test/a.js' (a.js contents)
    export const b = 'xx'
    export const bbbbbbb = 'xx'
    Copy the code

    Pack the result

    Built at: 01/16/2022 5:21:55 PM Asset Size Names favicon.ico 16.6 KiB [emitted] index.html 624 bytes [emitted] Even though it must be an absolute must, it must be an absolute must. Js /1.bc77410.js 750 bytes 1 [emitted] [immutable] js/main.34d22b8.js 9.01 KiB 0 [emitted] [immutable] main index. HTML (Only main.34d22b8.js is loaded, lazy dependencies are loaded by code control in main.34d22b8.js, which actually generates script tags dynamically)<! DOCTYPEhtml>
        <html>
        <body>
            <div id="app"></div>
            <script type="text/javascript" src="./js/main.34d22b8.js"></script>
        </body>
        </html>
    Copy the code

    Start by analyzing the lazy loading module js/1.bc77410.js (simple enough in itself)

    • As with the multi-chunk pattern, use the global object Window [“webpackJsonp”] as the cache “middleman”
    (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[1], [/* 0 */.// the 0th module is loaded first main.34d22b8.js
    / * 1 * /
    / * * * / (function(module, __webpack_exports__, __webpack_require__) {
    
    "use strict";
    __webpack_require__.r(__webpack_exports__); // The same way webPack parses esM modules, it emulates exports objects
    /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b".function() { return b; });
    /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bbbbbbb".function() { return bbbbbbb; });
    
    const b = 'xx';
    const bbbbbbb = 'xx';
    
    / * * * /})]]);Copy the code

    After analyzing main.34d22b8.js (the first one executed, the lazy loading module is not executed yet), let’s look at the main structure. The structure is the same as the single chunk package. A self-executing function(modules) (/* 0 */ index 0 is the code for main.34d22b8.js)

    • Pay attention to the comments!!
    (function (modules) {...// To simplify a large section of code
        function webpackJsonpCallback(data) {
          var chunkIds = data[0];
          var moreModules = data[1];
    
          // add "moreModules" to the modules object,
          // then flag all "chunkIds" as loaded and fire callback
          var moduleId, chunkId, i = 0, resolves = [];
          for (; i < chunkIds.length; i++) {
            chunkId = chunkIds[i];
            if (Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
              resolves.push(installedChunks[chunkId][0]);
            }
            installedChunks[chunkId] = 0;
          }
          for (moduleId in moreModules) {
            if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { modules[moduleId] = moreModules[moduleId]; }}while(resolves.length) { resolves.shift()(); }};var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] | | []; jsonpArray.push = webpackJsonpCallback;// Load entry module and return exports
        return __webpack_require__(__webpack_require__.s = 0);
    })
    ([
      /* 0 */
      (function (module.exports, __webpack_require__) {
        console.log('Do a lot of things');
        console.log('Do a lot of things');
        console.log('Do a lot of things');
        __webpack_require__.e(/* import() */ 1).then(__webpack_require__.bind(null.1)).then(e= > {
          // lazy loading: the './test/a' module will not be loaded until this line is executed
          console.log(e);
        });
        console.log(111);
        console.log('Do a lot of things'); })]);// The core point is only discussed here because the code is too longThe first concernimport() Where is the originalimport('./test/a').then(e= > { // lazy loading: the './test/a' module will not be loaded until this line is executed
          console.log(e)}) was replaced with __webpack_require__.e(/* import() */ 1).then(__webpack_require__.bind(null.1)).then(e= > { // lazy loading: the './test/a' module will not be loaded until this line is executed
          console.log(e); }); So let's focus on __webpack_require__.e(/* import() */ 1).then(__webpack_require__.bind(null.1)).then(e= > { // lazy loading: the './test/a' module will not be loaded until this line is executed
          console.log(e); }); __webpack_require__.e(/* import() */ 1) will get onePromiseIf thisPromiseThis will be a big pity. Then (__webpack_require__.bind()null.1)).then(e= >...). ; This line of code __webpack_require__.bind(null.1), and I'm sure those of you who understand the single chunk part will see right away that this is parsing1.Bc77410.js inside the module and then simulatemoduleExports, andreturn module.exports, and then. Then (e= >...). ; You can receive the parameters. Then parse __webpack_require__.e(/* import() */ 1The function __webpack_require__.e = is posted herefunction requireEnsure(chunkId) {
      var promises = [];
    
      // JSONP chunk loading for javascript
      var installedChunkData = installedChunks[chunkId];
      if(installedChunkData ! = =0) { // 0 means "already installed".
        // a Promise means "currently loading".
        if (installedChunkData) {
          promises.push(installedChunkData[2]);
        } else {
          // setup Promise in chunk cache
          var promise = new Promise(function (resolve, reject) {
            installedChunkData = installedChunks[chunkId] = [resolve, reject];
          });
          promises.push(installedChunkData[2] = promise);
    
          // start chunk loading
          var script = document.createElement('script');
          var onScriptComplete;
    
          script.charset = 'utf-8';
          script.timeout = 120;
          if (__webpack_require__.nc) {
            script.setAttribute("nonce", __webpack_require__.nc);
          }
          script.src = jsonpScriptSrc(chunkId);
    
          // create error before stack unwound to get useful stacktrace later
          var error = new Error(a); onScriptComplete =function (event) {
            // avoid mem leaks in IE.
            script.onerror = script.onload = null;
            clearTimeout(timeout);
            var chunk = installedChunks[chunkId];
            if(chunk ! = =0) {
              if (chunk) {
                var errorType = event && (event.type === 'load' ? 'missing' : event.type);
                var realSrc = event && event.target && event.target.src;
                error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ':' + realSrc + ') ';
                error.name = 'ChunkLoadError';
                error.type = errorType;
                error.request = realSrc;
                chunk[1](error);
              }
              installedChunks[chunkId] = undefined; }};var timeout = setTimeout(function () {
            onScriptComplete({type: 'timeout'.target: script});
          }, 120000);
          script.onerror = script.onload = onScriptComplete;
          document.head.appendChild(script); }}return Promise.all(promises); }; seevar script = document.createElement('script');
        document.head.appendChild(script); this2Ok, I think you've got the idea, use the script tag to load js/1.In addition, in the code above, in the webpackJsonpCallback function, there is2linevar jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] | | []; jsonpArray.push = webpackJsonpCallback;window["webpackJsonp"]. Push is overridden as webpackJsonpCallback (which retains the push capability but adds the following functions 👇🏻)PromiseThe state of "is changed from pending to depressingCopy the code

    Summarize the process

    1. ① Execute the contents of the main module first, from top to bottom, focusing on the import(‘xx’).then() line. When packaged, import() is replaced with the Webpack API (__webpack_require__.e(/* import() */ 1).then(__webpack_require__.bind(null, 1)).then())
    2. ② The replaced API does several things
      1. Generate script tag and appendChild into ducument. Head
      2. 2.Return a Promise object whose state is PendingPending states do not execute later.then(__webpack_require__.bind(null, 1)).then(), but it won’t block the main program, because it’s asynchronous.
      3. ③ (asynchronous) After waiting for a period of time, the requirement lazy loading module through the script tag, is downloaded to the browser will be directly parsed execution, triggerwindow["webpackJsonp"].pushThis method has been rewritten to trigger the webpackJsonpCallback function, rather than generating synchronous chunks
      4. ④ The function of webpackJsonpCallback
        1. Lazy module content will be added to the list of mudules’ modules in Main.
        2. (2) This will change the state of the Promise from pending to depressing, because the module to be lazy to load has already been resolved through the script tag. Then () can be fulfilled
      5. ⑤ The following is the normal package parsing, and the single-chunk parsing multi-module is the same

Finally, explain why webPack packaged code looks “ugly”.

Webpack was born before esM and after CommonJS

  • Browsers at the time could only load modules with script tags
    • Script tag loading code is not scoped, can only be implemented within the code using iIFE.
      • This is why webPack’s large code structure is iIFE
      • In addition, each module must be installed in function to ensure that the scope does not interfere with each other.
      • Is this the real reason why webPack packaged code looks messy at first glance and you can’t find your own code
  • The webpack code injection problem, becauseBrowsers do not support CJS, soWebpack implements the require and Module.exports methods itselfWebpack polyfills itself.
    • All these years, even now in 2022,Why don’t browsers support CJS?
      • CJS is synchronous, run-time, the Node environment uses CJS, and node itself runs on the server without waiting for a network handshake, so synchronization is fast
      • The browser is the client, accessing the server resources, waiting for the network handshake in the middle, which can be very slow, so the cards that can’t be synchronized are waiting for the server to return, and the experience is poor
  • After the subsequent RELEASE of ESM, webpack kept the iIFE structure and code injection in order to be compatible with the old packages sent on NPM before (and the heart was not determined enough at that time, resulting in more and more packages with ugly structure, and it was impossible to change such “ugly structure” in the future). As a result, the products packaged by WebPack are now preserved. At first glance, the structure is messy and there is a lot of code injection, their own code can not find

It is strongly recommended that you compare rollup horizontally after reading this article, so that both packaging tools will have a fuller understanding of rollup packaging product analysis and principles (compared to WebPack).

The length is a little long, it is not easy to write clearly, you can leave a message if there is a problem, and it may not be easy to understand

You’ll need a lot of background knowledge (CommonJS, ESM, advantages and disadvantages and browser compatibility issues, commonJS’s previous module history, WebPack configuration, third party vender dependency concept, code separation, lazy loading, self-executing functions iife, Promise (microtasks, macro tasks), Code debugging ability)

The author suggests that the best use of their own packaging debugging, packaging products and careful analysis. If you can’t understand it for a while, you can also collect this article and read it over a period of time to understand the pre-knowledge first

Finally, thanks for the likes!