Rollup packaging product analysis and principles (compared to Webpack)

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

A rollup positioning

Rollup is 2 years later than WebPack, which is definitely differentiated from WebPack

We can check out the official website rollupjs.org/guide/en/#o…

The following characteristics are obtained

  1. It is recommended that developers use esM to write modules.
    1. The benefits of using the ESM module are numerous:Juejin. Cn/post / 695936… )
      1. Native support for advanced browsers (there are only 2 ways for browsers to import JS modules, 1 for script tags and 2 for ESM modules)
      2. You can do tree shaking (earlier versions of Webpack did not support tree shaking)
      3. Can solve the problem of circular reference
  2. Esm will eventually be available anywhere (browser + Node is the future standard), but Rollup makes it possible for you today.
    • This is an important statement, and it’s what makes Rollup tick, and it’s why it was born
    • There are historical reasons (please refer to my previous article on Webpack for details)
    • To put it simply: the ESM-ECMAScript module is the official standard and mainstream of the future. However, the browser version needs to be higher, such as The Chorme version 63 or above
      • So the main point of rollup is: the future isn’t there yet, but rollup lets you write future code first.

Rollup uses the process

For applications used in the browser environment:

  1. Regardless of browser compatibility
    • Developers write ESM code -> rollup passesThe entrance, recursively recognizingESM modules -> eventually packaged into one or more bundle.js -> browsers can support import directly<script type="module">
  2. Need to consider browser compatibility issues
    • It can be complicated and requires additional Polyfill libraries, or in combination with Webpack

Packaged as an NPM package:

  • Developers write ESM code -> rollup passesThe entrance, recursively identifying ESM modules -> (can support configuration output of modules in multiple formats such as ESM, CJS, UMD, AMD) and ultimately packaged into one or more bundle.js
    • (Developers can also write CJS using @rollup/plugin-commonjs)

Preliminary opinion

  • Rollup is obviously a good place to package js libraries (react, Vue, etc.) or higher versions of browser applications that don’t need to be compatible down the line.
  • This packaged library makes full use of tree Shaking on ESM and minimizes the size of the source library

For a simple comparison of webPack packaging and rollup packaging, see 🌰

This demo is pure ESM writing

// enter main. js
import { b } from './test/a'
console.log(b + 1)
console.log(1111)

// './test/a'
export const b = 'xx'
export const bbbbbbb = 'xx'
Copy the code

Rollup package effect (very clean, no injected code)

const b = 'xx';
console.log(b + 1);
console.log(1111);
Copy the code

Webpack effects (lots of injected code)

  • In fact, our own code is at the bottom. The large chunk of code injected above is webPack’s own compatible code. The purpose is to implement require, modules.exports, export, and make the browser compatible with CJS and ESM syntax
  • Webpack implements its own Polyfill support module syntax and Rollup takes advantage of older browsers’ native ESM support.
/ * * * * * * / (function(modules) { // webpackBootstrap
/ * * * * * * /   // The module cache
/ * * * * * * /   var installedModules = {};
/ * * * * * * /
/ * * * * * * /   // The 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;
/ * * * * * * /   }
/ * * * * * * /
/ * * * * * * /
/ * * * * * * /   // expose the modules object (__webpack_modules__)
/ * * * * * * /   __webpack_require__.m = modules;
/ * * * * * * /
/ * * * * * * /   // expose the module cache
/ * * * * * * /   __webpack_require__.c = installedModules;
/ * * * * * * /
/ * * * * * * /   // 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 });
/ * * * * * * /    }
/ * * * * * * /   };
/ * * * * * * /
/ * * * * * * /   // 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 });
/ * * * * * * /   };
/ * * * * * * /
/ * * * * * * /   // create a fake namespace object
/ * * * * * * /   // mode & 1: value is a module id, require it
/ * * * * * * /   // mode & 2: merge all properties of value into the ns
/ * * * * * * /   // mode & 4: return value when already ns object
/ * * * * * * /   // mode & 8|1: behave like require
/ * * * * * * /   __webpack_require__.t = function(value, mode) {
/ * * * * * * /    if(mode & 1) value = __webpack_require__(value);
/ * * * * * * /    if(mode & 8) return value;
/ * * * * * * /    if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/ * * * * * * /    var ns = Object.create(null);
/ * * * * * * /    __webpack_require__.r(ns);
/ * * * * * * /    Object.defineProperty(ns, 'default', { enumerable: true.value: value });
/ * * * * * * /    if(mode & 2 && typeofvalue ! ='string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/ * * * * * * /    return ns;
/ * * * * * * /   };
/ * * * * * * /
/ * * * * * * /   // getDefaultExport function for compatibility with non-harmony modules
/ * * * * * * /   __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;
/ * * * * * * /   };
/ * * * * * * /
/ * * * * * * /   // Object.prototype.hasOwnProperty.call
/ * * * * * * /   __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/ * * * * * * /
/ * * * * * * /   // __webpack_public_path__
/ * * * * * * /   __webpack_require__.p = ". /";
/ * * * * * * /
/ * * * * * * /
/ * * * * * * /   // Load entry module and return exports
/ * * * * * * /   return __webpack_require__(__webpack_require__.s = 0);
/ * * * * * * / })
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/ * * * * * * / ([
/* 0 */
/ * * * / (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);

// CONCATENATED MODULE: ./src/test/a.js
const b = 'xx';
const bbbbbbb = 'xx';

// CONCATENATED MODULE: ./src/main.js
console.log(b + 1);
console.log(1111); 

/ * * * / })
/ * * * * * * / ]);
Copy the code

Both deal with the comparison of source code modules

Pure esm Pure CJS A mixture of the two
webpack Support (with code injection) Support (with code injection) Support (with code injection)
rollup Support (no injection) Native not supported (need to add plugin @rollup/plugin-commonjs) Native not supported (need to add plugin @rollup/plugin-commonjs)

Rollup also wants developers to write ESM, not CJS. Because ESM is the new standard for javascript and the future, it has a lot of advantages that older browsers support

Both processing external exposure module, very different!! (Explain why rollup is good for packaging libraries)

Add export to the demo above

// enter main. js
import { b } from './test/a'
console.log(b + 1)
console.log(1111)
export { // Add an export
  b
}

// './test/a'
export const b = 'xx'
export const bbbbbbb = 'xx'
Copy the code

Rollup package exports (very clean, no injected code)

  • Rollup doesn’t polyfill itself
  • Rollup configuration files require no special configuration and can be supportedExport multiple modules (ESM, CJS, UMD, AMD)
    // rollup.config.js
    const OUTPUT_DIR = 'dist'
    const INPUT_FILE = 'src/main.js'
    export default[
     // esm
      {
        input: INPUT_FILE,
        output: {
          file: OUTPUT_DIR + '/esm/index.js'.format: 'esm' // Export the ESM module}},// commonjs
      {
        input: INPUT_FILE,
        output: {
          file: OUTPUT_DIR + '/cjs/index.js'.format: 'cjs' // Export the CJS module}},// umd
      {
        input: INPUT_FILE,
        output: {
          file: OUTPUT_DIR + '/umd/index.js'.format: 'umd' // Export the UMD module}},]Copy the code

    Packaged to ESM and CJS

    // esm
    const b = 'xx';
    console.log(b + 1);
    console.log(1111);
    export { b };
    
    // cjs
    const b = 'xx';
    console.log(b + 1);
    console.log(1111);
    exports.b = b;
    
    // umD (compatible with 3 types: CJS, AMD, global)
    (function (global, factory) {
        typeof exports= = ='object' && typeof module! = ='undefined' ? factory(exports) :
        typeof define === 'function' && define.amd ? define(['exports'], factory) :
        (global = typeofglobalThis ! = ='undefined' ? globalThis : global || self, factory(global.aa = {})); }) (this, (function (exports) { 'use strict';
        const b = 'xx';
        console.log(b + 1);
        console.log(1111);
        exports.b = b;
        Object.defineProperty(exports.'__esModule', { value: true });
    }));
    Copy the code

Webpack export (huge difference, lots of injected code, not very good export ESM support)

  • Webpack needs to be configured (in this case webpack 4.x)

    output: { ... .library: 'myLib'.// The name of the exposed variable
      libraryTarget: 'commonjs',}Copy the code

    Webpack can only support exporting CJS or older compatible packages (UMDS) for now

    Esm not supported (experimental)

    Here we export the CJS package and compare it to rollup

    • There is a lot of injected code and it is redundant
    exports["myLib"] =
    / * * * * * * / (function(modules) { // webpackBootstrap
    / * * * * * * /   // The module cache
    / * * * * * * /   var installedModules = {};
    / * * * * * * /
    / * * * * * * /   // The 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;
    / * * * * * * /   }
    / * * * * * * /
    / * * * * * * /
    / * * * * * * /   // expose the modules object (__webpack_modules__)
    / * * * * * * /   __webpack_require__.m = modules;
    / * * * * * * /
    / * * * * * * /   // expose the module cache
    / * * * * * * /   __webpack_require__.c = installedModules;
    / * * * * * * /
    / * * * * * * /   // 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 });
    / * * * * * * /    }
    / * * * * * * /   };
    / * * * * * * /
    / * * * * * * /   // 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 });
    / * * * * * * /   };
    / * * * * * * /
    / * * * * * * /   // create a fake namespace object
    / * * * * * * /   // mode & 1: value is a module id, require it
    / * * * * * * /   // mode & 2: merge all properties of value into the ns
    / * * * * * * /   // mode & 4: return value when already ns object
    / * * * * * * /   // mode & 8|1: behave like require
    / * * * * * * /   __webpack_require__.t = function(value, mode) {
    / * * * * * * /    if(mode & 1) value = __webpack_require__(value);
    / * * * * * * /    if(mode & 8) return value;
    / * * * * * * /    if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
    / * * * * * * /    var ns = Object.create(null);
    / * * * * * * /    __webpack_require__.r(ns);
    / * * * * * * /    Object.defineProperty(ns, 'default', { enumerable: true.value: value });
    / * * * * * * /    if(mode & 2 && typeofvalue ! ='string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
    / * * * * * * /    return ns;
    / * * * * * * /   };
    / * * * * * * /
    / * * * * * * /   // getDefaultExport function for compatibility with non-harmony modules
    / * * * * * * /   __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;
    / * * * * * * /   };
    / * * * * * * /
    / * * * * * * /   // Object.prototype.hasOwnProperty.call
    / * * * * * * /   __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
    / * * * * * * /
    / * * * * * * /   // __webpack_public_path__
    / * * * * * * /   __webpack_require__.p = ". /";
    / * * * * * * /
    / * * * * * * /
    / * * * * * * /   // Load entry module and return exports
    / * * * * * * /   return __webpack_require__(__webpack_require__.s = 0);
    / * * * * * * / })
    / * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
    / * * * * * * / ([
    /* 0 */
    / * * * / (function(module, __webpack_exports__, __webpack_require__) {
    
    "use strict";
    // ESM COMPAT FLAG
    __webpack_require__.r(__webpack_exports__);
    
    // EXPORTS = {b: x} // EXPORTS = {b: x} // EXPORTS = {b: x} // EXPORTS = {b: x} Module. Exports = {b: xx}
    __webpack_require__.d(__webpack_exports__, "b".function() { return /* reexport */ b; });
    
    // CONCATENATED MODULE: ./src/test/a.js
    const b = 'xx';
    const bbbbbbb = 'xx';
    
    // CONCATENATED MODULE: ./src/main.js
    console.log(b + 1);
    console.log(1111);
    
    / * * * / })
    / * * * * * * / ]);
    Copy the code

    Look at the tenth row from the bottom, there’s a

    // EXPORTS __webpack_require__.d(__webpack_exports__, "b", function() { return /* reexport */ b; }); This line handles esM exports because we are using export {b: xx}. If we are using CJS exports like module.exports = {b: exports. Module. Exports = {b: xx} (webpack emulates module. Exports)Copy the code

Why does WebPack need to inject so much code?

Webpack was born 2 years before Rollup, before the ESM standard 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 implements polyfill 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

Rollup was created after the ESM standard came out, was designed for ESM, and has no historical baggage, so it can be truly “packaged” (streamlined, no extra injection)

  • (The earliest upload time according to NPM version: Webpack is around 2013, rollup is 2015.5)

How does rollup package third-party dependent and lazy-loaded modules and public modules?

As with WebPack packaging, there are two types: single-chunk packages and multi-chunk packages

  1. Single chunk package

    No additional configuration, generally all JS into a package. The same goes for packaging external dependencies (third parties). Such as:

    / / the main entrance. Js
    import Axios from 'axios'
    Axios.get()
    console.log(1111) ------ packed results ------// Eventually the axios source code and the main.js main code are packaged into a single file, with no additional code injection
    // The following is a truncated one, the middle is omitted
    import require$$1 $1from 'http';
    import require$$2 from 'https';
    import require$$0, $1from 'url';
    import require$$3 from 'assert';
    import require$$4 from 'stream';
    import require$$0 from 'tty';
    import require$$1 from 'util';
    import require$$7 from 'zlib';
    
    var axios$1 = {exports: {}};
    
    var bind$2 = function bind(fn, thisArg) {
      return function wrap() {
        var args = new Array(arguments.length);
        for (var i = 0; i < args.length; i++) {
          args[i] = arguments[i];
        }
        returnfn.apply(thisArg, args); }; }; . . . axios$1.exports = axios;
    
    // Allow use of default import syntax in TypeScript
    axios$1.exports.default = axios;
    
    var _axios_0_18_1_axios = axios$1.exports;
    _axios_0_18_1_axios.get();
    console.log(1111);
    Copy the code

    Here’s a note about rollup packaging:

    • Rollup /plugin-node-resolve is required to install @rollup/plugin-node-resolve. There is no tree shaking because it is a CJS package

      • The principle of plug-ins is to convert the CJS package into esM package in packaging
    • Now the popular monorepo is completely packaged with ESM write library +rollup. It is easy to tree shaking, making the core library smaller, parsing faster, and providing external tools to expand its influence

  2. Multiple Chunk packages (code separation)

    1. Configure multiple entry, this method is relatively simple, can test
      // rollup.config.js
       input: {            
           index: 'src/main.js'.other: 'src/other.js',},Copy the code
    2. Code separation (dynamic import, lazy load, import(XXX).then(module => {}))
    • Here’s an official example that couldn’t be clearer

      / / the main entrance. Js
      /* DYNAMIC IMPORTS DYNAMIC import Rollup supports automatic chunking and lazy-loading Rollup supports automatic chunking and lazy loading via DYNAMIC IMPORTS Utilizing the Import Mechanism dynamic imports of the host system. */
      if (displayMath) {
          import('./maths.js').then(function (maths) {
                  console.log(maths.square(5));
                  console.log(maths.cube(5));
          });
      }
      
      // './maths.js'
      import square from './square.js';
      export {default as square} from './square.js';
      export function cube (x ) {
              return square(x) * x;
      }
      
      // './square.js'
      export default function square ( x ) {
              returnx * x; } ---------------- package result ----------------// main.js
      'use strict';
      /* DYNAMIC IMPORTS DYNAMIC import Rollup supports automatic chunking and lazy-loading Rollup supports automatic chunking and lazy loading via DYNAMIC IMPORTS Utilizing the Import Mechanism dynamic imports of the host system. */
      if (displayMath) {
              // To package as a CJS module, replace import with Promise + require
              // Promise.resolve(require('.. /chunk-0ee5c472.js')).then(function (maths) {
              import('.. /chunk-c4d97f01.js').then(function (maths) {
                      console.log(maths.square(5));
                      console.log(maths.cube(5));
              });
      }
      
      / / '.. /chunk-0ee5c472.js'
      'use strict';
      function square ( x ) {
              return x * x;
      }
      function cube (x ) {
              return square(x) * x;
      }
      exports.cube = cube;
      exports.square = square;
      Copy the code

      For code splitting, there is also a way to explicitly tell Rollup which modules to split into separate chunks via the output.manualchunks option.

      Conclusion:

      • Dynamic import, rollup versus webPack support for module formats

        Packaged module format: esm cjs amd umd
        webpack Not supported. Experimental support support support
        rollup support support support Does not support
      • Implementation principle, compared to Webpack:

        • Webpack is its own implementation of “dynamic import” (with promise + script tag + window object + mock import method)
        • Rollup is (packaged as esM modules) naturally supported using browsers (chorme63 and above)Dynamic import
          • Or (packaged as a CJS module) Promise + CJS require
      • There is an important detail here

        • Vue and React single-page projects use dynamic import to load routes. Note that if you want to run a package on the browser, it should be an ESM package (browsers do not support CJS). Then pay attention to the browser version (chorme63 and above)

          • Because rollup does no additional code injection, it takes full advantage of older browsers’ native support for import (so the code is particularly clean and WebPack does a lot of compatibility with its own implementation of require and import)

    1. How does rollup handle public modules? (For example, modules A, B and C depend on D simultaneously)

      There are two cases:

      1. If there is no dynamic import in the source code, it will be classified as a chunk (modules A, B, C and D are all contained in a package, and d only has one copy normally).

      2. Lazy-loaded modules exist in the source code, and lazy-loaded modules also access public dependencies, such as

        / / the main entrance. Js
        import {deepCopy} from '@xxx/methods/deepCopy.js' // This is a package placed in the company's NPM domain, which can be understood as exporting a simple deepCopy function
        console.log(deepCopy(a))
        import('./test/a').then(e= > {
          console.log(e)
        })
        
        // './test/a' Lazy loading modules also depend on the same public module
        import {deepCopy} from '@xxx/methods/deepCopy.js'
        const a = {a: 1}
        export constB = deepCopy(a) ---------- Whether public dependencies will be packaged2Copy of? -------------- the answer is no, rollup or cow P, public dependencies will only come out one copy, and then externalexport(here is an example of export ESM format, test export CJS format can be the same, here is not repeated, interested can test their own) generated directory structure, there are3File A-19173be8.js main.js main-219c2eaf.js// main.js
        import './main-219c2eaf.js';
        
        // main-219c2eaf.js
        const deepCopy = function (obj) {
          // do ..
        };
        console.log(deepCopy(a));
        import('./a-19173be8.js').then(e= > {
          console.log(e);
        });
        
        // a-19173be8.js
        import { d as deepCopy } from './main-219c2eaf.js';
        const a = {a: 1};
        const b = deepCopy(a);
        export { b };
        Copy the code

        Summary: Rollup does not double pack for public dependencies! And no injected code at all! No additional configuration is required. In contrast to WebPack, WebPack needs to configure Optimization.splitChunks (above WebPack 4.x)

conclusion rollup vs webpack

Rollup was born after the ESM standard came out

  • The starting point is that we want developers to write ESM modules, which is good for code static analysis, tree shaking to reduce code size, and also the browser’s ability to truly modularize JavaScript beyond script tags. Is the future of JS
  • Rollup relies entirely on older browsers to support ESM modules natively, so there is no additional code injection and the structure of the packaged code is clean(Don’t iife like Webpack)
    • There are currently only three ways that browsers can support modularity:
      1. Script tag (disadvantage: no scope concept)
      2. Script tag + iife + window + function scope (can solve the scope problem. This is the packaged product of Webpack.)
      3. ③ ESM (everything is good, the only drawback requires a higher version browser)

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 itself(A lot of injection)
    • 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

End Use Recommendation

  1. Package open source libraries: Don’t think about it, rollup will be a better choice for you

    • Rollup itself also supports many plug-ins and the ecosystem is mature enough to handle almost any scenario
  2. Packaged applications: Personal recommendation, depending on whether your application needs to be compatible with older browsers

    For chorme, for example, more than chorme63 is required

    If you do not consider compatible with older browsers, you are advised to use Vite to develop applications.

    • Dev development: Vite provides dev servers and hot updates much faster than Webpack, making dev development a much better experience
    • PRD production: Vite production package, actually usedrollup, the author has used Vite on the real project, the development experience is great,The production package is much smaller than webpack, with a nice performance improvement
      • Vite advantages and characteristics, can see me another: Vite principle analysis – Dev (compared to webpack)
    • Theoretically chorme63 above can be used out of the box, chorme63 below is not completely unable to use, need to add their own polyfill or Vite plug-in (compatible with vite recommended practice)

The length is a little long, it is best to have a full understanding of Webpack first, in this article, you will better understand and comprehensive comparison. To understand Webpack, you can first read the author’s previous webPack product analysis and principle (including CJS/ESM/code separation/lazy loading).

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, thank you for your love of learning, thank you for your thumbs up!