Finally! The latest version of Node.js — v14.0.0 — was introduced on April 22nd, 2020. This update introduced a lot of interesting features, but there was one change we desperately waited for. Node 14 introduces ECMAScript modules — no more transpiling, no more difficulties with import and export. Why we are so excited to share this news and what it means for the JS developer community — I will explain here.
KeenEthics started with Meteor js development. This framework is mainly about Universal JS, and although it was not as successful as React or Angular, it had a profound impact on developers’ thoughts.
Some Background History
The community developed various systems to meet this goal: AMD, CommonJS, UMD, and ECMAScript modules.
AMD (Asynchronous Module Definition) is one of the most ancient module systems, which was initially implemented with the means of require.js library.
UMD (Universal Module Definition) is a module system introduced as a universal one and compatible with AMD and CommonJS.
CommonJS, in turn, is the module system created for Node.js server.
ECMAScript (also referred to as ES) was developed later as a system which both CommonJS and AMD users would be happy with.
More About ECMAScript Modules
As I said, the idea of ECMAScript modules was to make both CommonJS and AMD users happy. So, this system adopted a very simple but effective style rules:
Each module is a piece of code, and it is executed once loaded.
This code may include declarations of variables, functions, and so on. These declarations are local to the module.
If you mark these declarations as exports, other modules can import them.
“export” is a label that makes variables and functions accessible from outside the current module; “import” is a label that allows the use of functionality from other modules.
For a module to import a declaration from a different module, the former refers to the latter via module specifiers. These module specifiers can be the following:
Relative paths. These paths point relatively to the location of the importing module.
Absolute paths. These paths point directly to the file from which the module should be imported.
Names. Each name refers to a certain module as configured.
Each module is a singleton. That is, if a module is imported a few times, there still exists a single instance of it.
There are no global variables — only module specifiers are global.
This module system is now supported by all major browsers but for Internet Explorer. The convenience and universality of ECMAScript paved its road to popularity and success.
ECMAScript Modules and Node.JS
Things changed when the latest version of Node was released.
Node.js v14 offers full support of ECMAScript modules, and it is enabled by default. However, the interoperability between ECMAScript modules and CommonJS modules is still limited. The Node community urges developers to expect major changes in terms of interoperability soon.
The following files will be treated as ECMAScript modules:
Files ending in .js if there is a top-level field "type" with a value of "module” in the nearest parent package.json file
Files ending in .mjs
Strings passed in as an argument to --eval or --print, or piped to node via STDIN, with the flag --input-type=module.
The following files will be treated as CommonJS modules:
Files ending in .js if there is a top-level field "type" with a value of "commonjs” in the nearest parent package.json file
Files ending in .js if there is no top-level field "type" in the nearest parent package.json file
Files ending in .cjs
Strings passed in as an argument to --eval or --print, or piped to node via STDIN, with the flag --input-type=commonjs.
Strings passed in as an argument to --eval or --print, or piped to node via STDIN, without the flag --input-type
All the conditions supported by Node.js except “require” — that is “import”, “default”, and “node” — support both ECMAScript and CommonJS modules. The “require” condition is unique to CommonJS. Similarly, there are no “exports”, ”module.exports”, ”__filename”, ”__dirname”, “NODE_PATH”, “require.extensions”, “require.cache”, or “require.resolve” in ECMAScript.
“Require.resolve” can be implemented via “import.meta.resolve”, which is experimentally supported via the “--experimental-import-meta-resolve” flag.
When using the “import” keyword, unlike in CommonJS, in ECMAScript modules, a file extension must be provided and directory indexes must be fully specified.
As for other conditions — such as “browser” or “react-native”, which may be supported by tools and environments other than Node.js, — there is no precise guidance in Node v14 documentation, but it is expected to be offered later.
So, What’s Next?
As a Node.js development company, we observed this update for quite a while now and waited for the flag “Experimental” to be taken down. Finally, this change is out there — maybe not 100 percent perfectly implemented, and some bugs will definitely persist in a few future version updates. Yet, it is a huge and very promising step ahead.