Repository navigation
ts-node seems to fail to resolve dependencies in referenced projects #1381
Description
Activity
The
--filesoption might fix this, I'm not sure.https://typestrong.org/ts-node/docs/options
https://typestrong.org/ts-node/docs/typesYou can also try adding a triple-slash reference directive in the files that rely on cheerio types. Typically TS knows to look at types because you
importthem. In cases where you do notimportthem, but still want the compiler to understand they exist, you can/// <reference>them.I apologise, that was a mistake in my reproduction script- the error persists with
import cheerio from 'cheerio';inindex.ts, I've pushed those changes to make that clear.I've also tried the
--filesflag but it doesn't seem to make a difference, I get exactly the same error.Additionally, I thought I'd add (just to rule out that it's a problem with mocha) that the reproduction command uses mocha but you can get the same error by just running ts-node directly (this is with the explicit import and --files specified):
PS C:\Users\trinitrotoluene\WebstormProjects\ts-node-repro\b\btest> npx ts-node -r tsconfig-paths/register .\b.spec.ts C:\Users\trinitrotoluene\WebstormProjects\ts-node-repro\b\btest\node_modules\ts-node\src\index.ts:587 return new TSError(diagnosticText, diagnosticCodes); ^ TSError: ⨯ Unable to compile TypeScript: ../../a/liba/index.ts:3:28 - error TS2503: Cannot find namespace 'cheerio'. 3 export const repro = (foo: cheerio.Root) => { ~~~~~~~ at createTSError (C:\Users\trinitrotoluene\WebstormProjects\ts-node-repro\b\btest\node_modules\ts-node\src\index.ts:587:12) at reportTSError (C:\Users\trinitrotoluene\WebstormProjects\ts-node-repro\b\btest\node_modules\ts-node\src\index.ts:591:19) at getOutput (C:\Users\trinitrotoluene\WebstormProjects\ts-node-repro\b\btest\node_modules\ts-node\src\index.ts:921:36) at Object.compile (C:\Users\trinitrotoluene\WebstormProjects\ts-node-repro\b\btest\node_modules\ts-node\src\index.ts:1189:32) at Module.m._compile (C:\Users\trinitrotoluene\WebstormProjects\ts-node-repro\b\btest\node_modules\ts-node\src\index.ts:1295:42) at Module._extensions..js (node:internal/modules/cjs/loader:1138:10) at Object.require.extensions.<computed> [as .ts] (C:\Users\trinitrotoluene\WebstormProjects\ts-node-repro\b\btest\node_modules\ts-node\src\index.ts:1298:12) at Module.load (node:internal/modules/cjs/loader:989:32) at Function.Module._load (node:internal/modules/cjs/loader:829:14) at Module.require (node:internal/modules/cjs/loader:1013:19)Also thank you for the quick responses, I really appreciate it!
- changed the title
[-]ts-node seems to fail to resolve dependencies in referenced projects when running tests[/-][+]ts-node seems to fail to resolve dependencies in referenced projects[/+]on Jul 2, 2021 I believe this is the same issue as #1421, which is due to how TypeScript is unfortunately repeated invoked on files. It doesn't release this is outside the scope of your type checking project and is trying to also type check it.
@cspotcode I think one option might be to default
scopetotruein a future major release, and have the scope automatically set to therootoftsconfig.json.Are we sure that
cheeriois a namespace? Based on the contents of cheerio@1.0.0-rc.10, it looks likecheeriois a value of typeCheerioAPI, not a namespace nor a type.cheeriois the default import, right?https://unpkg.com/browse/cheerio@1.0.0-rc.10/package.json#L28
https://unpkg.com/browse/cheerio@1.0.0-rc.10/lib/index.d.ts#L21
https://unpkg.com/browse/cheerio@1.0.0-rc.10/lib/load.d.ts#L15Perhaps it would be helpful to locate where the type
cheerio.Rootis declared in cheerio's source code.
https://github.com/cheeriojs/cheerio/I've run into the same issue. My project successfully compiles using
tscand thetsconfig.jsonfiles I have set up, but when trying to run viats-node, I getTSError: x Unable to compile Typescript: src/myfile.ts:23:8 - error TS2307: Cannot find module '@myworkspace/mycomponent' or its corresponding type declarationsI'm using:
- TypeScript 4.2.4
- ts-node v10.0.0
- node: v14.17.1
- Windows 10, no WSL
Hmm, my issue seems to also be related to #897, as I'm working in a monorepo (not lerna, just a yarn PnP monorepo) and the module not being found is being referenced as
@myworkspace/mycomponent, and inpackage.json, the dependency entry for it is@myworkspace/mycomponent: workspace:packages/mycomponent. However, given that ts-node is transpiling on the fly, I would expect it to be able to find the references intsconfig.jsonand build the required dependencies. (Perhaps I expected too much—as I read in another issue, I hadn't fully appreciated the implications of "supporting project references" with respect to ts-node. 😛 )So on second-thought, maybe these two issues are actually related—and it all comes down to ts-node's support for TS project references?
One way that I had this working in the past is by updating the
package.jsonso that themainfield points to the typescript entry point, e.g."main": "./src/index.ts", instead of"main": "./lib/index.js". Pointing to the typescript file, ts-node works. However, this breaks actual builds of the packages, then, because during a build, the referenced dependencies are expecting to find a TypeScript file, but instead, the transpiled JavaScript should be used.And now that I think through everything, this makes sense why that change worked. ts-node isn't building the referenced projects, but when the package.json's
mainfield points to a dependendent package's main entry point TS file, ts-node will happily transpile and everything just works--well, everything except actual builds of the component packages.Reacted by Omar López and Evandro AraújoSee also: #1111 adds the necessary changes for ts-node to understand project references. It also explains what is happening behind the scenes, with TS's internal, monkey-patching of the Host. This monkey-patching teaches the language service that
./lib/index.jscorresponds to./src/index.tsIf anyone is motivated to finish that pull request, I will be happy to offer guidance, explain what's going on, and list what's missing.
@fourpastmidnight you understand the core issue pretty well. As you said, there are 2 possibilities when
@myworkspace/mylibtries to load@myworkspace/mycomponent:it is precompiled
@myworkspace/mycomponenthas been pre-compiled and./lib/index.jsand./lib/index.d.tsexist. This may technically work, but is non-ideal: TS will typecheck against.d.tsand node will resolve to.js. ts-node will not be executing the source .ts, which is what we probably want.it is not precompiled
@myworkspace/mycomponenthas not been compiled yet. #1111 teach ts-node to do the necessary configuration, so that TS understands./lib/index.jscorresponds to./src/index.ts. It understands because the referenced tsconfig has rootDir and outDir, which map betweensrcandlib. This is halfway there: the typechecker understands to typecheck againstindex.ts, but node does not understand which file to load. Node will attempt to require./lib/index.jswhich does not exist. We need to teach node to do the same mappings that TypeScript does. I talk about this in #1111 under "Missing is a runtime resolver"Reacted by Craig E. Shea and Jonas KelloI'm fairly new to all of this, having been thrown into a last-minute project that was a perfect use-case for React. I've learned a lot in the last 3 months, but still not 100% on this ecosystem 😉 I had a look at #1111, but I'm unable to quickly make heads or tails of it. Glad to see, however, that I do understand the core issue even if I'm not quite sure (yet) what it would take to bring #1111 to completion.
I wound up here again, reading my 14-day old self and your replies because I was once again trying to get ts-node to work with my (the same) project.... LOL. Anyway, it would be super sweet to have #1111 done and implemented. So I guess I should now try to see if I can't figure out what the heck that's all doing! LOL. No promises, I'm busy, but I'd really like to have a quick "F5" experience.
@fourpastmidnight yeah, it's like everything in open-source. Someone's got to do it, but the benefits are huge once it gets done.
If/when you start working on this, please do not hesitate to create draft pull requests, ask questions, create issues, whatever you need to feel productive. The PR and issue trackers exist to "get things done" and I'm a big proponent of pushing WIP, chatting, whatever fits your workflow.
I landed here after trying to setup an experimental project with yarn workspaces, typescript project references, snowpack for the client side and
node --loader ts-node/esmfor the server side. I'm trying to feed both snowpack and ts-node/esm the raw .ts files. This works until they cross a package border (across the monorepo's own packages).I give snowpack the
packages/client/src/index.tsfile to start with. Any file it imports in it's own package snowpack will find the .ts file. However when it doesimport x from "@myapp/shared"snowpack will find the symlinked package in node_modules, lookup the package.json, lookup themainfield and findlib/index.js. Then it will continue to build it's dependency chain using .js files instead. So when a .ts file is changed in the shared package snowpack does not have it in it's chain and nothing happens. To fix this it is possible to invent a new field instead ofmain, let's saytsMainand set it tosrc/index.ts. Then in snowpack config you can setpackageLookupFields: ["tsMain", "main"]and snowpack will prefertsMainand it will build a chain of only ts files across the package borders.Now for
node --loader ts-node/esmthat does not work of course since there is no equivalent of snowpack'spackageLookupFieldsconfig. From what I understand here ts-node is trying to solve this by working in the same way as the language server in vscode. Looking up in tsconfig.json what is the input and output dirs (usuallylibandsrc) and rewriting themainfield to map to it's corresponding input file (from the compiler option rootDir).@cspotcode Is this a correct understanding of the situation?
I think it would be great if the logic to do the re-mapping of
lib/index.jstosrc/index.tscould be externalized from ts-node but I don't think it really belongs intsconfig-pathseither since this is not related to thepathsfield in tconfig.json? If it is externalized perhaps tools like snowpack can leverage this logic too instead of having the hack withtsMainfield I described above.If I can help with this I will try subject to time constraints (still haven't got those 36h days I wished for Christmas for the last 20 years :-)).
EDIT: Here is an example repo for what i described above, and this note is about the limitation of module resolution.
+1 this does not work in NX workspaces when I tried to run a node CLI tool that is using some other packages withing the monorepo which are configured via tsconfig paths property in NX.
Would be great to have an option to somehow make it resolve those aliases, as for now it cannot find those workspace packages.
I was able to usetsxinstead for now to execute my cli project locally which resolves all tsconfig paths out of the box.tsxis the clear winner! Thx @gundReacted by Alex Malkevich, Evandro Araújo and JKPark
Expected Behavior
I would expect code that doesn't error when trying to compile it with
tscto compile when run throughts-node.Actual Behavior
I get a TSError warning me about missing dependencies (the README linked below) when ts-node tries to load a referenced project.
Reproduction
I've created a minimal reproduction repo for my scenario here with the behaviour/stack trace and command to reproduce.
Specifications
please see the reproduction repo for the tsconfig structure, here is the effective tsconfig:
Windows 10 Pro 19043.1052