Reputation: 7669
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",
Upvotes: 702
Views: 1881009
Reputation: 2435
In my case, I used the swc command to transpile, and the problem was the .swcrc
file missing. Due to the lack of this file, it was not being transpiled and that is why there is an error.
My solution:
Transpile command on package.json
"dist": "swc src -d dist --source-maps --copy-files",
.swcrc
config file:
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": false,
"dynamicImport": true,
"decorators": true
},
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
},
"target": "es2020",
"externalHelpers": false,
"keepClassNames": true,
"loose": false,
"minify": {
"compress": false,
"mangle": false
},
"baseUrl": "src",
"paths": {
"@/*": ["*"]
}
},
"module": {
"type": "commonjs"
}
}
Upvotes: 0
Reputation: 411
If you want to use Babel, I have a simple solution for that!
Remember this is for Node.js example: like an Express.js 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
Then configure your Babel file in your repository!
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
The full information is on @babel/node.
Upvotes: 4
Reputation: 367
If you are using the Vite - React application with the Speedy Web Compiler (SWC) and you tried to import the various methods of the Jest testing library
({import { describe, expect, test } from "@jest/globals";
), all your tests will run individually and outside the module. Hence you might get the error as:
SyntaxError: Cannot use import statement outside a module
Since you are using SWC, the Babel configuration won't help. So it could be resolved by just giving a simple development dependency:
npm install --save-dev @types/jest
Later remove the import statement, use methods (describe, test, expect, afterAll, afterEach, beforeAll, beforeEach, fail, fdescribe, fit, it, jasmine, jest, pending, spyOn, xdescribe, xit, xtest) directly since there are treated as globals. Install the link and other documentation here! @types/jest
Test your sum.test.js by npm run test
, supposing you have"test": "jest"
in scripts commands and jest in dev dependency:
const sum = (val1, val2) => {
return val1 + val2;
};
describe("sum module", () => {
test("adds 1 + 2 to equal 3", () => {
expect(sum(1, 2)).toBe(3);
});
});
Upvotes: 2
Reputation: 354
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!
The problem is that node
does not accept TypeScript files.
Instead, ts-node
might be the perfect replacement.
Upvotes: 6
Reputation: 61
For people coming to this question due to this error in Netlify functions even after adding "type": "module"
in the package.json file, update your netlify.toml file to use 'esbuild'. Since esbuild supports ES6, it would work.
[functions]
node_bundler = "esbuild"
Reference: Get started with functions
Upvotes: 1
Reputation: 377
Node.js 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);
});
Upvotes: 12
Reputation: 4016
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.
npm i typescript --save-dev
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"
}
}
Upvotes: 15
Reputation: 2349
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).
Upvotes: 0
Reputation: 651
If you are using Node.js, you should refer to this document. Just set up Babel in your Node.js application. It will work, and it worked for me.
npm install --save-dev @babel/cli @babel/core @babel/preset-env
Upvotes: 0
Reputation: 3123
I had this issue when I was running a migration.
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.
Upvotes: 2
Reputation: 697
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".
Upvotes: 0
Reputation: 12564
If you are using ES6 JavaScript imports:
cross-env
package.json
change "test": "jest"
to "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest"
package.json
, add these: ...,
"jest": {
"transform": {}
},
"type": "module"
Explanation:
cross-env allows to change environment variables without changing the npm command. Next, in file package.json you change your npm command to enable experimental ES6 support for Jest, and configure Jest to do it.
Upvotes: 10
Reputation: 307
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
Upvotes: 10
Reputation: 360
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
Upvotes: 20
Reputation: 5484
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.
Upvotes: 213
Reputation: 50008
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
.
Upvotes: 815
Reputation: 20420
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.
Upvotes: -1
Reputation: 1340
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": { ...
},
...
}
Upvotes: 124
Reputation: 15759
The common source of the problem is the MIME-type for "Module" type JavaScript files is not recognized as a "module" type by the server, the client, or the ECMAScript engine that process or deliver these files.
The problem is the developers of Module JavaScript files incorrectly associated Modules with a new ".mjs" (.js) extension, but then assigned it a MIME-type server type of "text/javascript". This means both .js and .mjs types are the same. In fact the new type for .js JavaScript files has also changed to "application/javascript", further confusing the issue. So Module JavaScript files are not being recognized by any of these systems, regardless of Node.js or Babel file processing systems in development.
The main problem is this new "module" subtype of JavaScript is yet known to most servers or clients (modern HTML5 browsers). In other words, they have no way to know what a Module file type truly is apart from a JavaScript type!
So, you get the response you posted, where the JavaScript engine is saying it needs to know if the file is a Module type of JavaScript file.
The only solution, for server or client, is to change your server or browser to deliver a new Mime-type that trigger ES6 support of Module files
, which have an .mjs
extension. Right now, the only way to do that is to either create a HTTP content-type
on the server of "module
" for any file with a .mjs
extension and change your file extension on module JavaScript files to ".mjs", or have an HTML script tag with type="module"
added to any external <script>
element you use that downloads your external .js
JavaScript module file.
Once you fool the browser or JavaScript engines into accepting the new Module file type, they will start doing their scripting circus tricks in the JS engines or Node.js systems you use.
Upvotes: 0
Reputation: 1669
The 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";
it will throw an 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.
Upvotes: 1
Reputation: 604
I'm new to Node.js, and I got the same issue for the AWS Lambda function (using Node.js) while fixing it.
I found some of the differences between CommonJS and ES6 JavaScript:
ES6:
Add "type":"module" in the package.json file
Use "import" to use from lib.
Example: import jwt_decode from jwt-decode
Lambda handler method code should be define like this
"exports.handler = async (event) => { }"
CommonJS:
Don't add "type":"module" in the package.json file
Use "require" to use from lib.
Example: const jwt_decode = require("jwt-decode");
The lambda handler method code should be defines like this:
"export const handler = async (event) => { }"
Upvotes: 8
Reputation: 2773
When I used sequelize migrations with npx sequelize db:migrate
, I got this error, so my solution for this was adding the line require('@babel/register');
into the .sequelizerc file as the following image shows:
Be aware you must install Babel and Babel register.
Upvotes: -1
Reputation: 1016
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):
Upvotes: 85
Reputation: 157
To use import, do one of the following.
Upvotes: 6
Reputation: 3521
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',
},
Upvotes: 3
Reputation: 8388
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'
Upvotes: 1
Reputation: 21
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
Upvotes: 0
Reputation: 2587
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.
Upvotes: 3
Reputation: 5303
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'],
};
Upvotes: 1
Reputation: 4917
I ran into the same issue and it's even worse: I needed both "import" and "require"
Here is what worked for me:
Turn your js file into .mjs as suggested in other answers
"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.
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
Upvotes: 55