In recent years, the front-end has been booming, with the transition from template engine calls to framework components, and many people may be confused by the difference between a component and a module
Because it looks like components and modules have a lot in common
- Is a collection of pieces of code, that is, are encapsulated
- Components can call each other, and modules can call each other
But their responsibilities are different, and in a nutshell:
Components solve the problem of code reuse, modules solve the problem of divide and conquer
If you don’t quite understand the above concepts, it doesn’t affect the rest of the reading, but you should know what a module is
JavaScript modules evolve slowly because the language was not modularized to begin with (thanks to the NodeJs ecosystem)
But in recent years, the front end of the boom, also let modular gradually standardized. While many people may not be aware of modularity developments over the past decade, this article will give you a brief overview
Script tags and closures
In the early days, JavaScript was embedded in HTML
<script>
console.log('UFO')
</script>
Copy the code
What’s the problem with that?
For example, if I download a module from the Internet and the function has thousands of lines of code, let’s assume only a few lines here, then I want to use its addition function, I will copy it directly:
<body>
<script> // Externally introduced code
var count = 0
function add() {
return ++count
}
</script>
<script> // My code
var box = docoment.getElementById('#box')
box.onclick = function () {
box.innerText = add()
}
// Since I didn't know count existed, there are thousands of lines of code
// Do something else that might change the value of count and break the code
var count = 10
</script>
</body>
Copy the code
The above problem is obvious. The variables on which the encapsulation function depends cannot be accessed externally.
We can solve this problem easily with IIFE
Execute functions now (IIFE)
Executing the function immediately creates a closure
(function() {
var a = 1}) ()console.log(a) //=>undefined
Copy the code
External variables cannot be accessed directly from inside
CDN versions of frameworks, such as Vue and JQuery, are usually made available to users in this way
(function (global, factory) {
global.Vue = factory()
global.$ = factory()
})(window.function(){
/ /...
})
Copy the code
Mount $and Vue to the Window object by executing the function immediately
Internal encapsulation of the logic function, external only exposed a way of use, greatly avoid accidental change of context
$('app')
new Vue()
Copy the code
So far, we’ve solved the scope problem. But there is another problem
How do you place them in HTML?
The following script will throw an error
<script>
new Vue() //throw Error
</script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
Copy the code
Obviously, the browser normally parses the script from top to bottom, so you must import the CDN link before using it
This is usually fine, if it’s a CDN package provided by a third party, you can put them in the tag.
However, a project may have multiple scripts wrapped by itself or colleagues. These scripts have a strong sequential logic
When a project introduces dozens or even hundreds of self-built modules, it can be confusing:
- The module has no name and is easy to distinguish
- Dependency management is difficult to manage
- Even when mounted to a Window, there are too many global variables
CommonJs
Js has no concept of module since its birth, and the emergence of CJS has revolutionized Js on the road of modularization
Let’s look at an example of CJS:
var count = 0
function add() {
count ++
}
module.exports = add
Copy the code
var add = require('./add.js')
setInterval(() = > {
add()
}, 1000);
console.log(count) //Error
Copy the code
As you can see, it solves the following problem:
- No scope contamination
- Clear dependencies
- Clearly know the reference module and its location
In this case, CJS has solved most of the pain points.
Unfortunately, the CJS specification only supports the Node environment and does not run in browsers, since CJS was originally focused on the server side
Also, the synchronous loading of CJS makes this solution unacceptable to browsers, so we still need an asynchronous module specification that can run on browsers
AMD
AMD stands for Asynchronous Module Definition.
AMD also uses the require() statement to load modules, but it is different from CJS. Since the load is asynchronous, either the callback function is passed in or the finished module is loaded
require(['add'].function (add) {
setInterval(() = > {
add()
}, 1000)})Copy the code
The AMD specification cannot be used directly on the browser side, and libraries that implement it need to be introduced. For example the require. Js
CMD
The representative library for CMD is SeaJs
Require.js was introduced early and complies with the AMD specification
SeaJs is proposed by Yubo, it complies with both AMD specification and CJS specification, so it is called CMD
- For dependent modules, AMD executes early and CMD executes late
- CMD advocates dependency nearby, AMD advocates dependency front
The jade uncle knows the original text
// CMD
define(function(require.exports.module) {
var a = require('./a')
a.doSomething() // Omit 100 lines here
var b = require('./b') // Dependencies can be written nearby
b.doSomething()
// ...
})
// AMD's default recommendation is
define(['./a'.'./b'].function(a, b) {
Dependencies must be written in the beginning
a.doSomething()
// Omit 100 lines here
b.doSomething()
/ /...
})
Copy the code
UMD
Strictly speaking, UMD does not belong to a set of specifications and is mainly used to deal with differential compatibility between CommonJs, AMD, and CMD
For example, the CDN version of vue@2.6.14 uses the UMD specification:
(function(global, factory) {
typeof exports= = ='object' && typeof module! = ='undefined' ?
module.exports = factory() :
typeof define === 'function' && define.amd ?
define(factory) :
(global = global || self, global.Vue = factory()); } (this.function() {
/ /...
})
Copy the code
And now the CDN version of the third party library, also use UMD to accommodate differences
ES Module
Since ECMAScript2015 / ECMAScript6 JavaScript native module concept is introduced
This is also the most popular modular solution:
import add from './add.js'
Copy the code
However, this approach does not run directly in the Node environment, because Node is probably biased towards the server side
CommonJs specification has been able to meet the needs of the service side, but front-end engineering can not be separated from Node, and there must be a modular development mode
Packaging tools such as WebPack, Rollup, Parcel, etc. translate ESM into other module specifications
Browsers now support native import as well
<script type="module">
import add from './add.js'
</script>
Copy the code
As a result, tools like Vite, which use native import imports, leave the packaging to the browser in the development environment and save a lot of time compared to traditional packaging tools
So far, the ESM has also become a common modular solution for browsers and servers
It will be interesting to see which future versions of Node will support imports natively