preface
Before I get into how it works, I want to take you through what CommonJs is. Some of you may not know what CommonJs is, some of you may have heard of it, but don’t know the relationship with the front end? You may only know a little about NodeJs, but it is a modular standard in NodeJs. What does the front end have to do with it? I want to tell you that a good front-end engineer’s stack must include NodeJs, and NodeJs has become a default skill for front-end engineers in big factories. But instead of talking about Node, this article will talk about its modular standard, CommonJs
A preliminary study
But before WE do that, two questions.
1. Why CommonJs? What problems is it used to solve? 2. Why don’t browsers use CommonJs?
To understand the first question, we need to talk about the development history of the front end. We know that for a long time, JavaScript did not have the concept of modularity, until the birth of Node.js, which brought JavaScript language to the server, faced with the file system, network, operating system and other complex business scenarios. Modularity becomes indispensable. As a result, node.js and CommonJS specifications complement and complement each other, and together they come into the sight of developers.
Why don’t browsers use CommonJs? After CommonJs came out and achieved success, the front end staff could not sit still, you can use JS back end to create a modular standard, this is not slapped us in the face, also started the path of modular exploration, at first everyone thought that we can use CommonJs as a modular standard for the front end, but later found that it does not work. Let’s see how CommonJs works to see why.
Browser modularity problem? Let’s start with how it works.
How CommonJs works
When importing a module using require(module path), Node does two things (regardless of module caching) :
-
Locate the native file through the module path and read the file contents.
-
The file’s code is executed in a function environment and the value of module.exports is returned as the result of require’s function.
These two steps make CommonJs well supported on the Node side.
You can assume that CommonJs is synchronous and must wait until the file is loaded and the code in the module is executed before proceeding backward
What if you use CommonJs in the browser?
There are some challenges when trying to put CommonJs on the browser side.
-
To load the JS file, the browser needs to fetch it remotely from the server, and the network transfer is far less efficient than reading the local file in the Node environment. Since CommonJs is synchronous, this greatly reduces performance. For example, if the module is too large, the page may be in a state of “suspended animation.”
-
If you need to read the content of JS files and put it into an environment for execution, you need the support of browser manufacturers, but browser manufacturers are not willing to provide support, the biggest reason is that CommonJs is a community standard, not an official specification, so browser manufacturers are not willing to spend time and effort to implement it.
The new specification
For these two reasons, browsers do not support modularity.
This does not mean that modularity cannot be implemented in browsers.
To implement modularity in a browser, you only need to solve the above two problems.
The solution is simple:
-
Wasting time loading JS remotely? Make it asynchronous and call a callback after loading.
-
Does the code in the module need to be placed into functions for execution? When writing modules, just put them into functions.
Based on this simple and effective idea, there are AMD and CMD specifications, which effectively solve the problem of browser modularization. (THIS article will not introduce THE AMD and CMD specifications, interested students can baidu or ask me).
Eventually, the ECMA organization referred to many of the community’s modularity standards, and finally became ES6 modularity in 2015 with the release of an official modularity standard for ES6. It is still used today. AMD and CMD also disappeared.
In one sentence: CommonJs — Not the front end but the front end revolution!
To the chase
With a general understanding of what CommonJs is, let’s move on to today’s topic.
There are now two modules: one for A.js and one for B.js. A. js is the entry file.
a.js
const b = require("./b");
b.sayHello();
Copy the code
b.js
console.log("Module B is loaded.");
exports.sayHello = function () {
console.log("hello, world!");
};
exports.name = "Strong bald head";
Copy the code
What will the node./ A.js terminal print?
// The b module is loaded
// Hello, world!
Copy the code
The output is indisputable.
Change b.JS slightly and then look at the result: B.js
console.log("Module B is loaded.");
module.exports = {
sayHello: function () {
console.log("Oh, yes, baby!); }};exports.sayHello = function () {
console.log("hello, world!");
};
exports.name = "Strong bald head";
Copy the code
Now what’s going to come out of the terminal? The answer is: module B is loaded. On, yes, babay!
Some students may be fooled, some big guys can see the answer at a glance, this is based on his internal implementation of the CommonJs specification.
Don’t worry. Let me tell you what I have to say.
First of all, the CommonJs specification puts the module’s contents into a function that executes immediately (to prevent contamination of global variables).
// We wrote the code to do this
(function(module){
Module.exports = {}
module.exports = {};
// exports adds an export, pointing to module.exports
var exports = module.exports;
// The code inside the module...
Module.exports is returned
return module.exports; }) ()Copy the code
So it’s easy to understand why the terminal output of the above code is quite different from what you might expect.
console.log("Module B is loaded.");
module.exports = {
sayHello: function () {
console.log("Oh, yes, baby!); }};exports.sayHello = function () {
console.log("hello, world!");
};
exports.name = "Strong bald head";
Copy the code
We changed the address of module.exports so that exports pointed to the same address as module.exports was initialized to. So no matter how we mount the property on exports, it has nothing to do with the exported value. Because in the end the CommonJs specification exports module.exports, not exports.
Advice:
Module. exports is not exported. If you change the address of module.exports or exports, the result will be different. If I had to write it as coexistence, I could write it this way.
module.exports.sayHello = function () {};
exports.name = "Strong bald head";
// Both operate on the same object. This is not recommended and is best exported using module.exports.
Copy the code
conclusion
NodeJs implementation of CommonJs
To implement the CommonJs specification, NodeJs does the following for the module.
- To ensure efficient execution, only necessary modules are loaded, and NodeJs only loads and executes modules when the require function is executed.
- To hide the code in the module, NodeJs puts all the code in the module into a function when executing the module, so as not to pollute global variables.
(function (module) {
// Code in the module}) ();Copy the code
- To ensure a smooth export of module content, NodeJs does the following
- Initialize a value of module.exports = {} before the module starts executing
- Module. exports is the exported value of a module
- Exports = module.exports NodeJs declares a variable exports = module.exports after initializing module. Exports
(function (module) { module.exports = {}; var exports = module.exports; // Code in modularization return module.exports; }) ();Copy the code
- In order to avoid loading the same module repeatedly, NodeJs enables module caching by default. If the loaded module has already been loaded, the exported result will be used automatically.
The article has the wrong place welcome everybody corrects, everybody has the good suggestion may the positive comment message ~, thanks!