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 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
What module to use in tsconfig, commonjs or es6?
How to make desicion? I need that output module will work in client/back sides.
So here we are talking about the module option that will be used by typescript to determine what is the name of the module that will compile your code to the targeted version of javascript you specified with the option target.
So the underlying question you are asking is, what is my target ? Should I target ES3, ES5, ES6, ES7, ES8 or ... ES42 ?
Answer : the compatibility.
In 2020 you propably target ES5 or ES6 (which is the default value).
(You can ignore CommonJS because it relate to ES3 which is 99% chance irrelevant to you)
some article
If your code is made to be executed on browsers, I would recommand you to look which is the latest version supported by all your targeted browser and take the one that is supported by all.
Ex: Safari ES6, Firefox ES8, Chrome ES8 : so you choose ES6 as target so your code works on every targeted browser.
The website caniuse.com is usefull to know which features are supported and which are not
If your code is made to run on backend (node.js), look at which version of node.js is running. Every version of node have different capabilities.
You can have a look here
Additionnal materials :
What version of Javascript is supported in node.js
I have several backend-only Node.js projects which use a simple TypeScript config.
Before March 2018, I had this in package.json:
"devDependencies": {
"#types/core-js": "^0.9.46",
"#types/node": "^9.6.2"
}
since ~March 2018, I have been omitting "#types/core-js" and everything seems to compile fine. Do we need "#types/core-js" anymore?
I have several Node-based projects written in TypeScript. I never ever used #types/core-js in my projects. So it is definitely not necessary to use #types/core-js in order to write Node-based code. Having #types/node, on the other hand, is a boon if you're going to use Node's API.
The first thing to do if you run into a compilation issue that appears to be caused by the compiler not knowing about features introduced in ES6 is to set lib to load the proper typings you need. For instance, if you decide to target es5 but want to use methods, classes, functions introduced in ES6, you do need to specify "es6" in your lib setting because by default the target es5 loads the lib es5 too. (According to the documentation, a target of es5 sets lib by default to DOM,ES5,ScriptHost, whereas a target of es6 sets lib by default to DOM,ES6,DOM.Iterable,ScriptHost.)
I've run into some very rare cases where there's something missing in the es6 lib. In such cases, I just write a definition to fix that specific problem. Loading #types/core-js might also fix the issue, but it also contains a lot of other things that are not necessary, and it adds a dependency to the project, which then must be managed, etc. Not worth it.
The focus above was Node projects, but even in web-based projects where I have a dependency on core-js I don't use #types/core-js. As I see it, the presence of core-js in a project should be entirely transparent to the project's application code. I'm writing code made to run on any platform providing an API that conforms to ES6 or later, I'm not writing code made to run with core-js specifically.
You should only need #types/core-js if you're using something that is in that declaration that is not available in your TypeScript declarations for your major version. This is useful if you're expecting to use core JavaScript ES6 features that are in core-js but were not implemented in the version of TS you were using at the time. There's more information available on the TS GitHub related to your question but in all reality if you're just using ES stuff that's there now, no you shouldn't need it anymore.
edit: Before I had stated it as node, but in all possibilities since it's TS it probably didn't know how to compile to the target without the declaration. As of TS 2 and NodeJS 6 you shouldn't really need it anymore.
I'm learning how to use Flux and I encountered the following line in the documentation: "We can use Node's EventEmitter to get started with a store."
I understand that you can use things like Browserify to do the bundling and minifying, grabbing all the dependencies that Node code has to make the bundled browser-compatible JS file. But what's bugging me right now is how you know what you can do this with. How do we know what Node code we're allowed to use in the browser?
So, first of all let's consider that when in node you have
JavaScript modules that are the 3rdParty modules written in JavaScript (ECMA5, ECMA6 and even TypeScript or CoffeScript) etc;
Node built-in module. Those are node Core modules like fs, path, util, etc.
native compiled module called Addons that are are
dynamically-linked shared objects, written in C or C++;
Then you have the packager / module bundlers
Browserify
Webpack
the transpilers i.e. source to source compilers that typicall will handle syntax tranforms like
Babel.js that shims modern JavaScript to legacy engines
and the techniques
ECMA5 Shim to support legacy JavaScript engines
HTML5 Cross-Browser Polyfills
Because you need to do polyfills if you want to transform not only syntax but even globals (like the Promise), so you combine transpiler to polyfill having like babel-polyfill
Finally we have different kind of modules design patterns (modules format) to be handled for the bundling process:
AMD modules format
CommonJS modules format
and formats that are not in those ones that must be bundled/shimmed - where possible - through custom loaders.
That said, native modules will not run in the browser: you cannot bundle a native module through Webpack. Ordinary modules will, but not all. This is due to several reasons. There are some specific methods that cannot be "browserified" or "webpacked". Let's take as example fs. Can you put this built-in module in the browser? There are some abstraction for that called brfs, that are transforms for built-in node apis fs.readFileSync() and fs.readFile(), so you will do
$ browserify -t brfs example/main.js > bundle.js
to get
var fs = require('fs');
var html = fs.readFileSync(__dirname + '/robot.html', 'utf8');
console.log(html);
This will not work for every non built-in modules, in the npm modules jungle, so WebPack has a module.noParse option to exclude Addons modules, non supported modules, etc. - see here about that.
So you have to look at the list of the transforms that means you can apply this transform to browserify to obtain like the fs transform mentioned above.
So that said, how do you know that a certain module will run in the browser? When you design your web application and Node backend you have to do opportunistic design choises to design shared modules/library that will run in both the environment, so being shimmed/packed at some point, like object models, application logic, etc., other modules that will deal with the File System I/O or will use native addons, so that will work in the server only, packing through wrappers it's possibile, but the behavior will look differently, as we have seen in the fs example above, and web specific modules, so it's a design matter.
A note can be added about networking modules i.e. node http, https that thanks to library abstractions like node request will run everywhere or using specific transforms like http-browserify.
Installing TypeScript requires node.js. And I assume that TypeScript uses Node.js to compile the .ts to a .js file.
My question is, does that created .js file require node.js? The ones I've seen so far appear not to. I don't want to load node.js into my html pages if it's not used.
thanks - dave
No, TypeScript just emits regular JavaScript.
If you use the "external modules" feature of the language (import x = require('foo');) you'll need to compile for either CommonJS (node) or AMD (require.js) and have those available, but that's opt-in.