I've been looking all over the Internet without a clear answer for this.
Currently Node.js uses only CommonJS syntax to load modules, and if you really want to use the standard ECMAScript 2015 modules syntax, you either have to transpile it beforehand or use an external module loader at runtime.
Currently I'm not too positive to use either of those two methods, are the Node.js maintainers even planning to support ECMAScript 2015 modules or not? I haven't found an hint at all about this.
At the moment Node.js 6.x claims to support 96% of the ECMAScript 2015 features, but there isn't any reference to modules (Node.js ECMAScript 2015 support link).
Do you know if Node.js will support these modules out of the box, in the near future?
Node.js 13.2.0 & Above
Node.js 13.2.0 now supports ES Modules without a flag 🎉. However, the implementation is still marked as experimental so use in production with caution.
To enable ECMAScript module (ESM) support in 13.2.0, add the following to your package.json:
{
"type": "module"
}
All .js, .mjs (or files without an extension) will be treated as ESM.
There are a number of different options other than entire package.json opt-in, all of which are detailed in the documentation for 13.2.0.
Node.js 13.1.0 & Below
Those still using older versions of Node may want to try the [esm][3] module loader, which is a production-ready implementation of the ES Modules Specificaiton for Node.js:
node -r esm main.js
Detailed Updates...
23 April 2019
A PR recently landed to change the way ECMAScript modules are detected:
https://github.com/nodejs/node/pull/26745
It's still behind the --experimental-modules flag, but there are major changes in the way modules can be loaded:
package.type which can be either module or commonjs
type: "commonjs":
.js is parsed as CommonJS
the default for an entry point without an extension is CommonJS
type: "module":
.js is parsed as an ECMAScript module
does not support loading JSON or a native module by default
the default for an entry point without an extension is ECMAScript module
--type=[mode] to let you set the type on entry point. Will override package.type for entry point.
A new file extension .cjs.
this is specifically to support importing CommonJS in the module mode.
this is only in the ECMAScript module loader, the CommonJS loader remains untouched, but the extension will work in the old loader if you use the full file path.
--es-module-specifier-resolution=[type]
options are explicit (default) and node
by default our loader will not allow for optional extensions in the import, the path for a module must include the extension if there is one
by default our loader will not allow for importing directories that have an index file
developers can use --es-module-specifier-resolution=node to enable the CommonJS specifier resolution algorithm
This is not a “feature”, but rather an implementation for experimentation. It is expected to change before the flag is removed
--experimental-json-loader
the only way to import JSON when "type": "module"
when enable all import 'thing.json' will go through the experimental loader independent of mode
based on whatwg/html#4315
You can use package.main to set an entry point for a module
the file extensions used in main will be resolved based on the type of the module
17 January 2019
Node.js 11.6.0 still lists ES Modules as experimental, behind a flag.
13 September 2017
Node.js 8.5.0 has been released with support for mjs files behind a flag:
node --experimental-modules index.mjs
The plan for this is to remove the flag for the v10.0 LTS release.
--Outdated Information. Kept here for historical purposes--
8 September 2017
The Node.js master branch has been updated with initial support for ESM modules:
https://github.com/nodejs/node/commit/c8a389e19f172edbada83f59944cad7cc802d9d5
This should be available in the latest nightly (this can be installed via nvm to run alongside your existing install):
https://nodejs.org/download/nightly/
And enabled behind the --experimental-modules flag:
package.json
{
"name": "testing-mjs",
"version": "1.0.0",
"description": "",
"main": "index.mjs" <-- Set this to be an mjs file
}
Then run:
node --experimental-modules .
February 2017:
An Update on ES6 Modules in Node.js
The Node.js guys have decided that the least bad solution is to use the .mjs file extension. The takeaway from this is:
In other words, given two files foo.js and bar.mjs , using import * from 'foo' will treat foo.js as CommonJS while import * from 'bar'
will treat bar.mjs as an ES6 Module
And as for timelines...
At the current point in time, there are still a number of
specification and implementation issues that need to happen on the ES6
and Virtual Machine side of things before Node.js can even begin
working up a supportable implementation of ES6 modules. Work is in
progress but it is going to take some time — We’re currently looking
at around a year at least.
October 2016:
One of the developers on Node.js recently attended a TC-39 meeting and wrote up a superb article on the blockers to implementing for Node.js:
Node.js, TC-39, and Modules
The basic take-away from that is:
ECMAScript modules are statically analyzed, and CommonJS are evaluated
CommonJS modules allow for monkey-patching exports, and ECMAScript modules currently do not
It's difficult to detect what is an ECMAScript module and what is CommonJS without some form of user input, but they are trying.
*.mjs seems the most likely solution, unless they can accurately detect an ECMAScript module without user-input
-- Original Answer --
This has been a hot potato for quite some time. The bottom line is that yes, Node.js will eventually support the ES2015 syntax for importing/exporting modules - most likely when the specification for loading modules is finalized and agreed upon.
Here is a good overview of what's holding Node.js up. Essentially, they need to make sure that the new specification works for Node.js which is primarily conditional, synchronous loading and also HTML which is primarily asynchronous.
Nobody knows for sure right now, but I imagine Node.js will support import/export for static loading, in addition to the new System.import for dynamic loading - while still keeping require for legacy code.
Here's a few proposals on how Node might achieve this:
In defense of .js
.mjs modules
Related
I was considering updating my Node/Express code to use import instead of require by adding to my package.json file the line:
"type": "module",
However, I did not know why most Node/Express code I see, still uses require while code I see in the browser via webpack uses import.
Is there a reason for this duality? Is upgrading to import recommended in general? Is import because it is newer considered an upgrade and a better technology?
This previous Q/A is over 7 years old and has lot of historical information. I am looking for more current information as the language has evolved.
The reason for having two types of modules is purely historical.
Back in 2009 when Node.js was created, ES modules (import syntax) did not exist yet, but there existed other nonstandard alternatives, with the most important being AMD and CommonJS, for which several browser implementations were available. Node.js decided to adopt CommonJS (require syntax). For this reason, all packages deployed up until 2015 are CommonJS packages.
Native ES modules were introduced with the ECMAScript 2015 standard, but they only made it as an experimental technology in Node.js 8.5 in 2017, and it wasn't until Node.js 12 (2019) that their support became good enough to place them as an alternative to CommonJS (although this is subjective).
For this reason, a large part of software developed for Node.js still uses CommonJS modules with require statements.
Whether ES modules are better is a matter of opinion, and not a proper question for StackOverflow. At least, they are standard JavaScript, which makes them fit for use both in browsers and in Node.js, which is imo a big advantage.
A disadvantage is that ES modules cannot be required in CommonJS code - the opposite is true: CommonJS modules can be imported by ES modules - so if any of your dependencies uses ES modules, that may be a good opportunity to switch your code to ES modules, too.
So should we upgrade to use import in general? Of course, that's also a matter of opinion. And if that was my opinion, the answer would be "no", because there is no reason to change a running system. CommonJS code is not going to rust or worsen simply because a better alternative exists nowadays, although ES modules are a better choice for new code. Node.js, as long as people use it, is not going to drop support for CommonJS either.
There is a project called Deno which is designed to provide a more modern and secure alternative to Node.js to run JavaScript code on the server. Deno was originally designed to work with ES modules only, but it soon became clear that not supporting CommonJS modules was a major issue, because so many npm packages were not working, so it introduced a compatibility mode to support CommonJS modules under a flag. The moral of the story is: removing support for require is good idea, but re-adding it is an even better one.
I have read several "ESM in NodeJS" articles as of late, consequently; I decided to convert a CJS module I had into an ES-Module (2020). Before I even began writing code, I noticed something that was overwhelming — though it wasn't completely unexpected — my page was one big red squiggly error. I found it easier to just rewrite the whole module, even though it took me a couple days.
So now I am at a point where I can't help but to wonder if ESM is necessary. To put it more simply: Am I going to run into comparability issues down the road if I don't start using ESM modules today, or can I continue to use CJS?
All new projects should be written as ESM modules as that is the present and the future of the Javascript language and nodejs. It's highly, highly unlikely that CJS modules will lose support for a very long time because a huge portion of the nodejs eco-system is still CJS modules and I rather doubt that the nodejs leadership wants to create the kind of situation Python did with 2.0 => 3.0 which was not pleasant in the developer community. Plus, the dual compatibility in nodejs is already there and not really harming anything right now.
There are some CJS conveniences like __dirname that are not as convenient in EJS. And, EJS requires static export declarations (they can't be computed like they can be in CJS) which is good news for bundlers, but rules out some situations where you might to do dynamic exports.
ESM is the module standard in Javascript. Nodejs is moving to fully support that standard. New code should be written as ESM modules. I would expect some new features in the future to only be available in ESM modules as that's where the development and innovation is happening.
CJS is node-specific, not a Javascript standard. The developers behind nodejs took ideas from existing 3rd party module systems, molded them to fit into the needs of nodejs and built them into the first version of nodejs. They are not a Javascript standard. ESM are now part of the Javascript standard and nodejs has been adopting that new standard and filling in a few bits where they needed more than the standard offers.
I have started working on an existing project based on Node.js. I was just trying to understand the flow of execution, where I encountered with some *.mjs files. I have searched the web where I found that these are module based JS-files.
I want to know how is it different from *.js files (how does it benefit)?
It indicates an ES6 module file.
Node.js's original module system is CommonJs (which uses require and module.exports).
Since Node.js was created, the ECMAScript module system (which uses import and export) has become standard and Node.js has added support for it.
Node.js will treat .cjs files as CommonJS modules and .mjs files as ECMAScript modules. It will treat .js files as whatever the default module system for the project is (which is CommonJS unless package.json says "type": "module",).
See also: Differences between ES6 module system and CommonJs
.MJS file
mjs an extension for EcmaScript modules
An MJS file is a source code file containing an ES Module (ECMAScript Module) for use with a Node.js application.
MJS files are written in JavaScript, and may also use the .JS extension outside of the Node.js context.
ES Modules allow web and application developers to organize code into smaller reusable components.
ECMAScript 6 (ES6) introduced the specification for ES Modules, providing a standard for implementing modules in JavaScript. As of 2018, all major web browsers support ES Modules.
However, the popularity of modularized JavaScript pre-dates ES6. Node.js, a JavaScript runtime environment, used CommonJS as the specification for modules. Because so many existing applications were built with CommonJS, when Node.js added support for native ES modules, it controversially introduced the MJS file extension to differentiate the two and prevent applications from breaking.
NOTE: Some developers informally refer to MJS files as "Michael Jackson Script" files.
For clarity. As for devs/humans, it's easy to distinguish between a module file(.mjs) and a normal javascript file(.js)... because it's not always easy to determine even if you examine the code in the file.
There are also performance benefits which gives you more reason to consider using it.
V8(JavaScript engine that powers Google Chrome) recommends the use of .mjs but it still depends on your situation. If you want to know more of it's advantages, check https://v8.dev/features/modules#mjs
Create-React-App uses Babel that converts my ES6 modules to CommonJS module and Webpack will bundle everything in single file that my browser can understand.
1) Why not use CommonJS modules directly and use Webpack as bundler?
2) Now that ES6 modules are supported in browsers, why don't we transpile React CommonJS modules to ES6 modules.
Go to your Chrome console and type in require, you will get the message require not defined.
Our browser, in particular Chrome, has no idea what CommonJS is, it has no idea what modules are.
But if you are looking to remove those restrictions in your project, you can make use of Electron.
If you run require inside of the Electron browser window you will get this:
f require(path) {
try {
exports.requireDepth += 1;
return mod.require(path);
} finally {
exports.requireDepth -= 1;
}
}
Chrome the browser has no idea what the above is, but the Electron browser window does. It has some additional capabilities that Chrome does not.
The Electron browser has a MainWindow object which has access to all the available modules the belong to the Nodejs runtime and access to all modules inside the browser as well. So access to CommonJS as well as fs, crypto, etcetera.
You can do `require('fs') and access the filesystem directly from the Electron browser console.
In short, I am saying that with Electron you can directly require in modules like you want without having to use Webpack.
CommonJS code will not allow you to write code using imports, arrow functions, destructuring, generators, class etc... This makes your developer's life easy and I do see below advantages:
Less code more for same functionality.
Less time required for writing same functionality.
As of chrome 61 + can process your ES6 code but other browser will not be supporting it. So you need to transpile ES6 code to common js code so that it is consistent across browsers.
I've seen some npm packages (vue for example) have a module field in their package.json.
But module is not included in the package.json documentation - is this a convention of some kind? Is there documentation for this somewhere?
Update: April 2022
The module field is not officially defined by Node.js and support is not planned. Instead, the Node.js community settled on package exports which they believe is more versatile.
For practical reasons JavaScript bundlers will continue to support the module field. The esbuild docs explain when to use module as well as related fields main and browser.
Original Answer
Is "module" an official npm property or is this a convention of some kind?
It's a proposal, but likely to be supported due to de facto usage.
Is there documentation for this somewhere?
There is, in fact, and it can be found right here and later removed here.
What's it for?
ES6 Module Interoperability in Node. Additional discussion can be found here and here. And here's a blog post from Rich Harris talking more about it.
This is used by bundler tools for ESM (ECMAScript Module) detection. The Rollup documentation says it pretty well:
If your package.json file also has a module field, ES6-aware tools
like Rollup and webpack 2 will import the ES6 module version directly.
This article on Rollup 1.0 says it another way:
The main field makes sure that Node users using require will be served the UMD version. The module field is not an official npm feature but a common convention among bundlers to designate how to import an ESM version of our library.
Further discussion of pkg.module is on the Rollup Github Wiki and the webpack Docs.