Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support exports and imports subpath (package.json) pointing to generated .js files #1974

Open
InExtremaRes opened this issue Mar 20, 2023 · 3 comments

Comments

@InExtremaRes
Copy link

Desired Behavior

Consider a source file src/package-a/index.ts that will be transpiled by tsc to build/package-a/index.js, and a package.json that looks like this:

{
  "type": "module",
  "imports": {
    "#package-a": "./build/package-a/index.js"
  }
}

Now TypeScript allows me to import import {...} from #package-a in any other file. Even when I am importing the generated .js file (that maybe don't exists yet), TypeScript knows that file will be generated from the .ts in src and correctly type-check that file, uses it for editor support, etc.

ts-node, however, doesn't know how to resolve the file and fails with

node_modules/ts-node/dist-raw/node-internal-modules-esm-resolve.js:366
    throw new ERR_MODULE_NOT_FOUND(
[...]

The same occurs for subpath exports: TypeScript resolves to the source file that will generate that .js but ts-node doesn't.

I would expect ts-node to follow TypeScript semantics here and resolve to the corresponding .ts file as the language server does.

Is this request related to a problem?

Using subpath imports (since v14, v12 in experimental) is a common practice to alleviate the burden of nested, relative paths, as well to provide "internal packages" and many other cases. TypeScript, with a well configured tsconfig.json and package.json, just works.

The issue is, you can't point to the .ts file in the "imports" field of the package.json to make ts-node works since that field will also be read by node at runtime to resolve the import, so it must point to the generated .js. This issue makes it really difficult to correctly use this Node feature.

Alternatives you've considered

My first idea was to use conditional imports so the package.json could look something like this:

{
  "type": "module",
  "imports": {
    "#package-a": {
      "ts-node": "./src/package-a/index.ts",
      "default": "./build/package-a/index.js"
    }
  }
}

However I can't figure out how to use a custom condition for ts-node (I'm using ts-node-esm but don't think that's relevant). I have tested with NODE_OPTIONS="-C ts-node" npx ts-node-esm thing but got the same error. A possible workaround is to allow custom conditions and the last pattern should work, but I still think the original example should be supported by ts-node out of the box (or at least via some config).

Additional context

I think the issue was commented on #1007, but that's a very long thread to follow a possible resolution there.

@robbiespeed
Copy link

robbiespeed commented May 12, 2023

Ran into this issue myself when working in a multi package repo. Only solution I could find was transpile all packages in watch mode, in which case there's no longer a benefit to using ts-node.

Switched to @esbuild-kit/esm-loader and that seems to handle it out of the box.

This dividab/tsconfig-paths#243 seems related for my setup, since I do have paths setup between the packages to match their package.json exports.

@mihaa1
Copy link

mihaa1 commented Dec 26, 2023

Ran into this issue myself when working in a multi package repo. Only solution I could find was transpile all packages in watch mode, in which case there's no longer a benefit to using ts-node.

Switched to @esbuild-kit/esm-loader and that seems to handle it out of the box.

This dividab/tsconfig-paths#243 seems related for my setup, since I do have paths setup between the packages to match their package.json exports.

Are u developing a package or app?
If this is a published package - how did u get around this comment in the TS docs?
"While it’s ok for bundled apps to set up paths, it’s very important that published libraries do not, since the emitted JavaScript will not work for consumers of the library without those users setting up the same aliases for both TypeScript and their bundler. Both libraries and apps can consider package.json "imports" as a standard replacement for convenience paths aliases."
?

@robbiespeed
Copy link

@mihaa1 developing multiple packages in a monorepo. There's no issue with the paths I have setup because they only serve to mimic nodes actual behavior. If I wasn't in a monorepo I wouldn't need them, or if typescript had built in support for monorepo setups.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants