-
Notifications
You must be signed in to change notification settings - Fork 2.6k
fix(core): scope typescript resolution cache correctly when processing the graph #31455
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
View your CI Pipeline Execution ↗ for commit 042f92e.
☁️ Nx Cloud last updated this comment at |
442306e
to
22f2643
Compare
22f2643
to
a46b8c7
Compare
a46b8c7
to
cdbc88f
Compare
if (this.typescriptResolutionCache.has(normalizedImportExpr)) { | ||
resolvedModule = this.typescriptResolutionCache.get(normalizedImportExpr); | ||
let cacheKey: string; | ||
if (normalizedImportExpr.startsWith('#')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why this is only done for imports that start with #
? I know there's a convention that frameworks set this but is there something special about # in the typescript spec?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's part of the Node.js specification for subpath imports. These imports are aliases that can only be used internally for the project where they are specified. So, they don't need to be unique across projects, and that's why we were getting the wrong cache hits and needed to special case their cache key to scope it to the project.
If your question is whether other imports without #
could also be internal to a project, I guess it could happen if you have TS path mappings defined in the project's tsconfig file. In that case, those TS path mappings only apply to the project and therefore, you could have TS path mappings with the same name in other projects.
I'll update this to always generate the cache key after the project root. It's a safer approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR scopes TypeScript module resolution cache keys by project for Node.js subpath imports and extends the resolution logic to correctly handle internal and external imports, along with adding an end-to-end test to verify the behavior.
- Scope cache keys for subpath imports (
#…
) to the importing project root - Update resolution flow to distinguish between internal project files and npm packages
- Add an e2e test for Node.js subpath import handling
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
File | Description |
---|---|
packages/nx/src/plugins/js/project-graph/build-dependencies/target-project-locator.ts | Scoped cache keys, refactored resolution logic to handle ESM and external deps |
e2e/nx/src/graph-ts-solution.test.ts | Added test case for subpath imports in the TS solution graph |
Comments suppressed due to low confidence (4)
packages/nx/src/plugins/js/project-graph/build-dependencies/target-project-locator.ts:371
- [nitpick] The variable name
cacheKey
is generic; consider renaming it toresolutionCacheKey
or similar to clarify its purpose in module resolution.
let cacheKey: string;
packages/nx/src/plugins/js/project-graph/build-dependencies/target-project-locator.ts:146
- [nitpick] Link this TODO to a specific issue or tracking ID to improve traceability and avoid losing context when the ESM rework is performed.
// TODO: this can be removed once we rework resolveImportWithRequire below
e2e/nx/src/graph-ts-solution.test.ts:323
- [nitpick] The test verifies specific subpath imports (
#file2
,#file3
) but does not validate the wildcard#*
mapping. Consider adding assertions to cover wildcard subpath import resolution.
it('should detect dependencies correctly when using Node.js subpath imports', () => {
packages/nx/src/plugins/js/project-graph/build-dependencies/target-project-locator.ts:386
- [nitpick] The indentation of this
else
block closing brace is inconsistent with the openingif
. Align the brace with theif
statement for better readability.
} else {
packages/nx/src/plugins/js/project-graph/build-dependencies/target-project-locator.ts
Outdated
Show resolved
Hide resolved
cdbc88f
to
965eba3
Compare
965eba3
to
e5a60c4
Compare
e5a60c4
to
bca8217
Compare
scripts/documentation/generators/generate-devkit-documentation.ts
Outdated
Show resolved
Hide resolved
bca8217
to
10f2034
Compare
10f2034
to
042f92e
Compare
Thank you, @leosvelperez & @FrozenPandaz ! 🙌 |
This pull request has already been merged/closed. If you experience issues related to these changes, please open a new issue referencing this pull request. |
Current Behavior
When using Node.js subpath imports with the same name in different projects, the Nx graph incorrectly picks up seemingly random dependencies between projects that shouldn't exist.
This happens because the result of the resolution performed with TypeScript is cached using the import path as the cache key. The problem with that is that multiple projects can have the same subpath import name pointing to internal files of the project, so when the resolution is made for the first project (say
project1
), the result will be cached and incorrectly reused for other projects with the same subpath import name. So, all projects with the same subpath import name would resolve the dependency to the first project (project1
).The same could happen to projects with TS path mappings defined in the project's tsconfig file. These TS path mappings would only apply to the project internally and therefore, other unrelated projects could also define them with the same name pointing to different files.
Expected Behavior
The Node.js subpath imports should be handled correctly. The TypeScript resolution result should be cached safely and scoped to the project from which the import is being done.
Related Issue(s)
Fixes #31223