Webpack learning - how it works

Following the last chapter Article This paper introduces the basic concept of webpack, the whole process, and the function of some events broadcast in the process of packaging. This article mainly talks about how to output the generated chunk file into a specific file. There are two cases of synchronous and asynchronous to analyze the output file using the webpack version: 3.8.0.

Module file show.js

    function show(content) {
        window.document.getElementById('app').innerText = 'Hello,' + content;
    }

    // Export show function through CommonJS specification
    module.exports = show;

Synchronous loading

// main.js

import show from './show';

show('TWENTY-FOUR K');

Generated bundle file

// Webbackbootstrap startup function
// Modules store an array of all modules. Each module is a function
(function(modules) {
    var installedModules = {}; // Cache installed modules to improve performance
    //Load the module corresponding to moduleId (index) in the modules array passed in, similar to node's require statement
    function __webpack_require__(moduleId) {
        // Check whether it has been loaded, if any, take it directly from the cache installedModules
        if(installedModules[moduleId]) {
            return installedModules[moduleId].exports;
        }
        // If not, create a new module directly and store it in the cache installedModules
        var module = installedModules[moduleId] = {
            i: moduleId, // index corresponding to modules, that is, moduleId
            l: false, // Flag module loaded
            exports: {}
        };
        // Execute the corresponding module function and pass in the required parameters
        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
        // Set flag to true
        module.l = true;
        // Return the export value of this module
        return module.exports;
    }
    // Store modules array
    __webpack_require__.m = modules;
    // Storage cache installedModules
    __webpack_require__.c = installedModules;
    // Define getter function for Harmony export
    __webpack_require__.d = function(exports, name, getter) {
        if(!__webpack_require__.o(exports, name)) {
            Object.defineProperty(exports, name, {
                configurable: false,
                enumerable: true,
                get: getter
            });
        }
    };
    // It is used for getdefaultexport function that is compatible with uncoordinated modules. It declares module.default or non module as a property of getter 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;
    };
    // Tool function, hasOwnProperty
    __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
    // publicPath in the webpack configuration, used to load the separated asynchronous code
    __webpack_require__.p = "";
    // Use the "webpack" require "function to load the module with index 0, and return the module with index 0, which is the corresponding file of main.js of the main entry file. The meaning of" webpack "require" is the corresponding index of the startup module
    return __webpack_require__(__webpack_require__.s = 0);
})
/************************************************************************/
([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
// Set "esModule" to true to affect the return value of "webpack" require ". N function
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
// Load the dependent module with index 1 synchronously
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__show__ = __webpack_require__(1);
// Get the export of the dependent module with index 1
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__show___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__show__);
// Synchronous loading


__WEBPACK_IMPORTED_MODULE_0__show___default()('wushaobin');

/***/ }),
/* 1 */
/***/ (function(module, exports) {

function show(content) {
  window.document.getElementById('app').innerText = 'Hello,' + content;
}

// Export show function through CommonJS specification
module.exports = show;


/***/ })
]);

Asynchronous loading

// main.js

// Load show.js asynchronously
import('./show').then((show) => {
  // Execute show function
  show('TWENTY-FOUR K');
});

Two files, 0.bundle.js and bundle.js, will be generated after the web pack. The reason for this is that show.js can be introduced in the form of asynchronous loading, which is also an optimization method to separate the code and reduce the file volume. The analysis of the two files is as follows.

0.bundle.js

// Load the modules contained in this file (0.bundle.js). Webbackjsonp is used to install modules from asynchronous loaded files and mount them to global (bundle.js) for other files
webpackJsonp(
// Module id stored in other files
[0],[
// Modules included in this document

/***/ (function(module, exports) {

function show(content) {
  window.document.getElementById('app').innerText = 'Hello,' + content;
}

// Export show function through CommonJS specification
module.exports = show;


/***/ })
]);

bundle.js

 (function(modules) { // Webbackbootstrap startup function
    // Install JSONP callback for block loading
    var parentJsonpFunction = window["webpackJsonp"];
    // chunkIds the chunkId corresponding to the module to be installed stored in the asynchronous load file (0.bundle.js)
    // The moreModules asynchronous load file (0.bundle.js) holds the list of modules to be installed
    // The executeModules asynchronous load file (0.bundle.js) stores the index corresponding to the modules to be installed and executed after installation
    window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
        // Add "moreModules" to the modules object,
        // Mark all modules corresponding to chunkIds as loaded successfully
        var moduleId, chunkId, i = 0, resolves = [], result;
        for(;i < chunkIds.length; i++) {
            chunkId = chunkIds[i];
            if(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];
            }
        }
        if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);
        // implement
        while(resolves.length) {
            resolves.shift()();
        }

    };

    // Cache installed modules
    var installedModules = {};

    // Store the loading status of each chunk
    // The key is the id of chunk, and a value of 0 means the loading is successful
    var installedChunks = {
        1: 0
    };

    // Load the module corresponding to the moduleId (index) in the modules array passed in. It is similar to the node's require statement, as above. It is omitted here
    function __webpack_require__(moduleId) {
        ...
    }

    // It is used to load the file corresponding to the chunk to be loaded asynchronously,
    // The chunk id needs the id corresponding to the chunks loaded asynchronously. A promise is returned
    __webpack_require__.e = function requireEnsure(chunkId) {
        // Get the loading status of the chunk file corresponding to the chunkId from installedChunks
        var installedChunkData = installedChunks[chunkId];
        // If the loading status is 0, it means that the chunk has been loaded successfully, and the promise resolve is returned directly
        if(installedChunkData === 0) {
            return new Promise(function(resolve) { resolve(); });
        }

        // When installedChunkData is not empty and 0, it means that chunk is loading on the network
        if(installedChunkData) {
            return installedChunkData[2];
        }

        // If the installedChunkData is empty, it means that the chunk has not been loaded. Load the file corresponding to the chunk
        var promise = new Promise(function(resolve, reject) {
            installedChunkData = installedChunks[chunkId] = [resolve, reject];
        });
        installedChunkData[2] = promise;

        // Through dom operation, insert a script tag into html head to load the javascript file corresponding to chunk asynchronously
        var head = document.getElementsByTagName('head')[0];
        var script = document.createElement('script');
        script.type = "text/javascript";
        script.charset = 'utf-8';
        script.async = true;
        script.timeout = 120000;
        // The nonce property of the HTMLElement interface returns the encrypted number that is used only once, and is used by the content security policy to determine whether the request is allowed to be processed.
        if (__webpack_require__.nc) {
            script.setAttribute("nonce", __webpack_require__.nc);
        }
        // The path of the file is spliced by the configured publicPath and chunkid
        script.src = __webpack_require__.p + "" + chunkId + ".bundle.js";
        // Set the maximum timeout for asynchronous loading
        var timeout = setTimeout(onScriptComplete, 120000);
        script.onerror = script.onload = onScriptComplete;
        // Callback when script loading and execution are complete
        function onScriptComplete() {
            // Prevent memory leaks
            script.onerror = script.onload = null;
            clearTimeout(timeout);
            
            var chunk = installedChunks[chunkId];
            // Judge whether the chunk corresponding to chunkid is installed successfully
            if(chunk !== 0) {
                if(chunk) {
                    chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));
                }
                installedChunks[chunkId] = undefined;
            }
        };
        head.appendChild(script);

        return promise;
    };

    // Multiple properties and methods will be set for webpack require, as above, omitted here
    

    // Error functions loaded asynchronously
    __webpack_require__.oe = function(err) { console.error(err); throw err; };

    // Load entry module and return exports
    return __webpack_require__(__webpack_require__.s = 0);
 })
/************************************************************************/
 ([
// Store the modules that are not loaded asynchronously and loaded with the execution of the entry file, that is, the synchronized modules
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
// Load the chunk corresponding to show.js asynchronously through "webpack" and "require"
// Load show.js asynchronously
__webpack_require__.e/* import() */(0).then(__webpack_require__.bind(null, 1)).then((show) => {
  // Execute show function
  show('Webpack');
});


/***/ })
 ]);

summary

Here we compare the simple application of synchronous loading and asynchronous loading to analyze the differences between the two cases. We find that the asynchronous loading bundle.js is basically similar to the synchronous bundle.js, which simulates the node.js's require statement to import the module. The difference is that there is an additional \\\\\\\ The files corresponding to the chunk s that need to be loaded asynchronously, as well as a wepackJsonp function, are used to install modules from the asynchronously loaded files.

Tags: Javascript Webpack network

Posted on Wed, 04 Dec 2019 00:32:29 -0500 by madhouse92