70 %
Chris Biscardi

nodejs native esm in v14+ conditional exports, package types, and mjs

NodeJS v14 includes ES Module support unflagged. To use it you have to know

  1. what kind of package you're in
  2. which file extension you're using
  3. what conditional exports are set up for the packages you're using

What kind of package you're in

For backward-compat reasons, all packages are CommonJS by default. You can make your package an ES Modules package by putting type: "module" in your package.json.

package.json
json
{
...
"type": "module",
...
}

CommonJS Packages

In a CommonJS package, all .js files are cjs format by default and thus would use require and other CommonJS idioms.

To use ESM in a CommonJS package, you must use the file extension .mjs and then you can use import in that file.

ESM Packages

In an ESM packages, all .js files are ESM format by default.

To use CommonJS in an ESM package, you must use the file extension .cjs.

Conditional Exports

Regardless of which package type you use, you'll likely want to take advantage of conditional exports. Here we'll show the import and require fields on the exports field.

package.json
json
{
"main": "./main-require.js",
"exports": {
"import": "./main-module.mjs",
"require": "./main-require.js"
},
"type": "module"
}

The import field indicates which file will be selected when using ESM imports or dynamic import() syntax. The require field does the same for require. This replaces main for versions of node that support it, allowing you to support both commonjs usage and esm usage in a single package.

Who uses what?

main, module, browser, as well as exports are all used by various systems. It's kind of a mess and you should check what you're using. Webpack 5 for example, merged support for node.js conditional exports but has supported the module key since version 2 (Rollup also has supported module).