SyntaxError: Cannot use import statement outside a module

Viewed 1081886

I've got an ApolloServer project that's giving me trouble, so I thought I might update it and ran into issues when using the latest Babel. My "index.js" is:

require('dotenv').config()
import {startServer} from './server'
startServer()

And when I run it I get the error

SyntaxError: Cannot use import statement outside a module

First I tried doing things to convince TPTB* that this was a module (with no success). So I changed the "import" to a "require" and this worked.

But now I have about two dozen "imports" in other files giving me the same error.

*I'm sure the root of my problem is that I'm not even sure what's complaining about the issue. I sort of assumed it was Babel 7 (since I'm coming from Babel 6 and I had to change the presets) but I'm not 100% sure.

Most of what I've found for solutions don't seem to apply to straight Node. Like this one here:

ES6 module Import giving "Uncaught SyntaxError: Unexpected identifier"

Says it was resolved by adding "type=module" but this would typically go in the HTML, of which I have none. I've also tried using my project's old presets:

"presets": ["es2015", "stage-2"],
"plugins": []

But that gets me another error: "Error: Plugin/Preset files are not allowed to export objects, only functions."

Here are the dependencies I started with:

"dependencies": {
"@babel/polyfill": "^7.6.0",
"apollo-link-error": "^1.1.12",
"apollo-link-http": "^1.5.16",
"apollo-server": "^2.9.6",
"babel-preset-es2015": "^6.24.1",
34 Answers

Verify that you have the latest version of Node.js installed (or, at least 13.2.0+). Then do one of the following, as described in the documentation:

Option 1

In the nearest parent package.json file, add the top-level "type" field with a value of "module". This will ensure that all .js and .mjs files are interpreted as ES modules. You can interpret individual files as CommonJS by using the .cjs extension.

// package.json
{
  "type": "module"
}

Option 2

Explicitly name files with the .mjs extension. All other files, such as .js will be interpreted as CommonJS, which is the default if type is not defined in package.json.

If anyone is running into this issue with TypeScript, the key to solving it for me was changing

    "target": "esnext",
    "module": "esnext",

to

    "target": "esnext",
    "module": "commonjs",

In my tsconfig.json. I was under the impression "esnext" was the "best", but that was just a mistake.

For those who were as confused as I was when reading the answers, in your package.json file, add "type": "module" in the upper level as show below:

{
  "name": "my-app",
  "version": "0.0.0",
  "type": "module",
  "scripts": { ...
  },
  ...
}

According to the official documentation:

import statements are permitted only in ES modules. For similar functionality in CommonJS, see import().

To make Node.js treat your file as an ES module, you need to (Enabling):

  • add "type": "module" to package.json
  • add "--experimental-modules" flag to the Node.js call

I ran into the same issue and it's even worse: I needed both "import" and "require"

  1. Some newer ES6 modules works only with import.
  2. Some CommonJS works with require.

Here is what worked for me:

  1. Turn your js file into .mjs as suggested in other answers

  2. "require" is not defined with the ES6 module, so you can define it this way:

    import { createRequire } from 'module'
    const require = createRequire(import.meta.url);
    

    Now 'require' can be used in the usual way.

  3. Use import for ES6 modules and require for CommonJS.

Some useful links: Node.js's own documentation. difference between import and require. Mozilla has some nice documentation about import

I had the same issue and the following has fixed it (using Node.js 12.13.1):

  • Change .js files extension to .mjs
  • Add --experimental-modules flag upon running your app.
  • Optional: add "type": "module" in your package.json

More information: https://nodejs.org/api/esm.html

First we'll install @babel/cli, @babel/core and @babel/preset-env:

npm install --save-dev @babel/cli @babel/core @babel/preset-env

Then we'll create a .babelrc file for configuring Babel:

touch .babelrc

This will host any options we might want to configure Babel with:

{
  "presets": ["@babel/preset-env"]
}

With recent changes to Babel, you will need to transpile your ES6 before Node.js can run it.

So, we'll add our first script, build, in file package.json.

"scripts": {
  "build": "babel index.js -d dist"
}

Then we'll add our start script in file package.json.

"scripts": {
  "build": "babel index.js -d dist", // replace index.js with your filename
  "start": "npm run build && node dist/index.js"
}

Now let's start our server.

npm start

I Tried with all the methods, but nothing worked.

I got one reference from GitHub.

To use TypeScript imports with Node.js, I installed the below packages.

1. npm i typescript --save-dev

2. npm i ts-node --save-dev

Won't require type: module in package.json

For example,

{
  "name": "my-app",
  "version": "0.0.1",
  "description": "",
  "scripts": {

  },
  "dependencies": {
    "knex": "^0.16.3",
    "pg": "^7.9.0",
    "ts-node": "^8.1.0",
    "typescript": "^3.3.4000"
  }
}

Node v14.16.0
For those who've tried .mjs and got:

Aviator@AW:/mnt/c/Users/Adrian/Desktop/Programming/nodejs_ex$ node just_js.mjs
file:///mnt/c/Users/Adrian/Desktop/Programming/nodejs_ex/just_js.mjs:3
import fetch from "node-fetch";
       ^^^^^

SyntaxError: Unexpected identifier

and who've tried import fetch from "node-fetch";
and who've tried const fetch = require('node-fetch');

Aviator@AW:/mnt/c/Users/Adrian/Desktop/Programming/nodejs_ex$ node just_js.js
(node:4899) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/mnt/c/Users/Adrian/Desktop/Programming/nodejs_ex/just_js.js:3
import fetch from "node-fetch";
^^^^^^

SyntaxError: Cannot use import statement outside a module  

and who've tried "type": "module" to package.json, yet continue seeing the error,

{
  "name": "test",
  "version": "1.0.0",
  "description": "to get fetch working",
  "main": "just_js.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT"
}

I was able to switch to axios without a problem.

import axios from 'axios'; <-- put at top of file.
Example:

axios.get('https://www.w3schools.com/xml/note.xml').then(resp => {

    console.log(resp.data);
});

Step 1

yarn add esm

or

npm i esm --save

Step 2

package.json

  "scripts": {
    "start": "node -r esm src/index.js",
  }

Step 3

nodemon --exec npm start

I found the 2020 update to the answer in this link helpful to answering this question as well as telling you WHY it does this:

Using Node.js require vs. ES6 import/export

Here's an excerpt:

"Update 2020

Since Node v12, support for ES modules is enabled by default, but it's still experimental at the time of writing this. Files including node modules must either end in .mjs or the nearest package.json file must contain "type": "module". The Node documentation has a ton more information, also about interop between CommonJS and ES modules."

To use import, do one of the following.

  1. Rename the .js file to .mjs
  2. In package.json file, add {type:module}

In my case. I think the problem is in the standard node executable. node target.ts

I replaced it with nodemon and surprisingly it worked!

The way using the standard executable (runner):

node target.ts

The way using the nodemon executable (runner):

nodemon target.ts

Do not forget to install nodemon with npm install nodemon ;P

Note: this works amazing for development. But, for runtime, you may execute node with the compiled js file!

This error also comes when you run the command

node filename.ts

and not

node filename.js

Simply put, with the node command we will have to run the JavaScript file (filename.js) and not the TypeScript file unless we are using a package like ts-node.

If you want to use BABEL, I have a simple solution for that!

Remember this is for nodejs example: like an expressJS server!

If you are going to use react or another framework, look in the babel documentation!

First, install (do not install unnecessary things that will only trash your project!)

npm install --save-dev @babel/core @babel/node

Just 2 WAO

then config your babel file in your repo!

example for express server node js and babel

file name:

babel.config.json

{
    "presets": ["@babel/preset-env"]
}


if you don't want to use the babel file, use:

Run in your console, and script.js is your entry point!

npx babel-node --presets @babel/preset-env -- script.js

example babel without file

the full information is here; https://babeljs.io/docs/en/babel-node

in the package.json write { "type": "module" }

it fixed my problem, I had the same problem

I had this error in my NX workspace after upgrading manually. The following change in each jest.config.js fixed it:

transform: {
  '^.+\\.(ts|js|html)$': 'jest-preset-angular',
},

to

transform: {
  '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular',
},

if you are using ES6 JS imports:

  1. install cross-env
  2. in package.json change "test": "jest" to "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest"
  3. more in package.json, add these:
    ...,
    "jest": {
        "transform": {}
    },
    "type": "module"

explanation: cross-env allows to change environment variables without changing npm command, next in package.json you change your npm command to enable experimental ES6 support for jest, and configure jest to do it

Just add --presets '@babel/preset-env'.

For example,

babel-node --trace-deprecation --presets '@babel/preset-env' ./yourscript.js

Or

in babel.config.js

module.exports = {
  presets: ['@babel/preset-env'],
};

To make your import work and avoid other issues, like modules not working in Node.js, just note that:

With ES6 modules you can not yet import directories. Your import should look like this:

import fs from './../node_modules/file-system/file-system.js'

I had this issue when I was running migration

Its es5 vs es6 issue

Here is how I solved it

I run

npm install @babel/register

and add

require("@babel/register")

at the top of my .sequelizerc file my

and go ahead to run my sequelize migrate. This is applicable to other things apart from sequelize

babel does the transpiling

My solution was to include babel-node path while running nodemon as follows:

nodemon node_modules/.bin/babel-node index.js

You can add in your package.json script as:

debug: nodemon node_modules/.bin/babel-node index.js

NOTE: My entry file is index.js. Replace it with your entry file (many have app.js/server.js).

  1. I had the same problem when I started to use Babel... But later, I had a solution... I haven't had the problem any more so far... Currently, Node.js v12.14.1, "@babel/node": "^7.8.4", I use babel-node and nodemon to execute (Node.js is fine as well..)
  2. package.json: "start": "nodemon --exec babel-node server.js "debug": "babel-node debug server.js"!! Note: server.js is my entry file, and you can use yours.
  3. launch.json. When you debug, you also need to configure your launch.json file "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/babel-node"!! Note: plus runtimeExecutable into the configuration.
  4. Of course, with babel-node, you also normally need and edit another file, such as the babel.config.js/.babelrc file

In case you're running nodemon for the Node.js version 12, use this command.

server.js is the "main" inside package.json file, replace it with the relevant file inside your package.json file:

nodemon --experimental-modules server.js

I recently had the issue. The fix which worked for me was to add this to file babel.config.json in the plugins section:

["@babel/plugin-transform-modules-commonjs", {
    "allowTopLevelThis": true,
    "loose": true,
    "lazy": true
  }],

I had some imported module with // and the error "cannot use import outside a module".

If you are using node, you should refer to this document. Just setup babel in your node app it will work and It worked for me.

npm install --save-dev @babel/cli @babel/core @babel/preset-env

When I use sequelize migrations with npx sequelize db:migrate I got this error so my solution for this was adding into .sequelizerc file the next line require('@babel/register'); as the next image shows enter image description here

be aware you must install babel and babel register

I'm new to NodeJS, I got the same issue for AWS Lambda function (using NodeJS) while fixing it

I found some of the differences between common-js and ES6 javascript:

ES6:

  • Add "type":"module" in package.json file

  • Use "import" to use from lib.

    Ex: import jwt_decode from jwt-decode

  • Lambda handler method code should be define like this

    "exports.handler = async (event) => { }"

common-js:

  • Don't add "type":"module" in package.json file

  • Use "require" to use from lib.

    Ex: const jwt_decode = require("jwt-decode");

  • Lambda handler method code should be define like this

    "export const handler = async (event) => { }"

I had this problem in a fledgling Express API project.

The offending server code in src/server/server.js:

import express from 'express';
import {initialDonationItems, initialExpenditureItems} from "./DemoData";

const server = express();

server.get('/api/expenditures', (req, res) => {
  res.type('json');
  res.send(initialExpenditureItems);
});

server.get('/api/donations', (req, res) => {
  res.type('json');
  res.send(initialDonationItems);
});

server.listen(4242, () => console.log('Server is running...'));

Here were my dependencies:

{
  "name": "contributor-api",
  "version": "0.0.1",
  "description": "A Node backend to provide storage services",
  "scripts": {
    "dev-server": "nodemon --exec babel-node src/server/server.js --ignore dist/",
    "test": "jest tests"
  },
  "license": "ISC",
  "dependencies": {
    "@babel/core": "^7.9.6",
    "@babel/node": "^7.8.7",
    "babel-loader": "^8.1.0",
    "express": "^4.17.1",
    "mysql2": "^2.1.0",
    "sequelize": "^5.21.7",
    "sequelize-cli": "^5.5.1"
  },
  "devDependencies": {
    "jest": "^25.5.4",
    "nodemon": "^2.0.3"
  }
}

And here was the runner that threw the error:

nodemon --exec babel-node src/server/server.js --ignore dist

This was frustrating, as I had a similar Express project that worked fine.

The solution was firstly to add this dependency:

npm install @babel/preset-env

And then to wire it in using a babel.config.js in the project root:

module.exports = {
  presets: ['@babel/preset-env'],
};

I don't fully grok why this works, but I copied it from an authoritative source, so I am happy to stick with it.

Taking out "module": "esnext" and making sure "moduleResolution": "node" is in it, that specific combo did it for me

Documentation is confusing. I use node.js to perform some local task in my computer.

Let's suppose my old script was test.js
Within it, if I want to use

import something from "./mylocalECMAmodule";

will throw a error like this

(node:16012) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
SyntaxError: Cannot use import statement outside a module
...

This is NOT a module error, but a node.js error, forbid loading anything outside a 'module'.

To fix this, just rename your old script test.js into test.mjs

That's all.

I had the same issue, I had copied the import statement in my Nodejs app. I fixed it by using require instead of import.

Simply just change it to:

const uuidv1 = require('uuid');

It will work fine.

Related