Open Danielku15 opened 1 year ago
I started the relevant changes here: https://github.com/dividab/tsconfig-paths/compare/master...Danielku15:tsconfig-paths:feature/ts-node-esm
The new ts-node-esm.mjs
can be used in node --loader
and will bootstrap tsconfig-paths
together with ts-node
in an ESM setup. The new example shows how it can be used. Beside that I needed an extension of the path resolving which returns me the matched file path instead of the trimmed variant.
I could prepare a full PR if there is a chance of getting it merged. Unit Tests are missing at this point.
After integrating a test build into my own project (TypeScript Codebase+Mocha+ESM+ts-node+tsconfig-paths), I got it even running with the Test Explorer VS Code Extensions:
@Danielku15 have you tried out tsx? I found it the other day and it's simplified every TypeScript + Node + ESM project I work on, and it does the paths resolution for you
@effervescentia I have tried it and encountered an issue with the decorator.
@effervescentia I have tried it and encountered an issue with the decorator.
Interesting... I use it on a project that runs a NestJS application and uses decorators heavily and haven'y had any issues based on the limitations they say that the configuration setting emitDecoratorMetadata isn't supported, which you don't need to actually use decorators for route binding like NestJS does. do you actually need it enabled for your usecase?
@8NAF I was able to get it working by adding an explicit @Inject(AppService)
decorator
https://stackblitz.com/edit/node-nxsjdb?file=src/app.controller.ts
@8NAF I was able to get it working by adding an explicit
@Inject(AppService)
decorator https://stackblitz.com/edit/node-nxsjdb?file=src/app.controller.ts
Fantastic! Everything is working now. I had to struggle all day to find a way to solve this issue. Thank you very much!
tsx still doesn't look like it can run typeorm
tsx still doesn't look like it can run typeorm
@mfts2048
I'm actually using typeorm
and @nestjs/typeorm
with my project and they're working properly
However, my ORM models are stored in a separate package so they have already been compiled with the appropriate metadata before being consumed in my NestJS app, so that might be why I'm not having the same issue.
Is there a way to get ESM supported in tsconfig-paths
?
Any updated?
@Danielku15 any chance to use with ESM? The following does not work still:
NODE_ENV=development node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register ./src/index.ts
@damianobarbati I am currently moving over towards tsx
which works fine for all my use cases.
https://github.com/esbuild-kit/tsx
I am currently trying to migrate the browser based tests (Rollup+Karma+Jasmine) of my TypeScript project to a node based setup (ts-node+mocha) but unfortunately it seems almost every package lacks some features, especially around ESM.
ts-node
would have ESM support, but doesn't have paths supporttsconfig-paths
hasts-node
support but no ESM support.So I attempted to get tsconfig-paths running with ESM and was successful by hooking into the resolve process. But it is still a bit hacky currently because
ts-node
doesn't export the relevant modules, andtsconfg-paths
doesn't have a public API of resolving the actual file that was found to match a configuredpaths
. First some code:Usage via node
```bash node --experimental-specifier-resolution=node --loader=ts-node-esm-paths.mjs ... ```Usage via .mocharc.json
```json { "extension": [ "ts" ], "node-option": [ "experimental-specifier-resolution=node", "loader=./scripts/ts-node-esm-paths", "no-warnings" ], "spec": "test/**/*.test.ts" } ```ts-node-esm-paths.mjs
```js // // Override default ESM resolver to map paths import { fileURLToPath } from 'url'; import { createRequire } from 'module'; import { join } from 'path'; import * as fs from 'fs'; const require = createRequire(fileURLToPath(import.meta.url)); const __dirname = fileURLToPath(new URL('.', import.meta.url)); import { createMatchPath, loadConfig, matchFromAbsolutePaths } from 'tsconfig-paths'; const configLoaderResult = loadConfig(); const matchPath = createMatchPath( configLoaderResult.absoluteBaseUrl, configLoaderResult.paths, configLoaderResult.mainFields, true ); /** @type {import('ts-node/dist-raw/node-internal-modules-esm-resolve')} */ const esmResolver = require(join( __dirname, '..', 'node_modules', 'ts-node', 'dist-raw', 'node-internal-modules-esm-resolve.js' )); const originalCreateResolve = esmResolver.createResolve; esmResolver.createResolve = opts => { const resolve = originalCreateResolve(opts); const originalDefaultResolve = resolve.defaultResolve; resolve.defaultResolve = (specifier, context, defaultResolveUnused) => { const found = matchPath(specifier); if (found) { // NOTE: unfortunately matchPath doesn't give us the absolute path // therefore we have to cheat here a bit if (fs.existsSync(found + '.ts')) { specifier = new URL(`file:///${found}.ts`).href; } else if (fs.existsSync(join(found, 'index.ts'))) { specifier = new URL(`file:///${join(found, 'index.ts')}`).href; } } const result = originalDefaultResolve(specifier, context, defaultResolveUnused); return result; }; return resolve; }; // // Adopted from ts-node/esm /** @type {import('ts-node/dist/esm')} */ const esm = require(join(__dirname, '..', 'node_modules', 'ts-node', 'dist', 'esm.js')); export const { resolve, load, getFormat, transformSource } = esm.registerAndCreateEsmHooks(); ```What I've done:
ts-node/esm
. This makes the usage easier because only one single loader has to be specified everywhere. But ts-node doesn't export some internal files, so we are required torequire
them via absolute path.ts-node/esm
I override some internal functions of it (like the tsconfig-paths/register does it for the CJS file loading). I override theresolve
function used internally and there usetsconfig-paths
to map the specified to the real file.In tsconfig-paths we could ship this maybe with two steps as a new feature:
matchPath
needs an extension to get back the final file path of the module which was found.registerAndCreateEsmHooks
with a callback for resolving we can import in atsconfig-paths/esm