ts-node
ts-node copied to clipboard
ERR_UNKNOWN_FILE_EXTENSION on Node v20.0.0
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
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
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.
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
+1
The issue also appears when using the specially dedicated ESM runner
$ ts-node-esm file.ts
I went forward and downgraded my node version to lts.
However, doing node --loader ts-node/esm {file} did work for me.
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
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
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.
Yes, node --no-warnings=ExperimentalWarning --loader ts-node/esm file.ts helps to bypass the issue until it's fixed.
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.
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
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]
Yes,
node --no-warnings=ExperimentalWarning --loader ts-node/esm file.tshelps 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
@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"
@Maxim-Mazurok, @dandv Are you sure you flagged your files as ESM properly? This can either be done by renaming the files to
.mtsor by having thepackage.jsonfile 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.
When will you release a version that fixes this issue ? Last ts-node version is more than one year old :(
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
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
👋 I deleted the *lock files with node_modules and reinstalled the dependencies. In my case, it helped me!
I have the same issue. I tried using
--esm,{ "esm": true }and--loader="ts-node/register", but got theERR_UNKNOWN_FILE_EXTENSIONno matter what I tried. Could not getts-nodeto 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.
I have the same issue. I tried using
--esm,{ "esm": true }and--loader="ts-node/register", but got theERR_UNKNOWN_FILE_EXTENSIONno matter what I tried. Could not getts-nodeto 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.tsContext: 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"
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)
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)
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:
- 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
// ...
}
}
- set
type: modulein 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");
- 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.
issue remains unresolved, and is now present in NodeJS v21.0.0 also
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 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.
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)
tsx also doesn't properly support Node 20+ IME, and has performance issues.
@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.