Open jeffpalmeri opened 6 months ago
There are two possible names for oneTable.ts
(one that goes via the symlink, one which doesn't), which is leading to problems.
Look again at the traceResolution line (I'll break it apart for clarity):
========
Resolving module
'../refreshContactCRM/contactSync.service'
from
'/Users/jpalmeri/Documents/tsbuild-repro/src/lambdas/crms/crmProps/oneTableTrigger/oneTable.ts'.
(etc)
File '/Users/jpalmeri/Documents/tsbuild-repro/src/lambdas/crms/crmProps/refreshContactCRM/contactSync.service.ts' exists - use it as a name resolution result.
The starting path is
/Users/jpalmeri/Documents/tsbuild-repro/src/lambdas/crms/crmProps/oneTableTrigger/oneTable.ts
The target name is
../refreshContactCRM/contactSync.service
So the most-likely place to find it, based on the path math, would be
/Users/jpalmeri/Documents/tsbuild-repro/src/lambdas/crms/crmProps/refreshContactCRM/contactSync.service.ts
Which is exactly what it finds
You basically have two copies of the originating source file - the one from the symlinked path, and the one in the symlink target. Only one of those paths can be the canonical one for how module resolution should treat as the correct one for relative paths, and it's really just whatever path gets hit first, which is why tsc and tsserver see different results.
This is likely in-principle fixable, but this project configuration isn't going to be something that's well-supported because it breaks a lot of fundamental assumptions; TS isn't going to repeatedly re-resolve module imports based on all the possible originating symlink locations. The symlink target should likely be exclude
d for consistency
Demo Repo
https://github.com/jeffpalmeri/tsc-build-repro
Which of the following problems are you reporting?
The module specifier resolves at build time, but shouldn't because it doesn't at runtime
Demonstrate the defect described above with a code sample.
Run
tsc --showConfig
and paste its output hereRun
tsc --traceResolution
and paste its output herePaste the
package.json
of the importing module, if it existsPaste the
package.json
of the target module, if it existsAny other comments can go here
To summarize the issue I'm seeing: TSC is compiling the code successfully without showing any errors, even though there is an import error that TSServer is correctly detecting and showing in the editor diagnostics ("Cannot find module '../refreshContactCRM/contactSync.service' or its corresponding type declarations. [2307]"). There is a symlink in the project that seems to be related to why this issue is occurring.
Actual behavior: TSC runs with no errors and produces a .js file that throws a MODULE_NOT_FOUND error when run. Expected behavior: TSC throws error when building (that is reflected by the diagnostic TSServer error shows in editor).
TSC version: Version 5.4.3
This is the project tree structure:
In the file src/lambdas/oneTableTrigger/oneTable.ts, there is a bad import:
import { getContactSyncStatus } from "../refreshContactCRM/contactSync.service";
The path does not lead to any file, and there is a correct diagnostic message shown in the editor telling me such. But running
tsc
the code compiles with no errors or warnings, producing a js file with this corresponding require:const contactSync_service_1 = require("../refreshContactCRM/contactSync.service");
Which errors when it is run because of this:
I see unexpected module resolution when I inspect the output of
tsc --traceResolution
that I don't understand, and am thinking that it could be a good clue on the source of the problem. Specifically here:Specifically on the 3rd line of that traceResolution output:
Loading module as file / folder, candidate module location '/Users/jpalmeri/Documents/tsbuild-repro/src/lambdas/crms/crmProps/refreshContactCRM/contactSync.service', target file types: TypeScript, Declaration.
The candidate module location is a real path, but I don't understand why or how it was picked as a candidate location, and this part seems like an error to me. If you manually follow the path from the import in the importing file, it looks like this: From
src/lambdas/oneTableTrigger/oneTable.ts
:import { getContactSyncStatus } from "../refreshContactCRM/contactSync.service";
What I would expect would be this: ->
src/lambdas/refreshContactCRM/contactSync.service.ts
(which is not a real path, no file at this location)There is something about the symlink being present that is causing this behavior, but it's not something I can explain or understand. It's as if the module resolution process is getting that candidate path from a symlink path, even though the file that is doing the importing is not a symlink, nor importing from a symlink location. It's a just a normal real file doing a normal relative import is what it looks like to me.
If I delete the symlink:
rm ./src/lambdas/crms/crmProps/oneTableTrigger
I get the same exact diagnostic error message in my editor, but running
tsc
fails with the expected behavior:When the symlink is present, it's as if the module resolution is choosing the candidate path just because there is a symlink present, even though the that's not the actual direction of the symlink, it's the reverse. And again, the file doing the importing here is not a symlink (the symlink in the project points to the directory that that the importing file is in), nor is it importing from a symlink. So when I try to follow the logic of the import, even with the presence of this symlink, it does not make sense to me.
Just a couple more notes:
I've tried adding the tsconfig option
preserveSymlinks
as both true and false, but that causes no difference. The outputs of--traceResolution
are exactly the same for both, and exactly the same as not including the option at all (as it is originally in the repo I provided)If you delete the symlink, you can add it back with this:
ln -s ../../oneTableTrigger ./src/lambdas/crms/crmProps/oneTableTrigger
And my last important thought: The module resolution feels like the bug to me here, but even if it is actually the correct behavior for an explainable reason, then it seems like a bug that there is a mismatch between what TSC produces and TSServer is telling me. The TSServer diagnostic message is showing me the correct error, and reflects the runtime error you receive when trying to run the produced javascript file, but TSC does not reflect that when it builds.