Hey there! First off, thanks for this awesome tool—it's been a huge time-saver! 🙌
I recently migrated a TypeScript project to ESM and used ts2esm to correctly add .js extensions in imports. While it worked well overall, I ran into a few challenges that I think could improve the tool even further.
1️⃣ Partial Support for tsconfig Paths
I saw that tsconfig path support works to some extent, but I had issues in an Nx monorepo with /apps/* and /libs/*. These are linked using tsconfig paths, and ts2esm only resolved the imports correctly after I moved libs inside an apps folder. My workaround looked like this:
- Move
libs/* into apps/myapp/libs/*
- Update
tsconfig.json paths accordingly
- Run
ts2esm
- Move
libs back to their original location
- Repeat for each app
If ts2esm could resolve paths of aliases outside the current project dir, that would be amazing!
2️⃣ Handling Package Exports and Subpath Imports
My project had a mix of modern packages (with package.json exports) and older ones using subpath imports. It would be great if ts2esm could leverage TypeScript's built-in resolver to automatically handle these cases.
Example 1: Legacy Package (lodash)
lodash doesn't have an exports field, so it requires .js in the import path:
// Before (CommonJS)
import omit from 'lodash/omit';
// After (ESM)
import omit from 'lodash/omit.js';
Currently, ts2esm doesn’t handle this, so I had to fix it manually.
Example 2: Modern Package (firebase-functions)
firebase-functions has an exports field, so no changes are needed:
// This works in both CJS and ESM
import { HttpsError } from 'firebase-functions/v1/https';
However, in cases where an import incorrectly targets a private subpath, it breaks in ESM:
// This works in CJS but fails in ESM
import type { ObjectMetadata } from 'firebase-functions/lib/v1/providers/storage';
Since TypeScript correctly flags these issues, maybe ts2esm could warn or ignore them?
3️⃣ Dynamic Imports Are Not Converted
I also noticed that dynamic imports aren’t updated with .js extensions:
const module = await import('./my-function.function');
// Expected:
const module = await import('./my-function.function.js');
Handling this would make ts2esm even more powerful!
Would love to hear your thoughts! Let me know if I can help test anything. 😊
Hey there! First off, thanks for this awesome tool—it's been a huge time-saver! 🙌
I recently migrated a TypeScript project to ESM and used
ts2esmto correctly add.jsextensions in imports. While it worked well overall, I ran into a few challenges that I think could improve the tool even further.1️⃣ Partial Support for
tsconfigPathsI saw that tsconfig path support works to some extent, but I had issues in an Nx monorepo with
/apps/*and/libs/*. These are linked usingtsconfigpaths, andts2esmonly resolved the imports correctly after I movedlibsinside anappsfolder. My workaround looked like this:libs/*intoapps/myapp/libs/*tsconfig.jsonpaths accordinglyts2esmlibsback to their original locationIf
ts2esmcould resolve paths of aliases outside the current project dir, that would be amazing!2️⃣ Handling Package Exports and Subpath Imports
My project had a mix of modern packages (with
package.jsonexports) and older ones using subpath imports. It would be great ifts2esmcould leverage TypeScript's built-in resolver to automatically handle these cases.Example 1: Legacy Package (
lodash)lodashdoesn't have anexportsfield, so it requires.jsin the import path:Currently,
ts2esmdoesn’t handle this, so I had to fix it manually.Example 2: Modern Package (
firebase-functions)firebase-functionshas anexportsfield, so no changes are needed:However, in cases where an import incorrectly targets a private subpath, it breaks in ESM:
Since TypeScript correctly flags these issues, maybe
ts2esmcould warn or ignore them?3️⃣ Dynamic Imports Are Not Converted
I also noticed that dynamic imports aren’t updated with
.jsextensions:Handling this would make
ts2esmeven more powerful!Would love to hear your thoughts! Let me know if I can help test anything. 😊