ts-node icon indicating copy to clipboard operation
ts-node copied to clipboard

ERR_UNKNOWN_FILE_EXTENSION on Node v20.0.0

Open septs opened this issue 2 years ago • 120 comments

Search Terms

Node, ERR_UNKNOWN_FILE_EXTENSION

Expected Behavior

Fix it

Actual Behavior

see Minimal reproduction

Steps to reproduce the problem

see Minimal reproduction

Minimal reproduction

$ cat example.ts
console.log('example')
$ cat tsconfig.json
{ "ts-node": { "esm": true } }
$ npx ts-node example.ts
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/septs/Projects/example/example.ts
    at new NodeError (node:internal/errors:399:5)
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:99:9)
    at defaultGetFormat (node:internal/modules/esm/get_format:139:38)
    at defaultLoad (node:internal/modules/esm/load:83:20)
    at nextLoad (node:internal/modules/esm/hooks:781:28)
    at load (/Users/septs/.npm/_npx/1bf7c3c15bf47d04/node_modules/ts-node/dist/child/child-loader.js:19:122)
    at nextLoad (node:internal/modules/esm/hooks:781:28)
    at Hooks.load (node:internal/modules/esm/hooks:381:26)
    at handleMessage (node:internal/modules/esm/worker:153:24)
    at checkForMessages (node:internal/modules/esm/worker:102:28) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}

Specifications

  • ts-node version: 10.9.1

  • node version: 20.0.0

  • TypeScript version: 5.0

  • tsconfig.json:

    { "ts-node": { "esm": true } }
    
  • package.json:

    {}
    
  • Operating system and version: macOS 13.3.1

septs avatar Apr 20 '23 02:04 septs

https://github.com/microsoft/TypeScript/issues/53922


Edited by 11/18/2023

Use tsx replace ts-node?

Or use ts-node@beta?

more see https://github.com/privatenumber/tsx, https://github.com/TypeStrong/ts-node/issues/2077

septs avatar Apr 20 '23 02:04 septs

I have the same issue. I tried using --esm, { "esm": true } and --loader="ts-node/register", but got the ERR_UNKNOWN_FILE_EXTENSION no matter what I tried. Could not get ts-node to run on Node v20 with native ESM modules.

csvn avatar Apr 20 '23 12:04 csvn

FYI Node 20 has made a breaking change:

Custom ESM loader hooks run on dedicated thread ESM hooks supplied via loaders (--experimental-loader=foo.mjs) now run in a dedicated thread, isolated from the main thread. This provides a separate scope for loaders and ensures no cross-contamination between loaders and application code.

https://nodejs.org/en/blog/release/v20.0.0

Jack-Works avatar Apr 21 '23 07:04 Jack-Works

+1

The issue also appears when using the specially dedicated ESM runner

$ ts-node-esm file.ts

RobinTail avatar Apr 21 '23 10:04 RobinTail

I went forward and downgraded my node version to lts. However, doing node --loader ts-node/esm {file} did work for me.

neurolag avatar Apr 22 '23 19:04 neurolag

i expirience the same issue on:

# node --version
v18.16.0

EDIT: my bad, i misinterpreted the gravity of the situation. manually enforcing the loader like this.

{
  "start": "npm run clean && cross-env NODE_ENV=development NODE_OPTIONS=\"--loader=ts-node/esm --trace-warnings\" webpack serve --mode=development --config webpack.config.ts",
}

worked out.

example sourced from here: https://github.com/webpack/webpack-cli/issues/2458

wibed avatar Apr 23 '23 10:04 wibed

i expirience the same issue on: Node v20, I tried: $ node --loader ts-node/esm ./path It worked for me but getting this warnning: ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time

RandivCosta avatar Apr 29 '23 19:04 RandivCosta

I'd like to add quickly that on windows (at least), doing node --loader ts-node/esm ./path works but with an insanely high CPU usage. Doing a quick npx tsc + node ./build/app.js works perfectly without the performance issue.

sywesk avatar May 04 '23 18:05 sywesk

Yes, node --no-warnings=ExperimentalWarning --loader ts-node/esm file.ts helps to bypass the issue until it's fixed.

RobinTail avatar May 06 '23 10:05 RobinTail

yeah, I recently upgraded to node 20 and started running with the --loader ts-node/esm parameter but noticed that my memory usage in my application had skyrocketed to 32G before it would die from OOM. I went chasing for a cause because I assumed it was due to a change I made, but downgrading to node 19 lowered memory usage down to around 500M again. I assume this is probably related to the CPU issues @sywesk had.

So I'd recommend people stay off Node 20 until this is fixed if you don't want to have unexpected issues in your runtime.

Aenigma avatar May 06 '23 17:05 Aenigma

Can't use esm:

node --loader ts-node/esm ./src/tools/spell-check.ts
(node:18954) ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
file:///home/maxim/MyProject/src/tools/spell-check.ts:39
Object.defineProperty(exports, "__esModule", { value: true });
                      ^

ReferenceError: exports is not defined in ES module scope
    at file:///home/maxim/WebWatcher/Frontend/src/tools/spell-check.ts:39:23
    at ModuleJob.run (node:internal/modules/esm/module_job:192:25)

Node.js v20.2.0

Maxim-Mazurok avatar Jun 02 '23 06:06 Maxim-Mazurok

I'm getting the same error as @Maxim-Mazurok when running a file that only does console.log(). I'm using the node20 Docker image:

docker run -it --name node20 -v "$PWD":/usr/src/myapp -w /usr/src/myapp node /bin/bash
# cat test.ts
console.log('hi');
root@12071c96b5fc:/usr/src/myapp# node --loader=ts-node/esm test.ts
(node:101) ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
file:///usr/src/myapp/test.ts:2
Object.defineProperty(exports, "__esModule", { value: true });
                      ^

ReferenceError: exports is not defined in ES module scope
    at file:///usr/src/myapp/test.ts:2:23
    at ModuleJob.run (node:internal/modules/esm/module_job:192:25)

Node.js v20.2.0
root@12071c96b5fc:/usr/src/myapp# node --version
v20.2.0
root@12071c96b5fc:/usr/src/myapp# npm ls ts-node
ts-code-samples@ /usr/src/myapp
`-- [email protected]

dandv avatar Jun 06 '23 13:06 dandv

Yes, node --no-warnings=ExperimentalWarning --loader ts-node/esm file.ts helps to bypass the issue until it's fixed. @RobinTail

Note — by using --no-warnings=ExperimentalWarning you're suppressing all node warnings because --no-warnings flag does not handle a value. --no-warnings works the same. https://nodejs.org/api/cli.html#--no-warnings

erictheswift avatar Jun 07 '23 10:06 erictheswift

@Maxim-Mazurok, @dandv Are you sure you flagged your files as ESM properly? This can either be done by renaming the files to .mts or by having the package.json file corresponding to the source file containing "type": "module"

neurolag avatar Jun 08 '23 08:06 neurolag

@Maxim-Mazurok, @dandv Are you sure you flagged your files as ESM properly? This can either be done by renaming the files to .mts or by having the package.json file corresponding to the source file containing "type": "module"

I use CJS, and have type: commonjs in my package.json.

The following ended up working for me: tsconfig.node.json:

{
  "extends": "@tsconfig/node18/tsconfig.json",
  "include": [
    "vite.config.*",
    "vitest.config.*",
    "cypress.config.*",
    "playwright.config.*",
    "orval.config.*",
    "src/tools/**/*"
  ],
  "compilerOptions": {
    "composite": true,
    "types": ["node"]
  }
}

(inherited "module": "Node16", "target": "es2022")

package.json scripts:

"ts-node-tool": "cross-env TS_NODE_PROJECT=\"tsconfig.node.json\" ts-node",
"my-tool": "npm run ts-node-tool ./src/tools/my-tool.ts"

Of course, can't use top-level await and had to use tsimportlib to import esm deps, might find more on that in https://github.com/Maxim-Mazurok/esm-in-cjs-ts-demo

Unsubscribing for now as I'm no longer blocked and happy with a solution. Hope it helps someone.

Maxim-Mazurok avatar Jun 10 '23 07:06 Maxim-Mazurok

When will you release a version that fixes this issue ? Last ts-node version is more than one year old :(

AlexandreFournier avatar Jun 16 '23 07:06 AlexandreFournier

Just chiming in here regarding the OOM issue: I believe it's FUD today and you're safe to update and use the workarounds detailed in this thread. The OOM issue with node on macOS was fixed in 20.1.0, see https://github.com/nodejs/node/issues/47761#issuecomment-1533793099

danieltroger avatar Jul 24 '23 15:07 danieltroger

One problem with the workarounds is that they hide any typos you have in your code. Like this isn't very helpful:

$ node --loader ts-node/esm example.ts 

node:internal/process/esm_loader:46
      internalBinding('errors').triggerUncaughtException(
                                ^
[Object: null prototype] {
  [Symbol(nodejs.util.inspect.custom)]: [Function: [nodejs.util.inspect.custom]]
}

Node.js v20.4.0

Yet if you feed the same file into tsc it gives you a much more useful error:

$ npx tsc
example.ts:71:1 - error TS2304: Cannot find name 'make_an_error_happen'.

71 make_an_error_happen
   ~~~~~~~~~~~~~~~~~~~~
Found 1 error in example.ts:71

adam-nielsen avatar Aug 07 '23 03:08 adam-nielsen

👋 I deleted the *lock files with node_modules and reinstalled the dependencies. In my case, it helped me!

floatrx avatar Aug 17 '23 15:08 floatrx

I have the same issue. I tried using --esm, { "esm": true } and --loader="ts-node/register", but got the ERR_UNKNOWN_FILE_EXTENSION no matter what I tried. Could not get ts-node to run on Node v20 with native ESM modules.

Same problem here. Fortunately, I don't need 20, so I just downgraded to v19.9 and it works. EG: ts-node --esm index.ts

Context: using vitejs to build typescript projects.

paxperscientiam avatar Aug 25 '23 06:08 paxperscientiam

I have the same issue. I tried using --esm, { "esm": true } and --loader="ts-node/register", but got the ERR_UNKNOWN_FILE_EXTENSION no matter what I tried. Could not get ts-node to run on Node v20 with native ESM modules.

Same problem here. Fortunately, I don't need 20, so I just downgraded to v19.9 and it works. EG: ts-node --esm index.ts

Context: using vitejs to build typescript projects.

Are you sure this is the command you executed? --loader="ts-node/register" is not correct. For ESM support, you need to pass --loader="ts-node/esm"

neurolag avatar Aug 25 '23 09:08 neurolag

I also have run into this issue w/ Node v20. The workaround to run node --loader ts-node/esm runs, but the line numbers in Error stack traces are incorrect. I think this must be related to the breaking changes, and some impact on source maps.

Here is what my (incorrect) stack trace looks like using the workaround in Node v20:

$ node -r ts-node/transpilers/swc --loader ts-node/esm --no-warnings --test ./api/src/shared/socket-set.test.ts:
  TypeError [Error]: Cannot read properties of undefined (reading 'once')
      at SocketSet.add (file:///Users/blah/blah/api/src/shared/socket-set.ts:47:20)

Here is what my (correct) stack trace looks like using the workaround in Node v19:

$ node -r ts-node/transpilers/swc --loader ts-node/esm --no-warnings --test ./api/src/shared/socket-set.test.ts:
  TypeError: "Cannot read properties of undefined (reading 'once')"
      at SocketSet.add (file:///Users/blah/blah/api/src/shared/socket-set.ts:58:14)

thesmart avatar Aug 26 '23 00:08 thesmart

I tried out tsx to see if it also has issues with Node v20 and it does.

Node v20 line numbers seem to be based on single-line transpiled code:

$ node --loader tsx --no-warnings --test ./api/src/shared/socket-set.test.ts:
  TypeError [Error]: Cannot read properties of undefined (reading 'once')
      at SocketSet.add (file:///Users/blah/blah/api/src/shared/socket-set.ts:1:970)

Node v18 produces correct line numbers:

$ node --loader tsx --no-warnings --test ./api/src/shared/socket-set.test.ts:
  TypeError [Error]: Cannot read properties of undefined (reading 'once')
     at SocketSet.add (file:///Users/blah/blah/api/src/shared/socket-set.ts:62:14)

thesmart avatar Aug 26 '23 18:08 thesmart

I encountered this issue when trying to run mocha tests with native ES modules, after reviewing a lot of suggestions above, searching a lot of web pages, and doing a lot of try-outs, I finally got it worked.

Here is what I do:

  1. set these compiler options options in tsconfig.json
{
    "compilerOptions": {
        "module": "esnext", // of course
        "noEmit": true,
        "allowImportingTsExtensions": true, // This is optional, but since I use this style, I need to turn it on.
        "esModuleInterop": true, //This is required since some of the dependencies are CommonJS packages.
        "moduleResolution": "NodeNext", // required
        // ...
    }
}
  1. set type: module in package.json (this is the key setting), since I'm coding a dual module system package, I wrote two scripts to temporarily change this setting during the test.
// pretest.cjs
const fs = require("fs");
const pkg = require("./package.json");

pkg.type = "module";

fs.writeFileSync("./package.json", JSON.stringify(pkg, null, "    ") + "\n", "utf8");
// posttest.cjs
const fs = require("fs");
const pkg = require("./package.json");

delete pkg.type;

fs.writeFileSync("./package.json", JSON.stringify(pkg, null, "    "), "utf8");
  1. Change the test command to this:
{
    "script": {
        "pretest": "node pretest.cjs",
        "posttest": "node posttest.cjs",
        // use `node --loader=ts-node/esm mocha` in stead of `mocha -r ts-node/esm`
        "test": "node --no-warnings=ExperimentalWarning --loader=ts-node/esm ./node_modules/mocha/bin/mocha *.test.ts"
    }
}

This configuration allows me to test from Node.js v14 (TypeScript 5.x demands) to v20.

Hope this helps others, especially for doing mocha tests.

ayonli avatar Sep 19 '23 12:09 ayonli

issue remains unresolved, and is now present in NodeJS v21.0.0 also

rosmcmahon avatar Oct 19 '23 01:10 rosmcmahon

Don't know if this is an acceptable work around for most people here but we switched to tsx https://github.com/esbuild-kit/tsx for the time being as upgrading to Node v20 (the now current LTS) was important to us.

atomicptr avatar Oct 19 '23 02:10 atomicptr

@atomicptr I was able to avoid tsx with the following work around:

package.json

{
    "type": "module",
    "scripts": {
        "start": "node --loader ts-node/esm src/app.ts",
        "test": "c8 --reporter=html node --loader=ts-node/esm node_modules/mocha/lib/cli/cli.js  --grep '' 'tests/**/*.ts'"
    },
    // dependencies
}

I've included the testing part as well, because it was a real pain in the ass to setup it up for a project that is ESM only, since jest and nyc don't work well with ESM only projects but mocha and c8 worked great!

tsconfig.json

{
    "compilerOptions": {
        "target": "es6",
        "module": "NodeNext",
        "outDir": "dist",
        "rootDir": "src",
        "strict": true,
        "esModuleInterop": true,
        "moduleResolution": "NodeNext",
        "sourceMap": true,
        "removeComments": true
    },
    "include": [
        "src"
    ],
    "ts-node": {
        "esm": true
    }
}

and from command like, since I can't just run ts-node, I had to alias it: alias tn="node --loader ts-node/esm"

I'm relatively new to nodejs and typescript, so if you noticed something weird feel free to suggest improvements.

eldare avatar Oct 19 '23 08:10 eldare

The problem still remains in Node.js v20.8.1,and the work arround node --loader ts-node/esm src/app.ts could work, with the following warning outputs:

(node:42788) 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)

kamaslau avatar Oct 22 '23 09:10 kamaslau

tsx also doesn't properly support Node 20+ IME, and has performance issues.

nickserv avatar Oct 23 '23 06:10 nickserv

@kamaslau I see it too, but I don't see any side effect from this warning. Everything works great. And since TypeScript is for development only, I can live with a small warning.

eldare avatar Oct 23 '23 11:10 eldare