This is not meant to be a comprehensive overview of ES modules and CommonJS modules — I do not go into depth about what modules are and how they work. Rather, it is meant to highlight the differences between ES modules and CommonJS modules and how you can use them together.
This is part two of a four part series.
- The three differences between require and import in Node.js
- Using ES modules with CommonJS modules in Node.js
- Using ES modules with CommonJS modules in the browser
- Using ES modules with CommonJS modules with webpack
Check out full code examples here: https://github.com/arcticmatt/javascript_modules/tree/master/node.
What is a module?
A module is just a single JavaScript file.
package.json
“type
” field
This field determines whether JavaScript files, i.e. files ending in .js
, are treated as ES modules or CommonJS modules.
Example
See the last field. Valid values are:
"module"
"commonjs"
If it is not specified, it implicitly defaults to "commonjs"
.
{
"name": "es_module_playground",
"version": "1.0.0",
"description": "Testing ES Modules",
"main": "module1.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"type": "commonjs"
}
"commonjs"
Behavior
.cjs
files are treated as CommonJS modules.js
files are treated as CommonJS modules.mjs
files are treated as ES modules
"module"
Behavior
.cjs
files are treated as CommonJS modules.js
files are treated as ES modules.mjs
files are treated as ES modules
As you can see, the difference is how .js
files are treated.
Mixing ES modules and CommonJS modules
Here are the general rules regarding what doesn’t work, accompanied by relevant errors. “Doesn’t work” means that it results in an error if you run the code with node
from the command line.
Remember from above that, if "type": "module"
, then an ES module is any .js
or .mjs
file. If "type": "commonjs"
, then an ES module is any .mjs
file.
- You can only use
import
andexport
in an ES module. Specifically, this means you can only useimport
andexport
in a.mjs
file, or in a.js
file if"type": "module"
.Cannot use import statement outside a module
Unexpected token ‘export’ - You cannot use
require
in an ES module, you must useimport
.ReferenceError: require is not defined
- You cannot use
require
to load an ES module.Error [ERR_REQUIRE_ESM]: Must use import to load ES Module
So, what does work?
- An ES module can import exports from a CommonJS module. As far as mixing goes, that’s it.
For example, if "type": "commonjs"
, then this example works, i.e. node module1.mjs
will run without any errors.
// module1.mjsconsole.log("require module1");import obj from "./module2.js";
console.log(`module2 = ${obj.module2}`);// module2.jsconsole.log("require module2");
exports.module2 = "require module2";
If "type": "module"
, then this example works, i.e. node module1
will run without any errors.
// module1.jsconsole.log("require module1");import obj from "./module2.cjs";
console.log(`module2 = ${obj.module2}`);// module2.cjsconsole.log("require module2");
exports.module2 = "require module2";
As a reminder, full code examples for these rules can be found here: https://github.com/arcticmatt/javascript_modules/tree/master/node.