Go on about CommonJS for a minute
Common knowledge is Common knowledge, Common knowledge is Common knowledge, Common knowledge is Common knowledge, Common knowledge is Common knowledge, Common knowledge is Common knowledge. Obviously not. This is not common sense. I originally thought that commonJS was an open source JS library that was easy to use and filled with common front-end methods. However, I was wrong. Not only is commonJS not a library, but it is an invisible thing. Like school discipline, used to standardize JS programming, shackle the front end. Like Promise, it is a specification, and while there are many open source libraries that implement these specifications, this specification can also be implemented with our JS capabilities.
CommonJs specification
So what does CommonJS regulate? To explain this specification, start with the nature of JS. JS is a literal scripting language that is compiled and run at the same time, so there is no concept of modules. So CommonJS is a specification that exists in order to perfect the lack of JS in this respect.
CommonJS defines two main concepts:
require
Function to import the modulemodule.exports
Variable used to export the module
However, browsers don’t support either of these keywords, so I think that’s why browsers don’t support CommonJS. If you want to use CommonJs in a browser, you need a compiler library like Browserify to help you build CommonJs into a browser-supported syntax that implements require and exports.
So what can CommonJS be used for? Although CommonJS cannot be used directly in browsers, NodeJS can be implemented based on the CommonJS specification. In NodeJS, we can import and export modules directly using the two keywords require and exports.
Implementation of CommomJS module in Nodejs
require
Let {count,addCount}=require(“./utils”) So what happens when you import? First of all, we must parse the path. The system gives us an absolute path. The relative path we write is for us to see, and the absolute path is for the system to see. So the first thing require does is parse the path. We can write very succinctly, only need to write the relative path and file name, even the suffix can be omitted, ask require to help us match to find. The first step in require is to parse the path to get the contents of the module:
- If it’s a core module, for example
fs
, directly back to the module - If it is with a path such as
/
.. /
And so on, concatenate an absolute path and read the cache firstrequire.cache
Then read the file. If no suffix is added, it is automatically suffixed and identified one by one..js
Parse to a JavaScript text file.json
Parsing JSON objects.node
Parse to a binary plug-in module
- Modules are cached after first loading
require.cache
In, so multiple loadsrequire
, the resulting object is the same. - When executing module code, the module is wrapped in the following mode so that the scope is within the module.
(function(exports, require, module, __filename, __dirname) {// module code is actually here});Copy the code
Nodejs official explanation, you can refer to
module
Having said what require does, what does the module that require triggers do? We look at usage, first to write a simple export module, write the module, only need to export parameters, join the module. Exports.
let count=0
function addCount(){
count++
}
module.exports={count,addCount}
Copy the code
And then add according to require when executing code, so our code actually looks like this:
(function(exports, require, module, __filename, __dirname) {
let count=0
function addCount(){
count++
}
module.exports={count,addCount}
});
Copy the code
What is happening to the module when require? We can interrupt it in vscode:
Based on this breakpoint, we can sort out:
In yellow, require, which is the method we’re calling
The work of the Module circled in red
Module._compile Module.extesions.. js Module.load tryMouduleLoad Module._load Module.runMainCopy the code
Circled in blue is what NodeJS does, which is the NativeModule that executes module objects.
We all know that in JS, the function is called in the stack mode, i.e., near before out, i.e., require this function is triggered, the runtime in the figure is run from bottom to top. So the blue box runs first. I’ll dig up some of his code, study it.
NativeModule native code key code, which is used to encapsulate modules.
NativeModule.wrap = function(script) {
return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
};
NativeModule.wrapper = [
'(function (exports, require, module, __filename, __dirname) { '.'\n}); '
];
Copy the code
Once the NativeModule triggers module. runMain, our modules will start loading. Let’s read from bottom to top.
Module._load
, is to create a new onemodule
Object, and then put the new object inModule
In cache.var module = new Module(filename, parent); Module._cache[filename] = module; Copy the code
tryMouduleLoad
And then the new onemodule
Object starts parsing the imported module contentmodule.load(filename); Copy the code
- The new
module
The module. load object inherits from the module. load method, which parses the type of the file and executes it separately Module.extesions.. js
This does two things: it reads the file, and it’s ready to compileModule._compile
So how does JS run text? There are three ways for javascript to turn text into an executable:-
The eval method eval (” the console. The log (” aaa “) “)
-
New Function() template engine
let str="console.log(a)" new Function("aaa",str) Copy the code
-
Node executes strings. We use advanced VMS
let vm=require("vm") let a='console.log("a")' vm.runInThisContext(a) Copy the code
Here the Module is compiled as a VM, first wrapped, then executed, and finally returned to require, so we can get the result of execution.
var wrapper = Module.wrap(content); var compiledWrapper = vm.runInThisContext(wrapper, { filename: filename, lineOffset: 0, displayErrors: true }); Copy the code
-
Because all modules are executed after encapsulation, the imported module can only be accessed through the module.exports interface.
To summarize
The _load method for Module is to create a cache of new modules in the current Module, so that the next time you require it, you can return to it without executing it again. Then the new Module’s load method loads and executes code via the VM to return the object to require.
Because of this, if the value of export is a parameter rather than a function, the change of the value of the current parameter will not cause the change of Export, because the parameter assigned to export is static and will not cause a second run.
CommonJs module and ES6 module differences
Usage scenarios
CommonJS is mostly used on the server side because of the limitations of the keyword. For ES6 module loading, there are already browsers that support this feature, so ES6 can be used in browsers. If you encounter a browser that does not support ES6 syntax, you can choose to translate it into ES5.
Syntax differences
ES6 is also a JavaScript specification. The difference between ES6 and CommonJs module is obvious. Firstly, the code is not the same.
commonJS | ES6 | |
---|---|---|
Supported keywords | arguments,require,module,exports,__filename,__dirname |
import,export |
The import | const path=require("path") |
import path from "path" |
export | module.exports = APP; |
export default APP |
Imported objects | modify | Can’t be modified at will |
The import number | Feel free torequire , but except for the first time, everything else is fetched from the module cache |
Import in the header |
** Attention everyone! To highlight! Nodejs is the CommonJS parent, so some ES6 features are not supported, such as the module import and export keywords. If you run nodeJS, expect a red error
Load difference
In addition to syntax differences, the nature of the modules they reference is different. Although both are modules, the structure of the modules varies greatly.
In ES6, if you want to test in a browser, you can use the following code:
//utils.js
const x = 1;
export default x
Copy the code
<script type="module">
import x from './utils.js';
console.log(x);
export default x
</script>
Copy the code
The first thing to do is to give the script type=”module” to indicate that it is an ES6 module, and this tag is loaded asynchronously by default, meaning that the page is fully loaded before being executed. The code will not run without this tag. Then you can write import and export directly.
Several problems with ES6 module import:
- The same module can only be introduced once, for example
x
If it is already imported, it cannot be imported from utilsx
- Different modules introduce the same module, this module will only be the first time
import
In the execution. - The introduced module is a reference to a value and is dynamic, changing other related values as well
- Do not break the links of imported objects, such as mine
count
I can’t change it, because it’s imported, and I can only change it incount
Modify the module where it resides. But if thecount
Is an object, so you can change the properties of the object, for examplecount.one=1
But don’tcount={one:1}
.
If you look at this example, I wrote a little test to change the value of object, and you can see that the initial value of count in utils.js should have been 0, but I ran addCount so the value of count changed dynamically, so the value of count became 2.
let count=0
function addCount(){
count=count+2
}
export {count,addCount}
Copy the code
<script type="module">
import {count,addCount} from './utils.js'; AddCount () console.log(count); </script>Copy the code
Contrast this with the commonJS module reference, which has the following features:
- As explained in the previous section, a fixed value exported by a module is a fixed value and will not change due to subsequent modifications, unless instead of exporting a static value, a function is called dynamically every time it is called, and the value is updated every time.
- The imported object can be modified at will and is just a copy of the imported module.
If you want to further study, you can refer to Ruan’s ES6 introduction – Module load implementation.
CommonJS module summary
CommonJS modules can only be run in environments that support the CommonJS specification. Nodejs is developed based on the CommonJS specification, so it can run perfectly. Nodejs does not support ES6 module specifications. So nodeJS server development is usually written using the CommonJS specification.
CommonJS modules import require and export module.exports. Note that if the exported object is a static value and the value is very large, it may be changed later. Use functions to dynamically obtain the exported object; otherwise, the modified value cannot be obtained. The imported parameters can be changed at will, so be careful when using them.