How to use hardhat with ES module? - node.js

I wanted to add hardhat to a project that uses ES modules. Hardhat complains that I can't use require in the hardhat.config.js file, so I renamed it to import, but it still won't compile with the following error:
require() of ES modules is not supported.
There isn't a place where require is being called (I have replaced it with import), but it says otherwise. Any solution?

I have "type": "module", in my package.json
I am using the "hardhat": "^2.12.0-esm.1" package. It's a new package that was specially written to support ESM.
In my test, if I need some HH function, I do something like:
import pkg from 'hardhat'
const { ethers } = pkg
My hardhat.config.js is renamed to hardhat.config.cjs but the inside is unchanged and has lots of requires in it, and they work, even though my package.json has type: "module".
In my scripts, I have lines like:
async function main() {
const [deployer] = await ethers.getSigners()
but I don't have any import nor require at the beginning. I guess calling hardhat run script/my_script.js does the import magic.

Related

NodeJS: loading ES Modules and native addons in the same project

Before the actual questions (see at the end), please let me show the steps that lead to that question through an example:
Creating the project
tests$ mkdir esm && cd esm
tests/esm$ nvm -v
0.37.2
tests/esm$ nvm use v15
Now using node v15.6.0 (npm v7.5.6)
tests/esm$ node -v
v15.6.0
tests/esm$ npm -v
7.5.6
tests/esm$ npm init
package name: (esm) test-esm
entry point: (index.js)
Installing nodehun
tests/esm$ npm install nodehun
added 2 packages, and audited 3 packages in 11s
tests/esm$ npm ls
test-esm#1.0.0 tests/esm
└── nodehun#3.0.2
dependencies of nodehun here
index.js
import { suggest } from './checker.js'
suggest("misspeling");
checker.js
import Nodehun from 'nodehun'
import fs from 'fs';
const affix = fs.readFileSync('dictionaries/en_NZ.aff')
const dictionary = fs.readFileSync('dictionaries/en_NZ.dic')
const nodehun = new Nodehun(affix, dictionary)
export const suggest = (word) => hun_suggest(word);
async function hun_suggest(word) {
let suggestions = await nodehun.suggest(word);
console.log(suggestions);
}
To obtain the required Hunspell dictionary files (affix and dictionary):
tests/esm$ mkdir dictionaries && cd dictionaries
tests/esm/dictionaries$ curl https://www.softmaker.net/down/hunspell/softmaker-hunspell-english-nz-101.sox > en_NZ.sox
tests/esm/dictionaries$ unzip en_NZ.sox en_NZ.aff en_NZ.dic
Running the project
As per nodejs documentation (Determining Module System) to support the import / export:
Node.js will treat the following as ES modules when passed to node as the initial input, or when referenced by import statements within ES module code:
• Files ending in .js when the nearest parent package.json file contains a top-level "type" field with a value of "module".
We add "type": "module" field in the package.json file of the project.
package.json
{
...
"main": "index.js",
"type": "module",
...
}
First Failed Run
tests/esm$ node index.js
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".node" for tests/esm/node_modules/nodehun/build/Release/Nodehun.node
... omitted ...
at async link (node:internal/modules/esm/module_job:64:9) {
code: 'ERR_UNKNOWN_FILE_EXTENSION'
}
Digging a bit on the reason of the above error:
in the documentation on how to load addons, it refers to the use of require
The filename extension of the compiled addon binary is .node (as opposed to .dll or .so). The require() function is written to look for files with the .node file extension and initialize those as dynamically-linked libraries.
once you define your node project as a "type": "module", require it ceases to be supported (as specified in Interoperability with CommonJS):
Using require to load an ES module is not supported because ES modules have asynchronous execution. Instead, use import() to load an ES module from a CommonJS module.
Temporary Solution
After some time searching the documentation, I found a temporary solution: Customizing ESM specifier resolution algorithm:
The current specifier resolution does not support all default behavior of the CommonJS loader. One of the behavior differences is automatic resolution of file extensions and the ability to import directories that have an index file.
The --experimental-specifier-resolution=[mode] flag can be used to customize the extension resolution algorithm.
To enable the automatic extension resolution and importing from directories that include an index file use the node mode.
tests/esm$ node --experimental-specifier-resolution=node index.js
(node:XXXXX) ExperimentalWarning: The Node.js specifier resolution in ESM is experimental.
(Use `node --trace-warnings ...` to show where the warning was created)
[
'misspelling',
'misspending',
'misspeaking',
'misspell',
'dispelling',
'misapplier',
'respelling'
]
There are a some posts that get to this same resolution (ref 1, ref 2).
However, using experimental flags does not seem a proper way to run your application on production.
Failed Alternative with esm package
From that point, several failed attempts have been tried to avoid the use of --experimental-* flags. Doing some search, I found some posts (ref 1, ref 2) recommending the use of the esm package.
esm gets 1.3M downloads per week.
According the read-me file in GitHub, it does not require any changes.
However, at this point, when I try this node -r esm index.js, a new error appears:
tests/esm$ npm install esm
added 1 package, and audited 4 packages in 709ms
tests/esm$ npm ls
test-esm#0.1.0 tests/esm
├── esm#3.2.25
└── nodehun#3.0.2
tests/esm$ node -r esm index.js
tests/esm/index.js:1
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: tests/esm/index.js
at new NodeError (node:internal/errors:329:5)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1125:13) {
code: 'ERR_REQUIRE_ESM'
}
The above could be due to a reported issue (Error [ERR_REQUIRE_ESM]: Must use import to load ES Module / require() of ES modules is not supported).
There is proposed patch to fix it, although I do not know how to use it myself.
const module = require('module');
module.Module._extensions['.js'] = function(module, filename) {
const content = fs.readFileSync(filename, 'utf8');
module._compile(content, filename);
};
Questions
Is there a (standard) way to use import / export (ES Modules) without incurring in issues with import addons?
Avoiding the use of the --experimental-specifier-resolution=node flag.
Perhaps esm could be the solution to the above. Is there anything I am doing wrong with the usage esm package?
If it is a correct usage, is there a way to use the proposed patch myself as a working around?
Any hints to help to solve it would be really appreciated.
Note: the final status of the example can be cloned from https://github.com/rellampec/test-esm.git
I ran into a similar problem and fixed it this way:
https://nodejs.org/api/module.html#module_module_createrequire_filename
// The project is "type": "module" in package json
// createRequire is native in node version >= 12
import { createRequire } from 'module';
import path from 'path';
// Absolute path to node modules (or native addons)
const modulesPath = path.resolve(process.cwd(), 'node_modules');
// Create the require method
const localRequire = createRequire(modulesPath);
// require the native add-on
const myNativeAddon = localRequire('my-native-addon');
After some ramblings trying to figure this out got to the root cause.
When using node -r esm index.js, the esm package does already all the work for your (as noted in other answers), and therefore (not mentioned in other answers):
the package.json should be updated by removing "type:" "module" (as it creates unintended interactions between the native node ES Modules feature and the esm package you installed)
Aside note: if you tried to use node ES Modules and then you try to switch to esm package, it is very easy to miss this point.

SyntaxError: The requested module 'graphql-relay' does not provide an export named 'fromGlobalId' [duplicate]

I've installed Node 8.9.1 (same problem happens in v10.5.0).
I'm trying to use named imports from npm packages in a file with the .mjs
import { throttle } from lodash;
I run:
node --experimental-modules index.mjs
and I get:
SyntaxError: The requested module 'lodash' does not provide an export named 'throttle'
at ModuleJob._instantiate (internal/modules/esm/module_job.js:80:21)
--experimental-modules are supposed to stop being experimental in v10 LTS, so why haven't more module authors jumped on the bandwagon?
EDITED NEW (AND MUCH BETTER) ANSWER
The Node team is ... slow. Meanwhile, the same guy who brought us Lodash (John-David Dalton) imagined a brilliant solution, and his idea is the best way to get full ES6 module support in 2019.
(In fact, I want to delete my earlier answer, but I've left it for historical purposes.)
The new solution is SUPER simple.
Step #1:
npm i esm
(https://www.npmjs.com/package/esm for package details)
Step #2:
node -r esm yourApp.js
That's the entirety of it: it's really just that easy. Just add -r esm as a Node arg, and everything just magically works (it's even less typing than --experimental-modules!) Thank you John-David Dalton!!!
As I said in my original answer, presumably someday Node will finally release full ES6 support, but when that happens adopting it will be as easy as removing "-r esm" from a few scripts :D
Finally, to give credit where due, while I didn't find it through his answer, #Divyanshu Rawat actually provided an answer with the precursor to this library long before I made this update.
ORIGINAL ANSWER
--experimental-modules does not have support for named exports yet:
--experimental-modules doesn't support importing named exports from a commonjs module (except node's own built-ins).
https://github.com/apollographql/graphql-tools/issues/913
This is why you are unable to use the syntax:
import { throttle } from 'lodash';
Instead (for now at least) you have to destruct what you need:
import lodash from 'lodash';
const { throttle } = lodash;
Presumably someday Node will add support for all of the ES Module features.
I just had this error with nodejs express *.mjs file and --experimental-modules flag enabled for googleapis.
import { google } from "googleapis";
SyntaxError: The requested module 'googleapis' does not provide an export named 'google'
Solution
//not working!
//import { google } from "googleapis";
//working
import googleapis from "googleapis";
const { google } = googleapis;
I do not understand why this is the case; if anyone knows why, please comment.
You have to use .mjs extension.
Once this has been set, files ending with .mjs will be able to be loaded as ES Modules.
reference: https://nodejs.org/api/esm.html
Update:
Looks like you haven't export the method yet.
Suppose i have hello.mjs with content
export function sayHello() {
console.log('hello')
}
i can use it in index.mjs like this
import {sayHello} from './hello.mjs'
sayHello()
For me loading lodash as ES Library did the job, here is the NPM Package for the same.
The Lodash library exported as ES modules.
https://www.npmjs.com/package/lodash-es
Then you can import utils in normal way.
import { shuffle } from 'lodash-es';
If lodash had been written as modules, and lodash/index.mjs exported throttle: export const throttle = ...;, then you'd be able to import { throttle } from lodash;
The problem here is that in commonjs there's no such thing as a named export. Which means that in commonjs modules export one thing only.
So think that lodash exports an object containing a property named throttle.
For the second part of the question, I believe people will slowly start adopting ES Modules once it's not experimental anymore. At the time of this writing, it still is (Node.js v11.14).
#machineghost answer works. I remember also adding 'type':'module' to package.json along with using esm with node v12(LTS) and it worked fine.## Heading ##
I updated my node to v14(current) and I got an error
C:\Users\andey\Documents\Project\src\app.js:1
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module:
C:\Users\andey\Documents\Project\src\app.js
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1217:13) {
code: 'ERR_REQUIRE_ESM'
}
To fix it I had to remove 'type':'module' from package.json.
source

node --experimental-modules, requested module does not provide an export named

I've installed Node 8.9.1 (same problem happens in v10.5.0).
I'm trying to use named imports from npm packages in a file with the .mjs
import { throttle } from lodash;
I run:
node --experimental-modules index.mjs
and I get:
SyntaxError: The requested module 'lodash' does not provide an export named 'throttle'
at ModuleJob._instantiate (internal/modules/esm/module_job.js:80:21)
--experimental-modules are supposed to stop being experimental in v10 LTS, so why haven't more module authors jumped on the bandwagon?
EDITED NEW (AND MUCH BETTER) ANSWER
The Node team is ... slow. Meanwhile, the same guy who brought us Lodash (John-David Dalton) imagined a brilliant solution, and his idea is the best way to get full ES6 module support in 2019.
(In fact, I want to delete my earlier answer, but I've left it for historical purposes.)
The new solution is SUPER simple.
Step #1:
npm i esm
(https://www.npmjs.com/package/esm for package details)
Step #2:
node -r esm yourApp.js
That's the entirety of it: it's really just that easy. Just add -r esm as a Node arg, and everything just magically works (it's even less typing than --experimental-modules!) Thank you John-David Dalton!!!
As I said in my original answer, presumably someday Node will finally release full ES6 support, but when that happens adopting it will be as easy as removing "-r esm" from a few scripts :D
Finally, to give credit where due, while I didn't find it through his answer, #Divyanshu Rawat actually provided an answer with the precursor to this library long before I made this update.
ORIGINAL ANSWER
--experimental-modules does not have support for named exports yet:
--experimental-modules doesn't support importing named exports from a commonjs module (except node's own built-ins).
https://github.com/apollographql/graphql-tools/issues/913
This is why you are unable to use the syntax:
import { throttle } from 'lodash';
Instead (for now at least) you have to destruct what you need:
import lodash from 'lodash';
const { throttle } = lodash;
Presumably someday Node will add support for all of the ES Module features.
I just had this error with nodejs express *.mjs file and --experimental-modules flag enabled for googleapis.
import { google } from "googleapis";
SyntaxError: The requested module 'googleapis' does not provide an export named 'google'
Solution
//not working!
//import { google } from "googleapis";
//working
import googleapis from "googleapis";
const { google } = googleapis;
I do not understand why this is the case; if anyone knows why, please comment.
You have to use .mjs extension.
Once this has been set, files ending with .mjs will be able to be loaded as ES Modules.
reference: https://nodejs.org/api/esm.html
Update:
Looks like you haven't export the method yet.
Suppose i have hello.mjs with content
export function sayHello() {
console.log('hello')
}
i can use it in index.mjs like this
import {sayHello} from './hello.mjs'
sayHello()
For me loading lodash as ES Library did the job, here is the NPM Package for the same.
The Lodash library exported as ES modules.
https://www.npmjs.com/package/lodash-es
Then you can import utils in normal way.
import { shuffle } from 'lodash-es';
If lodash had been written as modules, and lodash/index.mjs exported throttle: export const throttle = ...;, then you'd be able to import { throttle } from lodash;
The problem here is that in commonjs there's no such thing as a named export. Which means that in commonjs modules export one thing only.
So think that lodash exports an object containing a property named throttle.
For the second part of the question, I believe people will slowly start adopting ES Modules once it's not experimental anymore. At the time of this writing, it still is (Node.js v11.14).
#machineghost answer works. I remember also adding 'type':'module' to package.json along with using esm with node v12(LTS) and it worked fine.## Heading ##
I updated my node to v14(current) and I got an error
C:\Users\andey\Documents\Project\src\app.js:1
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module:
C:\Users\andey\Documents\Project\src\app.js
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1217:13) {
code: 'ERR_REQUIRE_ESM'
}
To fix it I had to remove 'type':'module' from package.json.
source

Get access to ES6 class in gulpfile.js [duplicate]

This question already has answers here:
Node.js - SyntaxError: Unexpected token import
(16 answers)
Closed 3 years ago.
I'm trying to get the hang of ES6 imports in Node.js and am trying to use the syntax provided in this example:
Cheatsheet Link
I'm looking through the support table, but I was not able to find what version supports the new import statements (I tried looking for the text import/require). I'm currently running Node.js 8.1.2 and also believe that since the cheatsheet is referring to .js files it should work with .js files.
As I run the code (taken from the cheatsheet's first example):
import { square, diag } from 'lib';
I get the error:
SyntaxError: Unexpected token import.
Reference to library I'm trying to import:
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
What am I missing and how can I get node to recognize my import statement?
Node.js has included experimental support for ES6 support.
Read more about here: https://nodejs.org/docs/latest-v13.x/api/esm.html#esm_enabling.
TLDR;
Node.js >= v13
It's very simple in Node.js 13 and above. You need to either:
Save the file with .mjs extension, or
Add { "type": "module" } in the nearest package.json.
You only need to do one of the above to be able to use ECMAScript modules.
Node.js <= v12
If you are using Node.js version 9.6 - 12, save the file with ES6 modules with .mjs extension and run it like:
node --experimental-modules my-app.mjs
You can also use npm package called esm which allows you to use ES6 modules in Node.js. It needs no configuration. With esm you will be able to use export/import in your JavaScript files.
Run the following command on your terminal
yarn add esm
or
npm install esm
After that, you need to require this package when starting your server with node. For example if your node server runs index.js file, you would use the command
node -r esm index.js
You can also add it in your package.json file like this
{
"name": "My-app",
"version": "1.0.0",
"description": "Some Hack",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node -r esm index.js"
},
}
Then run this command from the terminal to start your node server
npm start
Check this link for more details.
I just wanted to use the import and export in JavaScript files.
Everyone says it's not possible. But, as of May 2018, it's possible to use above in plain Node.js, without any modules like Babel, etc.
Here is a simple way to do it.
Create the below files, run, and see the output for yourself.
Also don't forget to see Explanation below.
File myfile.mjs
function myFunc() {
console.log("Hello from myFunc")
}
export default myFunc;
File index.mjs
import myFunc from "./myfile.mjs" // Simply using "./myfile" may not work in all resolvers
myFunc();
Run
node --experimental-modules index.mjs
Output
(node:12020) ExperimentalWarning: The ESM module loader is experimental.
Hello from myFunc
Explanation:
Since it is experimental modules, .js files are named .mjs files
While running you will add --experimental-modules to the node index.mjs
While running with experimental modules in the output you will see: "(node:12020) ExperimentalWarning: The ESM module loader is experimental.
"
I have the current release of Node.js, so if I run node --version, it gives me "v10.3.0", though the LTE/stable/recommended version is 8.11.2 LTS.
Someday in the future, you could use .js instead of .mjs, as the features become stable instead of Experimental.
More on experimental features, see: https://nodejs.org/api/esm.html
Using Node.js v12.2.0, I can import all standard modules like this:
import * as Http from 'http'
import * as Fs from 'fs'
import * as Path from 'path'
import * as Readline from 'readline'
import * as Os from 'os'
Versus what I did before:
const
Http = require('http')
,Fs = require('fs')
,Path = require('path')
,Readline = require('readline')
,Os = require('os')
Any module that is an ECMAScript module can be imported without having to use an .mjs extension as long as it has this field in its package.json file:
"type": "module"
So make sure you put such a package.json file in the same folder as the module you're making.
And to import modules not updated with ECMAScript module support, you can do like this:
// Implement the old require function
import { createRequire } from 'module'
const require = createRequire(import.meta.url)
// Now you can require whatever
const
WebSocket = require('ws')
,Mime = require('mime-types')
,Chokidar = require('chokidar')
And of course, do not forget that this is needed to actually run a script using module imports (not needed after v13.2):
node --experimental-modules my-script-that-use-import.js
And that the parent folder needs this package.json file for that script to not complain about the import syntax:
{
"type": "module"
}
If the module you want to use has not been updated to support being imported using the import syntax then you have no other choice than using require (but with my solution above that is not a problem).
I also want to share this piece of code which implements the missing __filename and __dirname constants in modules:
import {fileURLToPath} from 'url'
import {dirname} from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
If you are using the modules system on the server side, you do not need to use Babel at all. To use modules in Node.js ensure that:
Use a version of node that supports the --experimental-modules flag
Your *.js files must then be renamed to *.mjs
That's it.
However and this is a big however, while your shinny pure ES6 code will run in an environment like Node.js (e.g., 9.5.0) you will still have the craziness of transpilling just to test. Also bear in mind that Ecma has stated that release cycles for JavaScript are going to be faster, with newer features delivered on a more regular basis. Whilst this will be no problems for single environments like Node.js, it's a slightly different proposition for browser environments. What is clear is that testing frameworks have a lot to do in catching up. You will still need to probably transpile for testing frameworks. I'd suggest using Jest.
Also be aware of bundling frameworks. You will be running into problems there.
Use:
"devDependencies": {
"#babel/core": "^7.2.0",
"#babel/preset-env": "^7.2.0",
"#babel/register": "^7.0.0"
}
File .babelrc
{
"presets": ["#babel/preset-env"]
}
Entry point for the Node.js application:
require("#babel/register")({})
// Import the rest of our application.
module.exports = require('./index.js')
See How To Enable ES6 Imports in Node.js
You may try esm.
Here is some introduction: esm
Using the .mjs extension (as suggested in the accepted answer) in order to enable ECMAScript modules works. However, with Node.js v12, you can also enable this feature globally in your package.json file.
The official documentation states:
import statements of .js and extensionless files are treated as ES modules if the nearest parent package.json contains "type": "module".
{
"type": "module",
"main": "./src/index.js"
}
(Of course you still have to provide the flag --experimental-modules when starting your application.)
Back to Jonathan002's original question about
"... what version supports the new ES6 import statements?"
based on the article by Dr. Axel Rauschmayer, there is a plan to have it supported by default (without the experimental command line flag) in Node.js 10.x LTS. According to node.js's release plan as it is on 3/29, 2018, it's likely to become available after Apr 2018, while LTS of it will begin on October 2018.
Solution
https://www.npmjs.com/package/babel-register
// This is to allow ES6 export syntax
// to be properly read and processed by node.js application
require('babel-register')({
presets: [
'env',
],
});
// After that, any line you add below that has typical ES6 export syntax
// will work just fine
const utils = require('../../utils.js');
const availableMixins = require('../../../src/lib/mixins/index.js');
Below is definition of file *mixins/index.js
export { default as FormValidationMixin } from './form-validation'; // eslint-disable-line import/prefer-default-export
That worked just fine inside my Node.js CLI application.
I don't know if this will work for your case, but I am running an Express.js server with this:
nodemon --inspect ./index.js --exec babel-node --presets es2015,stage-2
This gives me the ability to import and use spread operator even though I'm only using Node.js version 8.
You'll need to install babel-cli, babel-preset-es2015, and babel-preset-stage-2 to do what I'm doing.

How can I use an ES6 import in Node.js? [duplicate]

This question already has answers here:
Node.js - SyntaxError: Unexpected token import
(16 answers)
Closed 3 years ago.
I'm trying to get the hang of ES6 imports in Node.js and am trying to use the syntax provided in this example:
Cheatsheet Link
I'm looking through the support table, but I was not able to find what version supports the new import statements (I tried looking for the text import/require). I'm currently running Node.js 8.1.2 and also believe that since the cheatsheet is referring to .js files it should work with .js files.
As I run the code (taken from the cheatsheet's first example):
import { square, diag } from 'lib';
I get the error:
SyntaxError: Unexpected token import.
Reference to library I'm trying to import:
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
What am I missing and how can I get node to recognize my import statement?
Node.js has included experimental support for ES6 support.
Read more about here: https://nodejs.org/docs/latest-v13.x/api/esm.html#esm_enabling.
TLDR;
Node.js >= v13
It's very simple in Node.js 13 and above. You need to either:
Save the file with .mjs extension, or
Add { "type": "module" } in the nearest package.json.
You only need to do one of the above to be able to use ECMAScript modules.
Node.js <= v12
If you are using Node.js version 9.6 - 12, save the file with ES6 modules with .mjs extension and run it like:
node --experimental-modules my-app.mjs
You can also use npm package called esm which allows you to use ES6 modules in Node.js. It needs no configuration. With esm you will be able to use export/import in your JavaScript files.
Run the following command on your terminal
yarn add esm
or
npm install esm
After that, you need to require this package when starting your server with node. For example if your node server runs index.js file, you would use the command
node -r esm index.js
You can also add it in your package.json file like this
{
"name": "My-app",
"version": "1.0.0",
"description": "Some Hack",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node -r esm index.js"
},
}
Then run this command from the terminal to start your node server
npm start
Check this link for more details.
I just wanted to use the import and export in JavaScript files.
Everyone says it's not possible. But, as of May 2018, it's possible to use above in plain Node.js, without any modules like Babel, etc.
Here is a simple way to do it.
Create the below files, run, and see the output for yourself.
Also don't forget to see Explanation below.
File myfile.mjs
function myFunc() {
console.log("Hello from myFunc")
}
export default myFunc;
File index.mjs
import myFunc from "./myfile.mjs" // Simply using "./myfile" may not work in all resolvers
myFunc();
Run
node --experimental-modules index.mjs
Output
(node:12020) ExperimentalWarning: The ESM module loader is experimental.
Hello from myFunc
Explanation:
Since it is experimental modules, .js files are named .mjs files
While running you will add --experimental-modules to the node index.mjs
While running with experimental modules in the output you will see: "(node:12020) ExperimentalWarning: The ESM module loader is experimental.
"
I have the current release of Node.js, so if I run node --version, it gives me "v10.3.0", though the LTE/stable/recommended version is 8.11.2 LTS.
Someday in the future, you could use .js instead of .mjs, as the features become stable instead of Experimental.
More on experimental features, see: https://nodejs.org/api/esm.html
Using Node.js v12.2.0, I can import all standard modules like this:
import * as Http from 'http'
import * as Fs from 'fs'
import * as Path from 'path'
import * as Readline from 'readline'
import * as Os from 'os'
Versus what I did before:
const
Http = require('http')
,Fs = require('fs')
,Path = require('path')
,Readline = require('readline')
,Os = require('os')
Any module that is an ECMAScript module can be imported without having to use an .mjs extension as long as it has this field in its package.json file:
"type": "module"
So make sure you put such a package.json file in the same folder as the module you're making.
And to import modules not updated with ECMAScript module support, you can do like this:
// Implement the old require function
import { createRequire } from 'module'
const require = createRequire(import.meta.url)
// Now you can require whatever
const
WebSocket = require('ws')
,Mime = require('mime-types')
,Chokidar = require('chokidar')
And of course, do not forget that this is needed to actually run a script using module imports (not needed after v13.2):
node --experimental-modules my-script-that-use-import.js
And that the parent folder needs this package.json file for that script to not complain about the import syntax:
{
"type": "module"
}
If the module you want to use has not been updated to support being imported using the import syntax then you have no other choice than using require (but with my solution above that is not a problem).
I also want to share this piece of code which implements the missing __filename and __dirname constants in modules:
import {fileURLToPath} from 'url'
import {dirname} from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
If you are using the modules system on the server side, you do not need to use Babel at all. To use modules in Node.js ensure that:
Use a version of node that supports the --experimental-modules flag
Your *.js files must then be renamed to *.mjs
That's it.
However and this is a big however, while your shinny pure ES6 code will run in an environment like Node.js (e.g., 9.5.0) you will still have the craziness of transpilling just to test. Also bear in mind that Ecma has stated that release cycles for JavaScript are going to be faster, with newer features delivered on a more regular basis. Whilst this will be no problems for single environments like Node.js, it's a slightly different proposition for browser environments. What is clear is that testing frameworks have a lot to do in catching up. You will still need to probably transpile for testing frameworks. I'd suggest using Jest.
Also be aware of bundling frameworks. You will be running into problems there.
Use:
"devDependencies": {
"#babel/core": "^7.2.0",
"#babel/preset-env": "^7.2.0",
"#babel/register": "^7.0.0"
}
File .babelrc
{
"presets": ["#babel/preset-env"]
}
Entry point for the Node.js application:
require("#babel/register")({})
// Import the rest of our application.
module.exports = require('./index.js')
See How To Enable ES6 Imports in Node.js
You may try esm.
Here is some introduction: esm
Using the .mjs extension (as suggested in the accepted answer) in order to enable ECMAScript modules works. However, with Node.js v12, you can also enable this feature globally in your package.json file.
The official documentation states:
import statements of .js and extensionless files are treated as ES modules if the nearest parent package.json contains "type": "module".
{
"type": "module",
"main": "./src/index.js"
}
(Of course you still have to provide the flag --experimental-modules when starting your application.)
Back to Jonathan002's original question about
"... what version supports the new ES6 import statements?"
based on the article by Dr. Axel Rauschmayer, there is a plan to have it supported by default (without the experimental command line flag) in Node.js 10.x LTS. According to node.js's release plan as it is on 3/29, 2018, it's likely to become available after Apr 2018, while LTS of it will begin on October 2018.
Solution
https://www.npmjs.com/package/babel-register
// This is to allow ES6 export syntax
// to be properly read and processed by node.js application
require('babel-register')({
presets: [
'env',
],
});
// After that, any line you add below that has typical ES6 export syntax
// will work just fine
const utils = require('../../utils.js');
const availableMixins = require('../../../src/lib/mixins/index.js');
Below is definition of file *mixins/index.js
export { default as FormValidationMixin } from './form-validation'; // eslint-disable-line import/prefer-default-export
That worked just fine inside my Node.js CLI application.
I don't know if this will work for your case, but I am running an Express.js server with this:
nodemon --inspect ./index.js --exec babel-node --presets es2015,stage-2
This gives me the ability to import and use spread operator even though I'm only using Node.js version 8.
You'll need to install babel-cli, babel-preset-es2015, and babel-preset-stage-2 to do what I'm doing.

Resources