egoist / tsup

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

Support for TypeScript project references #647

Open segevfiner opened 2 years ago

segevfiner commented 2 years ago

The vanilla TypeScript compiler has a feature called project references that makes it more convenient to work on composite/monorepo projects that would otherwise need multiple watch processes, and also for making sure they rebuild when a dependency changes.

It would be nice to have support for this in tsup.

Basically it might just need tsup to know how to correctly order the build of dependent project's d.ts.

https://www.typescriptlang.org/docs/handbook/project-references.html

Upvote & Fund

Fund with Polar

rosskevin commented 1 year ago

I'd like to add some context and reproduction to this. I'm converting existing monorepos over to vitest, vite and tsup, and we use vscode for our IDE.

Goals:

Reproduction (errors):

https://github.com/rosskevin/ts-esm-workspaces/tree/vite-tsup-project-references

cd packages/shared && yarn build

~/p/t/p/shared ❯❯❯ yarn build
CLI Building entry: src/index.ts
CLI Using tsconfig: tsconfig.json
CLI tsup v6.2.3
CLI Using tsup config: /Users/kross/projects/ts-esm-workspaces/packages/tsup.common.ts
CLI Target: node14
CLI Cleaning output folder
ESM Build start
CJS Build start
ESM dist/index.js     143.00 B
ESM dist/index.js.map 379.00 B
ESM ⚡️ Build success in 37ms
CJS dist/index.cjs     639.00 B
CJS dist/index.cjs.map 556.00 B
CJS ⚡️ Build success in 35ms
DTS Build start
src/index.ts(1,15): error TS6307: File '/Users/kross/projects/ts-esm-workspaces/packages/shared/src/utils.ts' is not listed within the file list of project ''. Projects must list all files or use an 'include' pattern.

Error: error occured in dts build
    at Worker.<anonymous> (/Users/kross/projects/ts-esm-workspaces/node_modules/tsup/dist/index.js:2157:26)
    at Worker.emit (node:events:513:28)
    at MessagePort.<anonymous> (node:internal/worker:233:53)
    at [nodejs.internal.kHybridDispatch] (node:internal/event_target:731:20)
    at exports.emitMessage (node:internal/per_context/messageport:23:28)
Error: Failed to compile. Check the logs above.
    at error (/Users/kross/projects/ts-esm-workspaces/node_modules/tsup/node_modules/rollup/dist/shared/rollup.js:198:30)
    at throwPluginError (/Users/kross/projects/ts-esm-workspaces/node_modules/tsup/node_modules/rollup/dist/shared/rollup.js:21718:12)
    at Object.error (/Users/kross/projects/ts-esm-workspaces/node_modules/tsup/node_modules/rollup/dist/shared/rollup.js:22672:20)
    at Object.error (/Users/kross/projects/ts-esm-workspaces/node_modules/tsup/node_modules/rollup/dist/shared/rollup.js:21895:42)
    at Object.transform (/Users/kross/projects/ts-esm-workspaces/node_modules/tsup/dist/rollup.js:7217:20)
    at /Users/kross/projects/ts-esm-workspaces/node_modules/tsup/node_modules/rollup/dist/shared/rollup.js:22879:40
DTS Build error

Reproduction without project references (doesn't fulfill the IDE requirement):

https://github.com/rosskevin/ts-esm-workspaces/tree/vite


TL;DR

Different tools require different setups. vite tooling requires tsconfig paths, whereas IDE tooling requires project references. tsup breaks when trying to use both, but tsc -b works.

Does that make sense?

segevfiner commented 1 year ago

Related https://github.com/egoist/tsup/issues/688

rosskevin commented 1 year ago

Workaround

I'm working on integrating this into my demo repo (I prototype all our tools there first).

EDIT: Unfortunately the DX of this is awful. The output from tsc -b for the ide conflicts with tsup, as well as the onSuccess emitDeclarationOnly stage errors due to TS6305: Output file 'shared/dist/index.d.ts' has not been built from source file. Part of this tooling conflict comes from the module output declarations in package.json. It matters to tsc -b and I don't want to have to rewrite these entres.

EDIT 2: Running tsc -b first (creates both types and js files), then tsup works, but we will need to clean up the {js,js.map} files between.

rosskevin commented 1 year ago

Ok, this workaround is awful, but it does work: https://github.com/rosskevin/ts-esm-workspaces/blob/vite-dual-config-tsup-paths-ide-proj-refs

  "scripts": {
    "build": "run-s clean build:ide pretsup build:tsup",
    "build:ide": "echo 'tsc -b' && tsc -b",
    "build:tsup": "lerna exec --stream --parallel -- yarn tsup --config ../../tsup.config.ts",
    "pretsup": "echo 'removing js' && node ./scripts/pre-tsup.js",
  },

1: build:ide works for vscode using incremental tsc, and produces our dts files.

  1. pretsup is a script that removes {js|js.map} artifacts from the previous stage to prepare our dist for bundles (as well as deletes the now invalid tsconfig.tsbuildinfo metadata.
  2. build:tsup generates bundles.

I do hope that my original comment serves as enough justification and provides a reproducible environment so that this is fixed at some point.

Zeswen commented 1 year ago

+1, it would be amazing to have support for references in tsup. For now, just to have it in VS Code, I just don't add composite: true to my packages and I live with the error. Hopefully this can be fixed soon!

Update: Locking the tsup version to 6.5.0 fixed this for me.

andreifloricel commented 1 year ago

+1, this would improve the DX significantly.

afsalz commented 1 year ago

I came across with the same problem. However I managed to workaround this using the onSuccess function.

const { defineConfig } = require('tsup');
const fs = require('fs');

module.exports = defineConfig({
  ....,
  async onSuccess() {
    if (process.env.npm_lifecycle_event === 'dev') {
      const time = new Date();
      fs.utimes('../../path-to-the/app-needs-to-rebuild/src/index.tsx', time, time, () => {});
    }
  },
});
toteto commented 11 months ago

I have setup minimal reproduction monorepo that demonstrates this issue: https://github.com/toteto/example-monorepo

johnsvanda commented 6 months ago

Any news?

elijahmontenegro commented 4 months ago

Please add support for this. I am using Turbo repo and utilize project references between my apps.

verydanny commented 3 months ago

I don't really think this is necessary (personally), it requires a bit more annoying config maybe, but I followed the TS official example and utilized emitDeclarationOnly in my referenced libraries.

Here's a repo with small reproducible example: https://github.com/verydanny/appwrite-adapters

I have the project set up using bun, but it works with node, yarn, pnpm, and npm. I tried it.

edit @elijahmontenegro @segevfiner Not sure if this is the behaviour you wanted, but it seems to work. As far as I can tell there's no issues with watching either. You do have to use tsc and tsup, but it's not much of a bother as there doesn't seem to be conflicts.

GermanJablo commented 3 weeks ago

Ok if I understand correctly:

  1. tsup transpiles faster than tsc because it uses esbuild.
  2. the composite option makes builds faster
  3. you can't use tsup with composite.

Am I understanding correctly? If so, I'd like to know what is a bigger loss: having to transpile with tsc or not using composite.

I guess the answer may depend on the structure of the monorepo and how it would impact the cache in that case, but I'd like to know if anyone has an opinion on that.

There is also the incremental option which I'm not sure can serve as an alternative to composite, since the differences between those 2 configurations are not very clear.