Solution from: https://github.com/TypeStrong/ts-node/discussions/1450#discussion-3563207
At the moment, the ESM loader does not handle TypeScript path mappings. To make it work you can use the following custom loader:
// loader.js
import {
resolve as resolveTs,
getFormat,
transformSource,
load,
} from "ts-node/esm";
import * as tsConfigPaths from "tsconfig-paths"
export { getFormat, transformSource, load };
const { absoluteBaseUrl, paths } = tsConfigPaths.loadConfig()
const matchPath = tsConfigPaths.createMatchPath(absoluteBaseUrl, paths)
export function resolve(specifier, context, defaultResolver) {
const mappedSpecifier = matchPath(specifier)
if (mappedSpecifier) {
specifier = `${mappedSpecifier}.js`
}
return resolveTs(specifier, context, defaultResolver);
}
Then use the loader with:
node --loader loader.js index.ts
Caveat: This only works for module specifiers without an extension. For example, import /foo/bar
works, but import /foo/bar.js
and import /foo/bar.ts
do not.
Remember to install these packages as well:
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.1.2",
Updated: 09/11/2023
The new loader will automatically resolve the index.(js|ts):
import { resolve as resolveTs } from 'ts-node/esm'
import * as tsConfigPaths from 'tsconfig-paths'
import { pathToFileURL } from 'url'
const { absoluteBaseUrl, paths } = tsConfigPaths.loadConfig()
const matchPath = tsConfigPaths.createMatchPath(absoluteBaseUrl, paths)
export function resolve (specifier, ctx, defaultResolve) {
const match = matchPath(specifier)
return match
? resolveTs(pathToFileURL(`${match}`).href, ctx, defaultResolve)
: resolveTs(specifier, ctx, defaultResolve)
}
export { load, transformSource } from 'ts-node/esm'
Example:
Path: /src/modules/order/index.ts
Resolve: import orderModule from '@/modules/order';
Updated: 11/04/2024
For the node version 20, we need to set the arg: --experimental-specifier-resolution=node
node --experimental-specifier-resolution=node --loader ./loader.js src/main.ts