Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" in Node v21.5.0 #2100

Open
cibilex opened this issue Jan 8, 2024 · 64 comments

Comments

@cibilex
Copy link

cibilex commented Jan 8, 2024

First of all ,I already looked at #1997 and most of other websites to solve the problem but I couldn't.This error is throwed when I try to use in Node v21.5.0.I realized that The problem is node version,when I updated Node version to v19.0.0 it works.Could you please update ts-node to work in new Node versions.

Best regards.

@AaronNGray
Copy link

AaronNGray commented Jan 15, 2024

Getting same issue, but I have a working version that I solved this issue on, and now a new project on which it does not. It is something else and I cannot remember what it is. Will report back once I have debugged the issue.

@AaronNGray
Copy link

AaronNGray commented Jan 16, 2024

Heres a working example with node v21.5.0, typescript v5.3.3, ts-node v10.9.2 :-
https://github.com/AaronNGray/ts-node-example

NOTE: I have just found this does not seem to support imports !!!

@AaronNGray
Copy link

First of all ,I already looked at #1997 and most of other websites to solve the problem but I couldn't.This error is throwed when I try to use in Node v21.5.0.I realized that The problem is node version,when I updated Node version to v19.0.0 it works.Could you please update ts-node to work in new Node versions.

Could you please provide a minimal example of what does not work and then we can try to figure out why !

@peschee
Copy link

peschee commented Jan 16, 2024

Heres a working example with node v21.5.0, typescript v5.3.3, ts-node v10.9.2 :- https://github.com/AaronNGray/ts-node-example

This is not an ESM package. Try setting type to module in your package.json.

@AaronNGray
Copy link

AaronNGray commented Jan 16, 2024

Heres a working example with node v21.5.0, typescript v5.3.3, ts-node v10.9.2 :- https://github.com/AaronNGray/ts-node-example

This is not an ESM package. Try setting type to module in your package.json.

AFAICS I am not sure ts-node supports ESM. Could you provide the example that works on node v19.0.0, but not v21.5.0. Or is it as simple as setting "type":"module" ? As in :-
https://github.com/AaronNGray/ts-node-example/tree/ts-node-esm-module

on v21.5.0 resulting in :-

C:\Users\Nathaniel\test\Node.js\ts-node-example>npm start

> ts-node-example@0.0.1 start
> ts-node src/index.ts

TypeError: Unknown file extension ".ts" for C:\Users\Nathaniel\test\Node.js\ts-node-example\src\index.ts
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:160:9)
    at defaultGetFormat (node:internal/modules/esm/get_format:203:36)
    at defaultLoad (node:internal/modules/esm/load:143:22)
    at async ModuleLoader.load (node:internal/modules/esm/loader:409:7)
    at async ModuleLoader.moduleProvider (node:internal/modules/esm/loader:291:45)
    at async link (node:internal/modules/esm/module_job:76:21) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}

@AaronNGray
Copy link

AaronNGray commented Jan 16, 2024

Adding :-

"start:node": "node --loader ts-node/esm src/index.ts"

and tsconfig.json :-

"module": "esnext"

We have :-

https://github.com/AaronNGray/ts-node-example/tree/ts-node-esm-loader

which gives :-

C:\Users\Nathaniel\test\Node.js\ts-node-example>npm run start:node

> ts-node-example@0.0.1 start:node
> node --loader ts-node/esm src/index.ts

(node:18508) ExperimentalWarning: `--experimental-loader` may be removed in the future; instead use `register()`:
--import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("ts-node/esm", pathToFileURL("./"));'
(Use `node --trace-warnings ...` to show where the warning was created)
ts-node

NOTE: I have just found this does not seem to support imports !!!

@cibilex
Copy link
Author

cibilex commented Jan 16, 2024

First of all ,I already looked at #1997 and most of other websites to solve the problem but I couldn't.This error is throwed when I try to use in Node v21.5.0.I realized that The problem is node version,when I updated Node version to v19.0.0 it works.Could you please update ts-node to work in new Node versions.

Could you please provide a minimal example of what does not work and then we can try to figure out why !

I've modified the project a bit and created new repository.link: https://github.com/cibilex/ts-node-err

This project doesn't work in node v21.5.0 while works In node v16.20.2 for me.

@AaronNGray
Copy link

AaronNGray commented Jan 16, 2024

First of all ,I already looked at #1997 and most of other websites to solve the problem but I couldn't.This error is throwed when I try to use in Node v21.5.0.I realized that The problem is node version,when I updated Node version to v19.0.0 it works.Could you please update ts-node to work in new Node versions.

Could you please provide a minimal example of what does not work and then we can try to figure out why !

I've modified the project a bit and created new repository.link: https://github.com/cibilex/ts-node-err

This project doesn't work in node v21.5.0 while works In node v16.20.2 for me.

You modified start to : -"start": "ts-node-esm src/index.ts"

The version I posted last works AFAICT without proper testing, but I did do an import

Note: --loader maybe deprecated.

https://github.com/AaronNGray/ts-node-example/tree/ts-node-esm-loader

NOTE: I have just found this does not seem to support imports !!!

@AaronNGray
Copy link

@cibilex - Theres a pull request waiting :- #2073

@cibilex
Copy link
Author

cibilex commented Jan 17, 2024

@cibilex - Theres a pull request waiting :- #2073

Thank you a lot,It works now splendid :)

@AaronNGray
Copy link

AaronNGray commented Jan 17, 2024

@cibilex - Did you manage to add the two commits to a ts-node fork or did you just patch the diff's ?
If you used git I would love to know how ! On the other front I seem to remember GitHub giving diffs but it does not seem to have downloads for them anymore. Or did you just use a reference to the repo in package.json dependencies ?

@cj-christoph-gysin
Copy link

@cibilex - Did you manage to add the two commits to a ts-node fork or did you just patch the diff's ? If you used git I would love to know how !

$ git fetch https://github.com/TypeStrong/ts-node refs/pull/2073/head
$ git checkout -b pr-2073 FETCH_HEAD

On the other front I seem to remember GitHub giving diffs but it does not seem to have downloads for them anymore.

You can just add .diff or .patch to any github url for a commit or PR, e.g.: https://github.com/TypeStrong/ts-node/pull/2073.diff

@AaronNGray
Copy link

@cibilex - Wow great thanks, think I was over complicating things :)

@MickL
Copy link

MickL commented Feb 14, 2024

Guys no need for ts-node, just use Deno or Bun:

deno run main.ts
bun run main.ts

@russell-miburn
Copy link

Is there an update on the progress of this bug?

@francip
Copy link

francip commented Feb 27, 2024

To summarize: Looks like this has been there for a while. Adding "type"="module" to package.json breaks ts-node --esm for any node version above v16.

The workarounds I've found so far:

  • remove "type="module"
  • downgrade to node v16
  • use node --loader ts-node/esm instead of ts-node --esm (comes with a warning)
  • use node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("ts-node/esm", pathToFileURL("./"));' instead of ts-node --esm (to avoid the warning)
  • use tsx instead of ts-node

If you are using webpack in your project, this also breaks using Typescript config files. The only workaround for this are:

  • switch back to JS config file
  • remove "type="module"
  • downgrade to node v16

@zq0904
Copy link

zq0904 commented Feb 28, 2024

First of all ,I already looked at #1997 and most of other websites to solve the problem but I couldn't.This error is throwed when I try to use in Node v21.5.0.I realized that The problem is node version,when I updated Node version to v19.0.0 it works.Could you please update ts-node to work in new Node versions.

Best regards.

Odd-numbered versions of node are typically beta versions and should not be supported

@russell-miburn
Copy link

I realised that the issue that I had was not with the version of node or ts-node but I was importing a typescript dependancy incorrectly from a library. removing the dependency i was importing and importing the .js from the library rather that a typescript file fixed this issues.

@francip
Copy link

francip commented Mar 3, 2024

Update: The node version where ts-node with package.json "type"="module" breaks is v18.19.0

Simple repro - francip/ts-node-test

@djomajeff
Copy link

I use node v20.10.0.

In Package.json apply this configuration:

  • Here is my start script : nodemon --exec node --no-warnings=ExperimentalWarning --loader ts-node/esm src/index.ts
  • Add "type": "module",
  • In dependencies add the matching @types dependencies in devDependencies if exists on npm for type completion:
    "devDependencies": { "@types/node": "^20.11.26", "@types/jsonwebtoken": "^9.0.6", "@types/express": "^4.17.21", "nodemon": "^3.1.0", "ts-node": "^10.9.2", "typescript": "^5.4.2" }, "dependencies": { "cors": "^2.8.5", "express": "^4.18.3", "jsonwebtoken": "^9.0.2" }

In tsconfig.json apply the following:

  • "module": "ESNext", "target": "ESNext"
  • "esModuleInterop": true, "moduleResolution": "Node"
  • At the same level of compiler option add "ts-node": { "esm": true, }

Hope It will work !!

@AaronNGray
Copy link

AaronNGray commented Mar 13, 2024

@djomajeff - building a repo following your instructions I am getting :- AaronNGray/ts-node-esm-test#1

I added you to the repo.

@AaronNGray
Copy link

AaronNGray commented Mar 17, 2024

@cibilex https://github.com/AaronNGray/ts-node-esm-test works fine now !
I have added a node --test example too.

@sleep-written
Copy link

sleep-written commented Apr 4, 2024

One of the reasons for the failures with ts-node in ESM projects is linked to the file extensions in import statements. To understand the problem, let's envision this directory structure:

.
├── node_modules
├── src
│   ├── sum.ts
│   └── index.ts
├── package.json
├── package-lock.json
└── tsconfig.json

In ESM, you must use the .js extension in your imports. For example, check ./src/index.ts:

import { sum } from './sum.js';  // ...but in reality, the actual file ends in ".ts"

const r = sum(55, 66);
console.log('value:', r);

Thus, when the original ts-node loader receives that import ./sum.js, it tries to resolve it as a ".js" file. But in reality, that file does not exist, and the available file ends with ".ts". To solve the problem, you have several options:

  • Rename all your imports from ".js" to ".ts":

    This solves the problem with ts-node, but when you transpile your project, you will need to transform your imports back to ".js".

  • Modify the ts-node loader:

    You must intercept all import statements and change the extension from ".js" to ".ts" only when attempting to execute ".ts" files.

I have created a module called @bleed-believer/path-alias (with ts-node as a dependency). Initially created to resolve path aliases, it now also solves this issue. To execute TypeScript files in ESM directly in Node 20 and above:

# Install the library:
npm i --save @bleed-believer/path-alias

# Execute your code using the command line:
npx bb-path-alias ./src/index.ts

# ...or if you need to execute using the node executable:
node --import @bleed-believer/path-alias ./src/index.ts

@francip
Copy link

francip commented Apr 4, 2024

@sleep-written Both ECMA 2025 and ECMA 2020 do not specify explicit extension, and the only import examples I found in both ( ECMA 2025, ECMA 2020 ) do not include any extension. But that's neither here, nor there...

If you look at my example, you will see nowhere do I use import statement, and the failure happens with a single file project. This is a basic scenario where ts-node should work without extra intermediaries.

Though, for folks who are just looking for a quick workaround, your solution might be good.

@sleep-written
Copy link

sleep-written commented Apr 5, 2024

Hi @francip, your example is relevant for Node.js versions 18 and earlier. However, when using Node.js version 20 or above with the command:

node --loader ts-node/esm ./src/index.ts

...you might encounter the following output:

(node:2036531) ExperimentalWarning: --experimental-loader may be removed in the future; instead use register():
--import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("ts-node/esm", pathToFileURL("./"));'
(Use node --trace-warnings ... to show where the warning was created)

To address this, consider creating a ./ts-node.register.mjs file with:

import { pathToFileURL } from "node:url";
import { register } from "node:module";

register("ts-node/esm", pathToFileURL("./"));

And then launch your application with:

node --import ./ts-node.register.mjs ./src/index.ts

This approach should seamlessly solve the issue, unless your project uses relative imports. According to the Node.js import specifiers:

Relative specifiers like './startup.js' or '../config.mjs'. They refer to a path relative to the location of the importing file. The file extension is always necessary for these.

More details of this problem are explained in this comment.
If executing your file with the ./ts-node.register.mjs preloaded results in errors due to relative imports, consider using my module register at @bleed-believer/path-alias. This or building a custom ts-node module register, with the required logic for address relative/absolute imports, could provide a solution too.

@StreetStrider
Copy link

StreetStrider commented Jun 26, 2024

@kolya182 although this looks weird, this is actually most logical way to import, considering ESM requires explicit extension, and TS exists in static time only. Extensionless is not a way anymore, so the only alternative is to have explicit .ts extension instead, which, by ESM rules, means «custom loader». If you introduce custom extention to your stack that is always more hard to setup and it is more error prone. You'll need to learn every part of your stack to understand it. It is an overkill when all you need is just a simple 1-to-1 relation between TS and corresponding JS file.

After a consideration, it turns out that this is a bliss that TS just works in such case. You can easily import .js, no custom resolvers/loaders involved and TS understands it out of the box. And later the code can be easily translated to JS without need to visit and rewrite each import, just stripping types would be enough.

@AaronNGray
Copy link

AaronNGray commented Jun 26, 2024

@francip - It an engineering solution, it works, is minimally annoying, not perfect, but at the end of the day we can get on and do work, whch is what really matters. niceties aside. Yes I don't like it either and this should have been sorted out properly long ago.

@DzmVasileusky
Copy link

@AaronNGray Importing .ts as .js extension is super confusing and really not obvious, did you add it to official docs because I doubt anyone will try this really without a hint?

@AaronNGray
Copy link

Hi @DzmVasileusky no I am hoping there will be a proper solution in the pipeline. This is just an “engineering solution” that will help people out for now so they can get on until a patch that solves this properly comes through. Your welcome to update the docs but it’s also dependent on tsconfig.json settings, and also settings in package.json.

@francip
Copy link

francip commented Jun 27, 2024

@AaronNGray I am aware (couple of variations) of the "engineering" solution :-) But as you said it yourself, this is not proper user-friendly solution. When you say

This is no longer an issue and has all been solved

people will tend to believe that the proper solution has been done.

@AaronNGray
Copy link

@francip I believe there is a PR. I have not looked at it thought. Anyway best not to be a perfectionist over having a working solution.

kleekich21 added a commit to f-lab-edu/deeply-copy that referenced this issue Jul 2, 2024
NOTE: npx ts-node renameFiles.ts not working
issue: TypeStrong/ts-node#2100
@ParrotStone
Copy link

Facing same issue. Node v22.4.0

james04321 added a commit to figma/variables-github-action-example that referenced this issue Jul 23, 2024
Use tsx instead of ts-node, which is [broken on Node >20](TypeStrong/ts-node#2100).

Before:

```
$ npm run sync-figma-to-tokens

> sync-figma-to-tokens
> ts-node-esm -P tsconfig.json src/sync_figma_to_tokens.ts

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/jyang/figma/variables-github-action-example/src/sync_figma_to_tokens.ts
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:160:9)
    at defaultGetFormat (node:internal/modules/esm/get_format:203:36)
    at defaultLoad (node:internal/modules/esm/load:143:22)
    at async nextLoad (node:internal/modules/esm/hooks:866:22)
    at async nextLoad (node:internal/modules/esm/hooks:866:22)
    at async Hooks.load (node:internal/modules/esm/hooks:449:20)
    at async MessagePort.handleMessage (node:internal/modules/esm/worker:196:18) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
```

After:

```
$ npm run sync-figma-to-tokens

> sync-figma-to-tokens
> tsx src/sync_figma_to_tokens.ts

Wrote Primitives — Completed.Modern Theme.json
Wrote Primitives — Completed.Brutal Theme.json
Wrote Tokens — Completed.Light.json
Wrote Tokens — Completed.Dark.json
Wrote Product interactions — Completed.Default.json
✅ Tokens files have been written to the tokens_new directory
```
@niz11
Copy link

niz11 commented Aug 8, 2024

Facing same issue. Node v22.4.0

Same. The quick fix I got from above which is working for me at the moment is:
node --no-warnings=ExperimentalWarning --loader ts-node/esm app.ts

@egoroof
Copy link

egoroof commented Aug 8, 2024

fixed for me with https://github.com/privatenumber/tsx

lassidevs added a commit to lassidevs/helloer that referenced this issue Sep 8, 2024
Changed from ts-node to node with ts-node/esm as the loader. There is a
bug with ts-node that breaks things when using ESM style modules only.
see: TypeStrong/ts-node#2100
@icocoding

This comment was marked as abuse.

swiing added a commit to swiing/Bit-TypedArray that referenced this issue Sep 22, 2024
With node v2x, running tests results in error
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"

See TypeStrong/ts-node#2100

Solved as per TypeStrong/ts-node#2100 (comment)
wolfy1339 added a commit to probot/probot.github.io that referenced this issue Sep 30, 2024
@jswhisperer
Copy link

55 comments on running .ts with ts-node, 🤦
Same issue here.

@StreetStrider
Copy link

@gregpalaci it was a big deal back in the day, but it's not quite one as of today:

  • There're various alternatives.
  • There's a hack to workaround this (see above in the thread).
  • Node 22 introduces --experimental-strip-types, they were incentivized by competitors, so I think it is a matter of time for Node to fully support running TS.
  • Deno supports TS out of the box.
  • Bun supports TS out of the box.

With three major runtimes able to just run TS, I think ts-node must be retired, along with its every alternative.

@jswhisperer
Copy link

@gregpalaci it was a big deal back in the day, but it's not quite one as of today:

  • There're various alternatives.
  • There's a hack to workaround this (see above in the thread).
  • Node 22 introduces --experimental-strip-types, they were incentivized by competitors, so I think it is a matter of time for Node to fully support running TS.
  • Deno supports TS out of the box.
  • Bun supports TS out of the box.

With three major runtimes able to just run TS, I think ts-node must be retired, along with its every alternative.

Totally I understand that sentiment, normally scaffold with vite and it takes care of it for me. I recently tried a project with no TS setup and it's sooo a bad DX still to get going. module and moduleResolution bundler so many things to try. This project mostly worked with tsx, tried bun and randomly a import failed { pg } from pg became a default pg from pg in bun?!

The unclearness and so many "solutions" is overwhelming at times, all of them get you 90% of the way.

@TamirCode
Copy link

It's sad that I have to switch from nodemon ts-node to TSX watch, because nodemon had the coolest color coding on console. But this is the only way in 2024.
The other option is using node's --watch but that has no color coding at all and the logs are ugly in the console.

color-coding aside, TSX is much more reliable and also it's 1 package instead of 2 (nodemon / ts-node), so it's a nice upgrade

@androiderik
Copy link

Remove the property:

 {
"type": "module"
}

from your package.json and that's it, there was conflict between this property making node trying to use modules without the use of ts-node. In this case there's no need to use this property yet.

@jswhisperer
Copy link

Yeah found npx -y tsx foo.ts the best bet for package.json scripts

@aintabb
Copy link

aintabb commented Nov 3, 2024

@gregpalaci Your solution worked for me. Thanks for sharing!

@someu
Copy link

someu commented Nov 11, 2024

Node version 18.17.0 where ts-node with package.json "type"="module" work fine

@francip
Copy link

francip commented Nov 22, 2024

@someu yes, because the version that broke it is v18.19.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests