ts-node-dev: [ERROR] Must use import to load ES module

Issue description

image

Context

Totally new Node project with typescript, @types/node, and ts-node-dev packages installed. I only get this error when I set type: "module" in package.json.

ts-node-dev: ^2.0.0

OS version (is it docker or host?), ts-node-dev version

Did you try to run with ts-node?

Did you try to run with --files option enabled?

Did you try to run with --debug option enabled?

Do you have a repro example (git repo) with simple steps to reproduce your problem?

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 75
  • Comments: 43

Commits related to this issue

Most upvoted comments

Update

Besides it working with Babel, I achieved to make it working with nodemon and ts-node.

Install nodemon and ts-node and of course typescript, set type: "module" in package.json, and set tsconfig.json to:

{
  "compilerOptions": {
    "esModuleInterop": true,
    "moduleResolution": "Node",
    "module": "ESNext",
    "target": "ESNext"
  }
}

And then: nodemon --exec node --loader ts-node/esm src/main.ts

I’m having the same problem

ts-node-dev version: 2.0.0 typescript version: 4.7.2

Same problem. I’m using ts-node-dev while i’m developing. And there the error occures. When i build my project for production with bable it’s woking. Yeah, with babel works.

You can try this config, I tested it with most ES2022 features (including Top Level Await) and it works.

{
  "type": "module",
  "name": "test_typescript_esm",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "dev": "nodemon -I --exec node --experimental-specifier-resolution=node  --loader ts-node/esm ./src/main.ts"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "nodemon": "^2.0.19",
    "ts-node": "^10.9.1",
    "typescript": "^4.7.4"
  },
  "exports": "./dist/index.js",
  "devDependencies": {
    "@babel/core": "^7.18.2",
    "@babel/node": "^7.17.10",
    "@babel/plugin-proposal-decorators": "*",
    "@babel/preset-env": "^7.18.2",
    "@types/node": "^18.6.2"
  }
}

if anyone want an alternative, i use tsx for about sometime and i love it, simple to use and maintained.

@angelhdzmultimedia,

My question is, is it mandatory to add this

We should somehow tell ts-node to use the loader that supports ESM. This can be done in one of the following ways:

1. Specify in tsconfig.json that the ts-node uses ESM loader

{
  "ts-node": {
    "esm": true
  }
}

In this case, you don’t need to specify additional arguments in nodemon command:

nodemon src/index.ts

2. Specify the ts-node command with ESM in nodemon:

nodemon --exec ts-node-esm src/index.ts

or

nodemon --exec 'ts-node --esm' src/index.ts

In this case, you don’t need to change the tsconfig.json file.

3. Set ts-node with ESM as the node loader

NODE_OPTIONS='--loader ts-node/esm' nodemon src/index.ts

or

nodemon --exec 'node --loader ts-node/esm' src/index.ts

I prefer the first case (set ts-node.esm to true in tsconfig), because it looks cleaner.

I solved my problem by simply removing “type” : “module” from package.json

and still nothing?

I’m using tsx now. No issues so far.

But thanks for the update. I’m gonna try ts-node-dev again with module resolution set to nodenext.

Is the ts-node set to esm mandatory?

Bun for Windows is out guys! 🔥👀✌️🤣

Bun, tsx, unjs/jiti. Solid options now.

Closing this.

I solved my problem by simply removing “type” : “module” from package.json

Sorry, but this is not a solution.

It is built on top of ts-node, and ts-node is a … please search on stackoverflow for solutions like --esm, remove { "type": "module" } … you will end up being recommended with tsx any way.

image

I don’t know what you’re trying to achieve, but I got it working with:

npx nodemon -e ts,json --exec node --experimental-specifier-resolution=node --loader ts-node/esm main.ts

Where main.ts is my main file in the root of my project.

image

I solved my problem by simply removing “type” : “module” from package.json

Sorry, but this is not a solution.

For me it is. Works fine.

My package.json:

{ "name": "general", "version": "1.0.0", "description": "", "main": "app.js", "scripts": { "dev": "ts-node-dev --respawn --transpile-only src/app.ts" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "ts-node-dev": "^2.0.0", "typescript": "^5.1.6" } }

According to the typescript documentation the moduleResolution must be:

  • node for Node.js’ CommonJS implementation
  • nodenext for Node.js’ ECMAScript Module Support from TypeScript 4.7 onwards.

So the moduleResolution must be nodenext for ESM. I created the repository with minimum configuration for restarting the node app when the file changes. It uses nodemon, because the ts-node-env doesn’t seem to support ESM yet.

I also encountered this problem. These contents may help you

node version : v16.13.2

package.json

{
  "devDependencies": {
    "@types/node": "^18.11.18",
    "nodemon": "^2.0.20",
    "ts-node": "^10.9.1",
    "typescript": "^4.9.4"
  },
  "scripts": {
    "dev": "nodemon --exec ts-node index.ts --project ./tsconfig.json"
  },
  "type": "module"
}

tsconfig.json

{
  "extends": "ts-node/node16/tsconfig.json",
  "ts-node": {
    "transpileOnly": true,
    "files": true,
    // Tell ts-node CLI to install the --loader automatically, explained below
    "esm": true,
    "compilerOptions": {
      "module": "ESNext"
    }
  },
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "Node",
    "lib": [
      "DOM",
      "ES2015"
    ],
    "target": "ES2015"
  }
}

i solved this problem removing “type”: “module” from my package.json and keeping just “module”: “CommonJS” on my tsconfig.json. it works fine.

Same problem here. I tried with

ts-node-esm --experimental-specifier-resolution=node --transpile-only ./src/index

and it works BUT it’ll not restart automatically if files will change

i solved this problem removing “type”: “module” from my package.json and keeping just “module”: “CommonJS” on my tsconfig.json. it works fine.

Yeah, yeah, “solved” and “works fine” (always were the words of the ignorant) - see you again later in the day when you figure out it’ll blow on all these “EVIL” ESM only packages or any other valid reason for ESM, e.g. publishing a package for others to use - then no ESM?! 🙀

Repo is looking stale, fair to say this isn’t getting fixed any time soon?

Seems that ts-node-esm and ts-node --esm are aliases of commands. ts-node/esm is the node loader.

I don’t see any of them being deprecated at the moment. So you can use any of these methods that you like best.

@angelhdzmultimedia Wow, tsx looks even better. I’ll try it. Thanks.

Is the ts-node set to esm mandatory?

Unfortunately, I don’t quite understand your question. To make ts-node compatible with ESM, we should use the appropriate loader in one of the following ways, but ts-node-dev (v2.0.0) still throws an error if ESM is used (Must use import to load ES Module).

P.S. tsx does not support type checking. We can, of course, run the TS compiler at first tsc --noEmit && tsx watch src/index.ts, but in this case, if we violated some types during watch mode, tsx doesn’t show any errors. This seems to be the main reason why tsx is faster than, for example, ts-node. IMO it’s inconvenient, because we don’t immediately know about mistakes in types.

We are looking forward to ESM support in ts-node-dev. In the meantime, we can use nodemon + ts-node if we need to check types in watch mode, or tsx if not.

I’m lately using node --watch ts-node/esm src/main.ts

I wonder what issues await the brave on that path (with latest Node, etc.), but would you share with us - why it’s not TSX anymore for you?

Just using it a day now, but works great so far, even already with Node 21.7.1.

And beside tons of features, it can also watch, same as TS-Node-Dev:

> tsx watch ./file.ts

I’m lately using node --watch ts-node/esm src/main.ts

And in tsconfig.json: { “ts-node”: { “experimentalSpecifierResolution”: “node”, “transpileOnly”: true, “esm”: true, } }

And works… good… I dream of a day where there’s only 1 configuration and working with TypeScript + Node is a pleasure… Waiting for Bun Windows 👀

if anyone want an alternative, i use tsx for about sometime and i love it, simple to use and maintained.

Thanks @angelhdzmultimedia and @ThallesP, works as great as you say - WoooF! 😻 😹💦

@angelhdzmultimedia,

My question is, is it mandatory to add this

We should somehow tell ts-node to use the loader that supports ESM. This can be done in one of the following ways:

1. Specify in tsconfig.json that the ts-node uses ESM loader

{
  "ts-node": {
    "esm": true
  }
}

In this case, you don’t need to specify additional arguments in nodemon command:

nodemon src/index.ts

2. Specify the ts-node command with ESM in nodemon:

nodemon --exec ts-node-esm src/index.ts

or

nodemon --exec 'ts-node --esm' src/index.ts

In this case, you don’t need to change the tsconfig.json file.

3. Set ts-node with ESM as the node loader

NODE_OPTIONS='--loader ts-node/esm' nodemon src/index.ts

or

nodemon --exec 'node --loader ts-node/esm' src/index.ts

I prefer the first case (set ts-node.esm to true in tsconfig), because it looks cleaner.

Thanks to your suggestions I got it working! There is one thing I didn’t get, I’m using TS, why do I need to import file adding the extension and this extension has be in .js?

import app from './api.js'
npx nodemon -e ts,json --exec 'node --experimental-specifier-resolution=node --loader ts-node/esm' <path>.js

not working on windows 😦

Got one-liner working with nodemon:

npx nodemon -e ts,json --exec 'node --experimental-specifier-resolution=node --loader ts-node/esm' <path>.js

mark