First, why modularity

In the early days of front-end development, we often encountered a problem where variables would pollute the whole world by introducing scripts as follows:

a.js

function log() {
    console.log('a')
    return 'a'
}
Copy the code

b.js

function log() {
    console.log('b')
    return 'b'
}
Copy the code

index.html

<meta charset="utf-8" />
<script src="./a.js"></script>
<script src="./b.js"></script>
<script>
    console.log('log: ', log()) // b
</script>
Copy the code

For example, we found that we could not call the log method of file A in any case, because the original writing method would lead to global log contamination. Therefore, especially in the case of large projects that reference many third-party libraries, it is difficult to detect the problem. So a modular solution to this problem.

Currently, there are AMD,CMD,UMD,CommonJs,ES Module solutions on the market. Here we only introduce CommonJs and ES Module

In fact, AMD,CMD and UMD are the earliest modular solutions, representing class libraries such as require.js and sea-.js. I will not give more introduction here, because the front-end development is mainly to build compiled code with packaging tools. The mainstream packaging tools support Commonjs and ES Module, so other solutions are not covered

Second, the CommonJs

CommonJs was first introduced to solve the problem of polluting the global environment after node.js appeared.

CommonJs imports modules via the require method and exports via module.exports and exports

Such as:

a.js

module.exports = {
    module: 'a'
}
Copy the code

b.js

module.exports = {
    module: 'b'
}
Copy the code

index.js

const a = require('./a.js')
const b = require('./b.js')
console.log('a: ', a)
console.log('b: ', b)
Copy the code

The result of this run is to print a and B, respectively

Let’s parse the source code:

(() = > {
    var o = {
            847: o= > {
                o.exports = { module: "a"}},996: o= > {
                o.exports = { module: "b" }
            }
     },
     r = {};

    function e(t) {
        var s = r[t];
        if (void 0! == s)return s.exports;
        var n = r[t] = {
            exports: {}};return o[t](n, n.exports, e), n.exports
    }
    
    (() = > {
        const o = e(847),
            r = e(996);
        console.log("a: ", o), console.log("b: ", r)
    })()
})();
//# sourceMappingURL=main.js.map
Copy the code

We can see that the implementation principle is to wrap all the code in a self-executing function, and then implement the modularity solution by converting the imported module into an object

CommonJs: CommonJs: CommonJs

  1. Modular solutions are dynamic, that is, modules are introduced at the time of invocation
  2. CommonJs caches modules that have been called before

Void 0 (undefined); void 0 (undefined); void 0 (undefined)

Let’s change the a file to:

const getMes = require('./b')
console.log('I'm file A')
exports.say = function() {
    const message = getMes()
    console.log(message)
}
Copy the code

B file changed to:

const say = require('./a')
const object = {
    author: 'I'm not an alien'
}
console.log('I'm file B')
console.log('Print a module', say)

setTimeout(() = > {
    console.log('Asynchronous print A module', say)
}, 0)

module.exports = function() {
    return object
}
Copy the code

The compiled source code is as follows:

(() = > {
    var o = {
            847: (o, n, e) = > {
                const t = e(996);
                console.log("I'm file A."),
                    n.say = function() {
                        const o = t();
                        console.log(o)
                    }
            },
            996: (o, n, e) = > {
                const t = e(847),
                    s = {
                        author: "I'm not an alien"
                    };
                console.log("I'm file B."),
                    console.log("Print module A", t),
                    setTimeout((() = > {
                        console.log("Asynchronous print A module", t)
                    }), 0),
                    o.exports = function() { return s }
            }
        },
        n = {};

    function e(t) {
        var s = n[t];
        if (void 0! == s)return s.exports;
        var r = n[t] = {
            exports: {}};return o[t](r, r.exports, e), r.exports
    }
    e(847), e(996), console.log("Node entry file")
})();
//# sourceMappingURL=main.js.map! [] ()
Copy the code

The result after running is as follows:

  • First we will load the A file (the corresponding number is 847)

      var s = n[t];   
            if (void 0! == s)return s.exports;
            var r = n[t] = {
                exports: {}};Copy the code
  • From the above loading code, we can know that when module A is loaded for the first time, s=undefined, it will allocate an empty object containing exports to module A, and then export the property of the empty object. Because the first line of module A calls module B and repeats the steps of loading module A. Module B’s say constant is an empty object.

  • Then execute in order, output I am b file, then output print module A {}

  • The setTimeout macro task is then executed, so setTimeout is printed at the end

  • Finally, in module B, we do an export and update exports through the cache object passed by method E

  • Then print the I am A file and the Node entry file in that order

  • {say:Fn} {say:Fn} {say:Fn} {say:Fn} {say:Fn} {say:Fn} {say:Fn} {say:Fn} {say:Fn} {say:Fn}

Exports ={} exports={} exports={} exports={

We changed file A to:

const getMes = require('./b')
console.log('I'm file A')
exports = {
    say: function() {
        const message = getMes()
        console.log('a file say', message)
    }
}
Copy the code

Compiled as follows:

From here we can see that the essence of the reason is that there is no source code generated export, this may be a bit different from other technical articles, that is, I want to illustrate a point, do not look at the source code to do analysis more or less is a bit of a mistake.

Third, ES Module

The essential difference between Es Module and CommonJs is that CommonJs is dynamically loaded and Es Module is statically compiled. This limits the tree shaking of Es Modules in webpack to reduce code. Dynamically executing CommonJs is not tree shaking.

Change file A to:

export default {
    a: true
}
Copy the code

B file changed to:

export default {
    b: true
}
Copy the code

Index file changed to:

import a from './a.js'
import b from './b.js'

console.log('a: ', a)
console.log('b: ', b)
Copy the code

The compiled source code is as follows:

(() = > {
    "use strict";
    console.log("a: ", { a:!0 }), console.log("b: ", { b:!0 })
})();
//# sourceMappingURL=main.js.map
Copy the code

Let’s explore how Module dependencies are handled in ES Module

A file was changed to:

import b from './b'
console.log('A module load')
export default function say() {
    console.log('hello , world')}Copy the code

B file changed to:

console.log('B module load')
export default function sayhello() {
    console.log('hello,world')}Copy the code

The index file is:

console.log('Main.js begins execution')
import say from './a'
import say1 from './b'
console.log('Main.js executed')
Copy the code

Compiled as follows:

(() = > {
    "use strict";
    console.log("B module loading"), console.log("Module A loading"), console.log("Main.js starts execution"), console.log("Complete execution of main.js")
})();
//# sourceMappingURL=main.js.map
Copy the code

We can draw the conclusion that:

  1. Import Takes precedence over imported modules
  2. Unused code is not compiled into the code that is eventually executed
  3. ES module will analyze module dependencies during preloading and execute modules in the form of deep traversal

Four, summary

By interpreting the differences between CommonJs and ES Module from the perspective of source code, we can have a clearer understanding of the similarities and differences between them. In the author’s opinion, simply reading long articles on the Internet to understand the differences between them is not conducive to memory and application. So reading source code is a simple and convenient way to learn

5. Reference materials

Commonjs and Es Module

Front-end modular: CommonJS,AMD,CMD,ES6

Void 0 === undefined