preface

Front road has experienced a long process of modularization, according to the bosses here to write articles, made a summary and finishing of modular specification part, want to learn more about the friend can watch boat in the sea god wrote the front end of the modular (full version), want to read some friend can harvest, also hope to find useful friend can order a praise, ballpoint pen.

What is a module

  • Encapsulate a complex program into several blocks (files) according to certain rules (specifications) and combine them together
  • The internal data and implementation of a block are private, exposing only interfaces (methods) to communicate with other external modules

CommonJS

Node applications are composed of modules that follow the CommonJS module specification. Each file is a module with its own scope. Variables, functions, and classes defined in one file are private and invisible to other files. On the server side, modules are loaded synchronously at runtime. On the browser side, modules need to be compiled and packaged in advance.

The CommonJS specification loads modules synchronously, meaning that subsequent operations cannot be performed until the load is complete.

Basic syntax:

  • Exposure module:module.exports = valueexports.xxx = value
  • Introduction module:require(xxx)If the module is a third-party module, XXX is the module name. For a custom module, XXX is the module file path

However, CommonJs has a major limitation that makes it unsuitable for browser environments, and that is that the require operation is synchronous. This is not a problem on the server because all modules are stored on the local hard disk and can be loaded synchronously, and the wait time is the hard disk read time. However, for browsers, this is a big problem because modules are on the server side and the wait time can be long depending on the speed of the network, leaving the browser in a state of “suspended animation”.

So, browser-side modules, you can’t do synchronous loading, you can only do asynchronous loading, and that’s where the AMD specification came from.

AMD

Features: asynchronous loading module, allow to specify the callback function, browser side generally using AMD specifications

Require.js

Usage:

    // Define modules with no dependencies
    define(function(){
       returnModule})// Define dependent modules
    define(['module1'.'module2'].function(m1, m2){
       returnModule})// Import the usage module
    require(['module1'.'module2'].function(m1, m2){
       / / use the m1 / m2
    })
Copy the code

CMD

Features: specially used for browser side, module loading is asynchronous, module will be loaded when used

Sea-js

Usage:

    // Define modules with no dependencies
    define(function(require, exports, module){
      exports.xxx = value
      module.exports = value
    })
    
    // Define dependent modules
    define(function(require, exports, module){
      // Import dependent modules (synchronization)
      var module2 = require('./module2')
        // Introduce dependency modules (asynchronous)
        require.async('./module3'.function (m3) {})// Expose the module
      exports.xxx = value
    })
    
    // Import the usage module
    define(function (require) {
      var m1 = require('./module1')
      var m4 = require('./module4')
      m1.show()
      m4.show()
    })
Copy the code

CMD is different from AMD

The biggest difference between AMD and CMD is that the execution time of dependent modules is different, rather than the loading time or way is different, both are asynchronous loading modules.

AMD dependency front, JS can easily know who the dependency module is, immediately load;

However, CMD relies on nearby modules, which need to be parsed into a string to know which modules depend on. This is also a point that many people criticize CMD, sacrificing performance to bring convenience of development. In fact, the time to parse modules is short to be ignored.

In a word: both load asynchronously, but at different times. AMD relies on forward execution, CMD relies on close execution, delayed execution.

UMD

UMD is a mashup of AMD and CommonJS:

AMD modules evolve on a browser-first basis, loading modules asynchronously.

The CommonJS module follows the server first principle of synchronous loading and does not require unwrapped modules.

This forced people to come up with another, more generic pattern, UMD (Universal Module Definition), which wanted to solve cross-platform solutions.

UMD determines whether any module (exports) that supports Node.js exists and uses node.js module mode if it does.

Check whether AMD is supported (define exists). If AMD exists, load modules in AMD mode.

    (function (window, factory) {
        if (typeof exports === 'object') {
         
            module.exports = factory();
        } else if (typeof define === 'function' && define.amd) {
         
            define(factory);
        } else {
         
            window.eventUtil = factory();
        }
    })(this.function () {
        //module ...
    });
Copy the code

ES6 modular

The ES6 module is designed to be as static as possible, so that the module dependencies, as well as the input and output variables, can be determined at compile time. Both CommonJS and AMD modules can only determine these things at runtime. For example, a CommonJS module is an object, and you have to look for object properties when you enter it.

The ES6 Module is not supported by the browser by default, so you need to use Babel.

ES6 uses the keyword import to import modules, and the keyword export to export modules:

    /** How to export modules **/
    
    var a = 0;
    export { a }; / / the first
       
    export const b = 1; / / the second
      
    let c = 2;
    export default { c }/ / the third kind
    
    let d = 2;
    export default { d as e }// The fourth type, alias
    
    /** How to import modules **/
    
    import { a } from './a.js' // For export export, the.js suffix can be omitted
    
    import main from './c' // For export default, use main.c
    
    import 'lodash' // Just execute the lodash module without entering any values
Copy the code

Named exports versus default exports

Export {< variable >} is usually called a named export or named export, and an export is a reference to a variable.

Export default This mode is called default export or anonymous export. The exported value is a single value.

For example:

    // a.js
    let x = 10
    let y = 20
    setTimeout((a)= >{
        x = 100
        y = 200
    },100)
    export { x }
    export default y

    // b.js
    import { x } from './a.js'
    import y from './a.js'
    setTimeout((a)= >{
        console.log(x,y) / / 100
    },100)
Copy the code

Differences between ES6 modules and CommonJS modules

The CommonJS module outputs a copy of a value. The ES6 module outputs a reference to a value.

The CommonJS module outputs a copy of the value, meaning that once a value is output, changes within the module do not affect that value. Also, no matter how many times the CommonJS module is loaded, it will only run once on the first load, and any subsequent load will return a cache of the results of the first run, unless the system cache is manually cleared.

The operating mechanism of the ES6 module is different from that of CommonJS. When the SCRIPT is statically analyzed, the JS engine generates a read-only reference when encountering the module loading command import. When the script is actually executed, the script is evaluated in the set module based on this read-only reference. In other words, the IMPORT of ES6 is a bit like the “symbolic link” of Unix systems, where the original value changes and the import load value changes with it. Therefore, ES6 modules are referenced dynamically and do not cache values. Variables in modules are bound to the module in which they are located.

② CommonJS module is loaded at runtime, ES6 module is output at compile time.

CommonJS loads an object (that is, the module.exports property) that is generated only after the script runs. That is, the entire module is loaded on input, an object is generated, and methods are read from that object. This loading is called “runtime loading.”

Such as:

    / / CommonJS module
    let { stat, exists, readFile } = require('fs');
    
    / / is equivalent to
    let _fs = require('fs');
    let stat = _fs.stat;
    let exists = _fs.exists;
    let readfile = _fs.readfile;
Copy the code

The above code essentially loads the FS module as a whole (that is, all the methods that load FS), generates an object (_fs), and then reads three methods from that object. Because this object is only available at run time, there is no way to do “static optimization” at compile time.

An ES6 module is not an object, and its external interface is a static definition that is generated during the code static parsing phase. The export command explicitly specifies the output code, and the import command takes the form of a static command. That is, when you import, you can specify that an output value is loaded instead of the entire module, which is called “compile-time loading” or “static loading.”

    / / ES6 module
    import { stat, exists, readFile } from 'fs';
Copy the code

The essence of the above code is to load three methods from the FS module and none of the others. ES6 can load modules at compile time, which is more efficient than CommonJS modules. Of course, this also makes it impossible to reference the ES6 module itself because it is not an object.

Because ES6 modules are loaded at compile time, static analysis is possible. With it, you can further expand JavaScript syntax by introducing features such as macros and type systems that can only be implemented with static analysis.

In addition to the benefits of static loading, ES6 modules have the following benefits:

  • The UMD module format is no longer needed and the ES6 module format will be supported by both servers and browsers in the future. This is already being done through various tool libraries.
  • In the future, the browser’s new apis will be available in module format and will no longer have to be global variables ornavigatorObject properties.
  • Objects are no longer required as namespaces (e.gMathObject), and in the future these functions could be provided through modules.

conclusion

  1. The CommonJS specification is mainly used for server-side programming, loading modules are synchronous, this is not suitable in the browser environment because synchronization means blocking loading, browser resources are loaded asynchronously, hence the AMD, CMD solution.
  2. The AMD specification loads modules asynchronously in the browser environment, and multiple modules can be loaded in parallel. However, AMD specifications are expensive to develop, code is difficult to read and write, and semantics are not smooth in the way modules are defined.
  3. The CMD specification is similar to the AMD specification in that it is used for browser programming, relies on proximity, deferred execution, and can be easily implemented inNode.jsIn the running. However, depending on SPM packaging, the loading logic of modules is biased.
  4. ES6 in the language standard level, the realization of module function, and the implementation is quite simple, can completely replace CommonJS and AMD specifications, become a common browser and server module solution.

The above is the content of this article, welcome to put forward their own ideas, we learn and progress together, with you.

The resources

  • Front-end Modular Details (Full version)

  • ECMAScript introduction to 6

  • Nearly 10,000 words ES6 grammar knowledge supplement

  • Thoroughly understand javascript require, import, and export

  • CommonJS, AMD, CMD, ES6, require and import explanation