Learning the JavaScript language, you will find that it has two types of modules.
One is the ES6 module, referred to as ESM; the other is Node.js dedicated CommonJS module, referred to as CJS. The two modules are not compatible.
Many people use Node.js and only require()
load modules, but don't know what to do when they encounter ES6 modules. This article will talk about how to use ES6 modules in Node.js.
The difference between the two modules
There is a big difference between ES6 modules and CommonJS modules. The syntax of the module being loaded is different. CJS modules are loaded with require()
and exported with module.exports
. But ESM modules are loaded with import
and exported with export
.
require()
is doing synchronous loading, the following statements must wait for this statement to be executed before it is executed. But import
is doing asynchronous loading, to be precise it has a static code analysis and dependency resolution phase.
The distinction of Node.js
Node.js requires ES6 modules to use the .mjs
file extension. In other words, as long as the import
or export
is used in the script file, the .mjs
file extension should be used. When Node.js encounters a .mjs
file, it considers it to be an ES6 module, and strict mode is enabled by default, and it is not necessary to specify it at the top of each module file "use strict"
. If you do not want to change the file extension to .mjs
, you can specify the type
field as a module
in the project file's package.json
.
JSON
{
"type": "module"
}
Once set, the JS scripts in the directory will be interpreted as ES6 modules.
bash
# Interpreted as ES6 Module
$ node my-app.js
If you still want to use the CommonJS module at this time, you need to change the file extension of the CommonJS script to .cjs
. If there is no type
field, or the type
field is commonjs
, the .js
script will be interpreted as a CommonJS module.
Summarized in one sentence: .mjs
files are always loaded as ES6 modules, .cjs
files are always loaded as CommonJS modules, and the loading of .js
files depends on the settings of the type
field inside the package.json
.
Note: Try not to mix ES6 modules and CommonJS modules. The require()
cannot load the .mjs
file, and an error will be reported. Only the import
can load the .mjs
file. Conversely, require()
cannot be used in .mjs
files, they should use import
.
CommonJS module loads ES6 modules
require()
cannot load ES6 modules and an error will be reported in the CommonJS module. You can only use the import()
method to load ESM.
JavaScript
(async () => {
await import('./my-app.mjs');
})();
The above code can be run in the CommonJS module.
One reason why require()
does not support ES6 modules is that, it is loaded synchronously, and the top-level await
statement can be used inside ES6 modules, which would cause the module not to be able to be loaded synchronously.
ES6 modules load CommonJS modules
In the ES6 module, import
can load CommonJS modules, but the CJS module should be loaded altogether, and can not just load a specific single exported object.
JavaScript
// Correct
import packageMain from 'commonjs-package';
// Report an error
import { method } from 'commonjs-package';
This is because ES6 modules need to support static code analysis, and the export interface of CommonJS modules is module.exports
, which is an object that cannot be statically analyzed, so it can only be loaded as a whole.
To load a specific single exported object, it can be written as follows.
JavaScript
import packageMain from 'commonjs-package';
const { method } = packageMain;
Support two formats of modules at the same time
It is easy for a module to support both CommonJS and ES6 formats. If the original module is in ES6 format, you need to give an overall output interface, such as export default obj
, so that CommonJS can be loaded with import()
.
If the original module is in CommonJS format, a packaging layer can be added.
JavaScript
import cjsModule from '../index.js';
export const foo = cjsModule.foo;
The above code first enters the CommonJS module as a whole and then exports the named interface as needed. You can change the extension of this file to .mjs
, or put it in a subdirectory, and put a separate package.json
file in this subdirectory, specifying {type: "module" }
.
Another approach is to specify the respective loading entry of the two format modules in the exports
field of the package.json
file.
"exports":{
"require": "./index.js",
"import": "./esm/wrapper.js"
}
The above code specifies require()
and import
, and loading the module will automatically switch to a different entry file.
Top comments (0)