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

11

573

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?

Litter answered 24/8, 2017 at 6:11 Comment(8)
@Larrydx kind of. Nodejs v13 requires to have package.json somewhere in current or parent directory and {"type": "module"} in it and you can use ES6 imports. From doc: Files ending with .js or lacking any extension will be loaded as ES modules when the nearest parent package.json file contains a top-level field "type" with a value of "module". Check more here: nodejs.org/api/esm.html#esm_package_json_type_fieldEberhart
@Madeo no transpilation seems to be necessary anymore?Parisi
Checkout support for import () the nodejs v16 - nodejs.org/api/packages.htmlPollie
@madeo ES Modules are the future for a number of reasons, so saying, "Don't" might be a disservice to new devs especially. Consider this tweet for more perspective.Cavender
We don't have to install 10 dependencies - as of Node 13 - like end of 2019. Most devs are not going to waving 🎏 to install additional dependencies. There is more to it than that. Not that this is about me promoting anything - just trying to share ℹ️ info - but, for example, I have a very simple node starter template It's all ready to go for import. There are actually no dependences related to using ES Modules. The dependencies are all other things like like eslint, etc.Cavender
🔑 is: "type": "module", in package.json ✅.Cavender
created a repo for this: github.com/jasonjin220/es6-express-rest-api-boilerplatePirbhai
In 2021 (nodejs v16 LTS) you don't need to do anything as modern nodejs is interoperable now with the ES6 modules system. Read more here: nodejs.org/dist/latest-v16.x/docs/api/…Southwest
D
615

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
Drink answered 24/8, 2017 at 6:34 Comment(13)
For working example see https://mcmap.net/q/67988/-how-can-i-use-an-es6-import-in-node-js-duplicateKeener
well I tried this method but inside .mjs file there was a require statement which then threw an error 'require is not defined' or somethingMadcap
You can alternatively use .js file extensions if you include "type": "module" in your package.json along with the flag node --experimental-modules my-app.jsRafe
The .mjs extension is no longer necessary, just use .js straight awayStephanstephana
a minimalistic example: github.com/Nexysweb/node13ecmaScriptInsufficiency
@JTHouk the flag is needed only befor v13, now flag was dropped. Nodejs v13 requires to have package.json somewhere in current or parent directory and {"type": "module"} in it and you can use ES6 imports. From doc: Files ending with .js or lacking any extension will be loaded as ES modules when the nearest parent package.json file contains a top-level field "type" with a value of "module". Check more here: nodejs.org/api/esm.html#esm_package_json_type_fieldEberhart
Just remark - when importing modules it is important to write full path and add .js extention to filenames (it is the same behaviour as browser, but not webpack where it completes extentions and /index.js for you) otherwise node with throw an error code:'ERR_MODULE_NOT_FOUND'Astaire
yarn 2.0.0-rc.32 chokes on this... hm....Eec
Node 14 removed the warning . Still expremental as far as i know .Izawa
Adding the { "type": "module" } doesn't work. Do you have a working example for that, and does that only works in Node.js >= v13 ?Malinin
using node 14.16, I did follow the instructions, and still getting the same error until i added the extension to the import. Kind of: import en from './lang/en/locale.js'; and it started to work.Stcyr
i have read this instruction in lots of places and it always freaks me out: Add { "type": "module" } in the nearest package.json because i don't understand the implications of doing that, ie: a) does this effect all require/import statements in all your files? b) is it possible this will negatively impact require/imports of 3rd party packages? c) will this prevent you from using require or does it just give you the option of using import?Downswing
@user1063287: Did you solve it?Vincenz
T
347

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.

Triacid answered 8/1, 2019 at 10:43 Comment(5)
Seems I am having a problem with importing with asterisk sign. E.g. import * as log from 'loglevel';Sternwheeler
I hope you export your functions from 'loglevel' before attempting to using import * as log 'loglevel'Triacid
This is ace! Doesn't work for Jest, unfortunatelyScarlett
This is the best option for use with Typescript as the ts-node loader makes the .mjs extension infeasible. node -r esm -r ts-node/register index.tsAmphioxus
Attention: Breaks TS reflect-metadata: github.com/standard-things/esm/issues/809Spraggins
K
177

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:

  1. Since it is experimental modules, .js files are named .mjs files
  2. While running you will add --experimental-modules to the node index.mjs
  3. While running with experimental modules in the output you will see: "(node:12020) ExperimentalWarning: The ESM module loader is experimental. "
  4. 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.
  5. Someday in the future, you could use .js instead of .mjs, as the features become stable instead of Experimental.
  6. More on experimental features, see: https://nodejs.org/api/esm.html
Keener answered 1/6, 2018 at 10:39 Comment(8)
passing this flag doesnt allow me to run my ./bin/www from boilerplate...Abrams
What is the error message you are seeing?Keener
Are you sure about number 5? I was under the impression that .mjs wasn't to denote it as experimental, but because the module spec didn't provide an efficient way to tell whether a file should use the module loader or require loader just by reading the code.Uncoil
Not sure. But, which editors will color code mjs files? Possibly no one including vscode. Yes, not sure, but just reasoned :-)Keener
This worked for me in Node 10.15.1Mcconnell
I think it can't be stressed enough that the file suffix indeed has to be .mjs for this to work (Windows, node 10.15.3)Elongation
Worked in node v12.6.0. But sad to see this is still experimentalTopside
You do not need to use the .mjs extension if you add this key as a top level key to your package.json file: "type": "module". I'm using node 13.2.0 but I believe that this also worked with a previous version, though I'm not sure how far back.Parkerparkhurst
E
84

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)
Excavate answered 28/5, 2019 at 21:51 Comment(9)
v12.11.1 doesn't support import without tweaksGrados
@AlexeySh. The methods I described above works fine in that version, I just tested.Excavate
I tested it too. And it doesn't work.Grados
Did you use the --experimental-modules flag? And did you put a package.json file in the same folder or a parent folder with {"type": "module"} ? What is the error you get?Excavate
if you will read my initial comment carefully, you can see there the following words "import without tweaks". that means no flags and no configs. this is the main point of my comment.Grados
@AlexeySh. Well, it was a very weird thing to comment on what I wrote, since I didn't state anything else.Excavate
As of Node v. 13 the experimental flag is not needed. nodejs.org/api/esm.htmlQuelpart
FYI: As of Node.js 12.17.0, the --experimental-modules flag is no longer necessary to use ECMAScript modules sourceRashid
@Madeo I would need to see your script if you want help with this, or at least the full error message / stack trace. Does this help? #56724178Excavate
P
23

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:

  1. Use a version of node that supports the --experimental-modules flag
  2. 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.

Pieria answered 26/1, 2018 at 11:35 Comment(3)
Do you have any documentation for this?Mess
This is for node 9.X but will apply down to v8.6 I believe nodejs.org/dist/latest-v9.x/docs/api/all.html#esm_enablingPieria
Why do you suggest Jest? I've had this same problem with Jest. Can't for example use this library with Jest: github.com/mrichar1/jsonapi-vuex/issues/104. Do you have a way to make it work?Willy
D
23

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

Die answered 8/12, 2018 at 6:53 Comment(1)
THANK YOU. I'm not sure how all of the other answers help anyone given that switching on "modules": true fails on 50% of node_modules used in projects out there. esm assumes you are calling the entry script directly from node and not e.g. via another libraries command. This answer just makes all the pain go away, and gives you the syntax you're after.Acetaldehyde
C
15

You may try esm.

Here is some introduction: esm

Conure answered 13/1, 2018 at 6:6 Comment(1)
This is a good option, especially while TC39 is still up in the air.Pieria
B
12

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.)

Beset answered 26/4, 2019 at 15:31 Comment(0)
V
8

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.

Violette answered 29/3, 2018 at 14:4 Comment(4)
has it been added yet :?Plunge
@RanaTallal Node 10 api still shows the flagDrink
@RanaTallal: I was just wondering too. node indeed still has the flag. But I'm currently studying for an Angular 6 course, and I use imports like import { FormsModule } from '@angular/forms'; all the time. And Angular runs on node. I'm confused.Tabathatabb
these kind of imports known as es6 are supported from 10x onwards. Which is now in LTS so you probably are using 10x or 11x. Thats the reason for you using these imports without any complications... So I am guessing they removed it somewhere in 10."x"Plunge
A
8

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.

Ancona answered 23/5, 2018 at 13:26 Comment(1)
Whilst this will work, this is not the answer. Ultimately this should not be needed.Pieria
M
6

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.

Mixologist answered 21/9, 2018 at 13:1 Comment(2)
thanks but @babel/node should be existed on devDependencies.Geller
Yes also react uses babel for compiling ES6. Babel created for compiling ES updates to older versions of JSPostfix

© 2022 - 2024 — McMap. All rights reserved.