watch: node_modules dependencies are watched in a pnpm workspace (contrary to docs)
Acknowledgements
- I read the documentation and searched existing issues to avoid duplicates
- I understand this is a bug tracker and anything other than a proven bug will be closed
- I understand this is a free project and relies on community contributions
- I read and understood the Contribution guide
Minimal reproduction URL
https://github.com/SebT/tsx-emfile-repro
Problem & expected behavior (under 200 words)
tsx watch restarts when a file inside node_modules changes, although the docs say node_modules is ignored by default. In a pnpm workspace every imported dependency gets watched.
Repro (./reproduce.sh): a subpackage imports nanoid and idles; touching nanoid's file under node_modules makes tsx restart, in its own words:
[tsx] change in ./../../node_modules/.pnpm/[email protected]/node_modules/nanoid/index.js Restarting...
Also reproduced on a clean Linux runner (workflow in the repo).
Why pnpm: a dep's real files live at node_modules/.pnpm/<pkg>@<ver>/node_modules/<pkg>, resolved from a subpackage as ../../node_modules/.... The default node_modules filter doesn't match that parent-relative path.
--exclude: --exclude '**/node_modules/**' is a silent no-op; only --exclude '../../node_modules/**' (or an absolute path) works — tsx seems to match --exclude against absolute realpaths.
Impact: across ~10 services each tsx holds thousands of node_modules watches (≈50 under ts-node-dev); on macOS this exhausts the system file table (kern.maxfiles) and an unrelated fs.watch dies with EMFILE: too many open files, watch.
Expected: the default node_modules exclusion should cover pnpm's .pnpm realpaths, and/or --exclude '**/node_modules/**' should match them.
Bugs are expected to be fixed by those affected by it
- I'm interested in working on this issue
Compensating engineering work will speed up resolution and support the project
- I'm willing to offer $10 for financial support
Source: privatenumber/tsx