egoist / tsup

The simplest and fastest way to bundle your TypeScript libraries.
https://tsup.egoist.dev
MIT License
9.01k stars 217 forks source link

TypeScript files are seen as JavaScript when tsup resolves types of an external package in certain conditions #1023

Open umajho opened 11 months ago

umajho commented 11 months ago

If a package points a subpath export (exports: { "./a": "./a.ts" } in package.json) to a TypeScript file (“a.ts”: import {…} from "./b.ts"), and you use that package as a dependency, when you run tsup with dts: { resolve: true }: the file (“a.ts”) itself is treated as TypeScript code, but TypeScript files (like “b.ts”) imported by the former file are treated as plain JavaScript codes.

If “a.ts” is set as the main export (exports: { ".": "./ts" }), everything works.

Reproduction

https://github.com/umajho/tsup-reproduction-dts-resolve-pnpm-workspace

in “packages/support-lib”:

// foo.ts:
export type Foo = "foo";
export const foo: Foo = "foo";

// bar-that-imports-foo.ts:
export * from "./foo";

// package.json:
{
  // …
  "exports": {
    "./foo": "./foo.ts",
    "./bar-that-imports-foo": "./bar-that-imports-foo.ts",
    ".": "./bar-that-imports-foo.ts"
  }
}

cd packages/lib-to-be-built

pnpm run build-foo-dts-resolve ⭕️

Importing from “support-lib” with the subpath “./foo”, and building the library using tsup with dts: { resolve: true }:

// lib-imports-foo.ts:
import { Foo, foo } from "@tsup-reproduction-dts-resolve-pnpm-workspace/support-lib/foo";
export const baz: Foo = foo;
success ``` ➜ lib-to-be-built git:(main) pnpm run build-foo-dts-resolve > @tsup-reproduction-dts-resolve-pnpm-workspace/lib-to-be-built@1.0.0 build-foo-dts-resolve /private/tmp/test/packages/lib-to-be-built > tsup --config tsup.foo-dts-resolve.config.ts CLI Building entry: lib-imports-foo.ts CLI Using tsconfig: tsconfig.json CLI tsup v7.2.0 CLI Using tsup config: /private/tmp/test/packages/lib-to-be-built/tsup.foo-dts-resolve.config.ts CLI Target: es2020 CLI Cleaning output folder ESM Build start ESM dist/lib-imports-foo.js 98.00 B ESM ⚡️ Build success in 10ms DTS Build start DTS ⚡️ Build success in 474ms DTS dist/lib-imports-foo.d.ts 60.00 B ```

pnpm run build-bar-using-main-dts-resolve ⭕️

Importing from “support-lib” with the main path, and building the library using tsup with dts: { resolve: true }:

// lib-imports-bar-using-main.ts:
import { Foo, foo } from "@tsup-reproduction-dts-resolve-pnpm-workspace/support-lib";
export const baz: Foo = foo;
success ``` ➜ lib-to-be-built git:(main) pnpm run build-bar-using-main-dts-resolve > @tsup-reproduction-dts-resolve-pnpm-workspace/lib-to-be-built@1.0.0 build-bar-using-main-dts-resolve /private/tmp/test/packages/lib-to-be-built > tsup --config tsup.bar-using-main-dts-resolve.config.ts CLI Building entry: lib-imports-bar-using-main.ts CLI Using tsconfig: tsconfig.json CLI tsup v7.2.0 CLI Using tsup config: /private/tmp/test/packages/lib-to-be-built/tsup.bar-using-main-dts-resolve.config.ts CLI Target: es2020 CLI Cleaning output folder ESM Build start ESM dist/lib-imports-bar-using-main.js 109.00 B ESM ⚡️ Build success in 12ms DTS Build start DTS ⚡️ Build success in 453ms DTS dist/lib-imports-bar-using-main.d.ts 60.00 B ```

pnpm run build-bar-dts-resolve

Importing from “support-lib” with the subpath “./bar-that-imports-foo”, and building the library using tsup with dts: { resolve: true }:

// lib-imports-bar.ts:
import { Foo, foo } from "@tsup-reproduction-dts-resolve-pnpm-workspace/support-lib/bar-that-imports-foo";
export const baz: Foo = foo;
failed ``` ➜ lib-to-be-built git:(main) pnpm run build-bar-dts-resolve > @tsup-reproduction-dts-resolve-pnpm-workspace/lib-to-be-built@1.0.0 build-bar-dts-resolve /private/tmp/test/packages/lib-to-be-built > tsup --config tsup.bar-dts-resolve.config.ts CLI Building entry: lib-imports-bar.ts CLI Using tsconfig: tsconfig.json CLI tsup v7.2.0 CLI Using tsup config: /private/tmp/test/packages/lib-to-be-built/tsup.bar-dts-resolve.config.ts CLI Target: es2020 CLI Cleaning output folder ESM Build start ESM dist/lib-imports-bar.js 98.00 B ESM ⚡️ Build success in 16ms DTS Build start Error parsing: /private/tmp/test/packages/support-lib/foo.ts:1:7 Error: error occured in dts build at Worker. (/private/tmp/test/node_modules/.pnpm/tsup@7.2.0_typescript@5.2.2/node_modules/tsup/dist/index.js:2294:26) at Worker.emit (node:events:511:28) at MessagePort. (node:internal/worker:263:53) at [nodejs.internal.kHybridDispatch] (node:internal/event_target:762:20) at exports.emitMessage (node:internal/per_context/messageport:23:28) DTS Build error Unexpected token (Note that you need plugins to import files that are not JavaScript) 1: export type Foo = "foo"; ^ 2: 3: export const foo: Foo = "foo";  ELIFECYCLE  Command failed with exit code 1. ```

Upvote & Fund

Fund with Polar

umajho commented 11 months ago

Well, I found the problem. It is my fault. I should set:

    "module": "NodeNext",
    "moduleResolution": "NodeNext",

in tsconfig.json.

umajho commented 11 months ago

I just noticed that when I set

    "module": "NodeNext",
    "moduleResolution": "NodeNext",

in tsconfig.json, it just make the command not complain, but the generated .d.ts is wrong.

pnpm run build-bar-dts-resolve

generated definition file:

import { Foo } from './foo.js'; // Cannot find module './foo.js' or its corresponding type declarations.ts(2307)

declare const baz: Foo;

export { baz };
ron0115 commented 11 months ago

I face the same problem, need somebody to help

cdalton713 commented 3 months ago

I'm also running into this - were you able to find a solution?

theoephraim commented 1 week ago

Also hitting this issue within a monorepo where I am trying to bundle an unpublished internal library package into a published one. This internal library is listed under noExternal and while the bundling is working just fine, the dts generation was leaving those imports as if they were external. Enabling dts resolve is now causing this issue :(