Webpack modular principle diagram

Why modularity is needed

Scenario 1

Student A developed module A and student B developed module B, which are referenced in the following way under the page

<script src="a.js"></script>

<script src="b.js"></script>

Copy the code

The code in module A and template B is exposed globally if module A defines a method del. Unbeknownst to student B, a method del is also defined in module B. This creates the problem of naming conflicts. As shown in figure

Scenario 2

C has developed a common tool library, utils.js, and D has developed a common component, Tab.js, which relies on utils.js. Student E needs to use tab.js developed by student D, so it needs to be referenced in the following way

<script src="util.js"></script>

<script src="tab.js"></script>

Copy the code

Student E has also developed a dailog.js which also relies on util.js. The page now references both dialog.js and Tab.js, as follows

<script src="util.js"></script>

<script src="dialog.js"></script>

<scrpt src="tab.js"></script>

Copy the code

Student E not only needs to reference all three JS files at the same time, but also must ensure that the reference order between the files is correct. Also, we can’t see the dependencies between modules directly from the above code, and if we don’t dig into Tab.js, we won’t know whether tab.js depends only on util.js, dialog.js, or both. As the project grows, the dependencies between different modules become harder to maintain and a large number of variables in many modules are exposed to the global environment.

Several implementations of modularity

There are many specifications for modularity, as follows

specification Implementation scheme
CommonJS node.js
AMD Require.js
CMD Sea.js
UMD
ES6 Module

Webpack supports CommonJS, AMD, ESModule and other modularized syntax

Modularity in WebPack

In WebPack, everything is a module. Let’s package the following code using WebPack. Through the analysis of the package code, to understand the implementation of modularity step by step.

The directory structure is as follows:

The code is as follows:

// webpack.config.js

const path = require('path');



module.exports = {

  entry: 'a.js'.

  output: {

    path: path.resolve(__dirname, "dist"),

    filename: "[name].js"

 },

 resolve: {

    modules: [path.resolve(__dirname)]

 },

 optimization: {

    minimize: false

 }

}

Copy the code
// a.js

var b = require('b');



module.exports = b.text + ' world';



Copy the code
// b.js

exports.text = 'hello';

Copy the code

Executing the webpack command in the simple directory will generate dist/output.js file in the simple directory.

// outout.js

// The code and comments are as follows



(() = > {

// All imported modules are stored in an __webpack_modules__ object, and each module requires an ID that identifies that module

  var __webpack_modules__ = ({

     847: ((module, __unsed_webpack_exports, __webpack_require__) => {

/ / module a...

     }),

     996: ((__unused_webpack_module, exports) => {

/ / module b...

     })

  })

  

  var __webpack_module_cache__ = {};



  function __webpack_require__(moduleId) {

// Check that the 847 export object does not exist in the cache to prevent module 847 from executing multiple times

     if (__webpack_module_cache__[moduleId]) {

// Return 847 exported objects from the cache

        return __webpack_module_cache__[moduleId].exports;

     }

     

// 1. Create {exports: {}}

// 2. Add the object to the cache and associate it with module ID 847

     var module = __webpack_module_cache__[moduleId] = {

       exports: {}

     }

     

// 3. Query module 847 through __webpack_modules__

// 4. Execute module 847 and pass in the newly created module 847 export object module, module. Exports, etc

     __webpack_modules__[moduleId](module, module.exports, __webpack_require__);

     

// 5. Return the exported object of module 847

     return module.exports;

  }

  

// Import module 847

  __webpack_require__(847);

}) ()

Copy the code

As we can see from the above code, all modules are stored in __webpack_modules__, and module exports are stored in __webpack_module_cache__. Each module we define can be accessed by passing in the moduleId and calling the __webpack_require__ interface to access the module and its exported objects.

When we access the export object of module 847 through the __webpack_require__ interface. The __webpack_module_cache__ object will first determine if there are any exported objects for the module, and if so, it will return. If not, yes

  • (1) Create export objects for module 847
var module = {

  exports: {}

}

Copy the code
  • (2) Add the exported object to__webpack_module_cache__In the object
__webpack_module_cahce__[moduleId] = module

Copy the code
  • (3) (4)__webpack_modules__Query module 847 and run
// Pass in the export object of module 847 and the require interface

__webpack_modules__[moduleId](module, module.exports, __webpack_require__)

Copy the code
  • (5) Return the exported object of module 847
return module.exports

Copy the code

The diagram is as follows:

  • The elements on an orange background represent data
  • The elements with a green background represent functions

conclusion

Through the modular management mode

  1. Each module is wrapped in its own local environment through functions. Modules communicate with each other through the require interface. And not through exposure to the global environment.

  2. Each module explicitly passes in dependent modules through the require interface, so the dependencies between modules are also clear. As shown in figure

a -> b -> c -> d

  • The first time the module is referenced, the require interface is called to add the exported object to the cache. And returns the added export object.

  • When the module is referenced for the second + time, when the require interface is called to query the cache object, the corresponding exported object in the cache is returned