We announce support for ECMAScript modules in Node.js

Node.js 13.2.0 comes with ECMAScript support for modules known for their import and export syntax. Previously, this functionality was behind the --experimental-modules



flag, which is no longer required. However, the implementation is still experimental and is subject to change.







From a translator: this long-awaited feature will finally allow us to use the standard modular syntax already available in modern browsers, and now also in Node.js without flags and transpilers







Activation



Node.js will process the code as ES modules in the following cases:









In all other cases, the code will be considered CommonJS. This applies to .js



files without "type": "module"



in the nearest package.json



and to the code passed through the command line without specifying --input-type



. This is done in order to maintain backward compatibility. However, since we now have two kinds of modules, CommonJS and ES, it will be better to specify the type of modules explicitly.







You can explicitly mark your code as CommonJS with the following features:









To learn more about these features, see the "Package Scope and File Extensions" documentation sections and --input-type









Syntax import and export



In the context of the ES module, you can use import



, pointing to other Javascript files. They can be specified in one of the following formats:









In imports, you can use default ( import _ from "es-module-package"



) and named values ​​( import { shuffle } from "es-module-package"



), as well as import everything as one namespace ( import * as fs from "fs"



). All built-in Node.js packages, like fs



or path



, support all three types of imports.







Imports that point to CommonJS code (that is, all current JavaScript written for Node.js require



and module.exports



) can only use the default option ( import _ from "commonjs-package"



).







Importing other file formats such as JSON and WASM remains experimental, and requires the flags --experimental-json-modules



and --experimental-wasm-modules



respectively. However, you can download these files using the module.createRequire



API, which is available without additional flags.







In your ES modules, you can use the export keyword to export default and named values.







Dynamic expressions with import()



can be used to load ES modules from either CommonJS or ES code. Note that import()



does not return a module but its promise (Promise).







import.meta.url



is import.meta.url



available in the modules, which contains the absolute URL of the current ES module.







Files and the new "type" field in package.json



Add "type": "module"



to the package.json of your project, and Node.js will begin to perceive all .js



files of your project as ES modules.







If some files of your project still use CommonJS and you cannot migrate the whole project at once, you can either use the .cjs



extension for this code, or put it in a separate directory and add package.json



containing { "type": "commonjs" }



, which tells Node.js that it should be treated as CommonJS.







For each downloaded file, Node.js will look at package.json



in the directory containing it, then one level up, and so on until it reaches the root directory. This mechanism is similar to how Babel .babelrc



files
. This approach allows Node.js to use package.json



as a source of various metadata about the package and configuration, similar to how it already works in Babel and other tools.







We recommend that all package developers specify a type



field, even if commonjs



is written commonjs



.







Package entry points and the "exports" field in package.json



Now we have two fields for specifying the entry point into the package: main



and exports



. The main



field is supported by all versions of Node.js, but its capabilities are limited: with it you can define only one main entry point in the package. The new exports



field also allows you to define the main entry point, as well as additional paths. This gives additional encapsulation for packages where only the explicit exports



paths are available for import from outside the package. exports



applies to both types of modules, CommonJS and ES, it doesn't matter if they are used through require



or import



.







This functionality will allow pkg/feature



type imports to point to a real path like ./node_modules/pkg/esm/feature.js



. Also, Node.js will throw an error if the import refers to pkg/esm/feature.js



which is not specified in exports



.







An additional, still experimental, feature, conditional exports provides the ability to export different files for different environments. This will allow the package to give CommonJS code to call require("pkg")



and the ES module code to import through import "pkg"



, although writing such a package is not without other problems . You can enable conditional exports with the —-experimental-conditional-exports



flag.







The main rake of the new modules



Required file extensions



When using imports, you must specify the file extension. When importing an index file from a directory, you must also completely specify the path to the file, that is, "./startup/index.js".







This behavior coincides with how imports work in browsers when accessing a regular server without additional configuration.







module.exports



, exports



, module.exports



, __filename



, __dirname





These values ​​from CommonJS are not available in the context of ES modules. However, require



can be imported into an ES module through module.createRequire()



. The equivalents __filename



and __dirname



can be obtained from import.meta.url



.







Creating packages



At the moment, we recommend that package authors use either fully CommonJS or fully ES modules for their Node.js projects. The module working group for Node.js continues to look for ways to improve support for dual packages, with CommonJS for legacy users and ES modules for new ones. Conditional exports are now experimental and we hope to roll out this functionality or its alternative by the end of January 2020, or even earlier.







To learn more about this, see our examples and recommendations for creating dual CommonJS / ES Module packages.







What will happen next



Loaders. Work continues on the API for writing custom loaders, for implementing module transpilation in runtime, redefining import paths (packages or individual files), and also instrumentation of code. The experimental API, accessible under the —-experimental-loader



flag, will be subject to significant alterations before we remove it from the flag.







Dual CommonJS / ES module packages. We want to provide a standard way to publish a package that can be used both through require



in CommonJS and through import



in ES modules. We have more information about this in the documentation . We plan to complete the work and withdraw from the flag by the end of January 2020, if not earlier.







That's all! We hope ECMAScript module support brings Node.js closer to JavaScript standards and brings new compatibility features across the JavaScript ecosystem. The workflow for improving module support is being done publicly here: https://github.com/nodejs/modules .








All Articles