Skip to content

VSCode TypeScript project references resolve of duplicate files #48058

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

Closed
xiaoxiangmoe opened this issue Feb 28, 2022 · 7 comments
Closed

VSCode TypeScript project references resolve of duplicate files #48058

xiaoxiangmoe opened this issue Feb 28, 2022 · 7 comments
Labels
Not a Defect This behavior is one of several equally-correct options

Comments

@xiaoxiangmoe
Copy link
Contributor

xiaoxiangmoe commented Feb 28, 2022

Bug Report

πŸ”Ž Search Terms

VSCode, tsconfig ,project references

πŸ•— Version & Regression Information

  • TypeScript Version: 4.1.0-dev.20201020 (4.1.0-dev.20201019 works well)
  • VS Code Version: 1.64.2 (Universal)
  • OS Version: Darwin x64 21.2.0

⏯ Example repo

https://github.com/xiaoxiangmoe/typescript-project-reference-demo.git

πŸ’» Code

// tsconfig.json

{
  "files": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.test.json"
    },
  ]
}

// tsconfig.app.json

{
  "include": ["src/**/*"],
  "exclude": ["src/**/__tests__/*"],
  "compilerOptions": {
    "moduleResolution": "Node",
    "composite": true,
    "target": "ESNext",
    "noEmit": true,
    "strict": true,
    "lib": ["DOM", "ESNext"],
    "types": []
  }
}

// tsconfig.test.json

{
  "extends": "./tsconfig.app.json",
  "exclude": [],
  "compilerOptions": {
    "types": ["node"]
  }
}

// src/components/Foo.ts

export type FooProps = { a: number };
export function Foo(props: FooProps) {
  return null;
}
/**
 * this file is included in both `tsconfig.app.json` and `tsconfig.test.json`
 * 
 * So we should follow the order of `references` in `tsconfig.json`
 * 
 * `tsconfig.app.json` comes before `tsconfig.test.json`, so we should use config file `tsconfig.app.json` in vscode
 * 
 */
const cwd = process.cwd()

πŸ™ Actual behavior

I think const cwd = process.cwd() should has an Error.

Because file src/components/Foo.ts are included in tsconfig.app.json. So it has not include type @types/node.

πŸ™‚ Expected behavior

const cwd = process.cwd() has no Error.

File src/components/Foo.ts is included in both tsconfig.app.json and tsconfig.test.json. VSCode search references field and use the last item of references β€”β€” tsconfig.test.json. So it has no error.

I think we should use first reference. I remember that earlier versions of vscode did this too. I want to know why VSCode/TS change it to use last reference?

@xiaoxiangmoe
Copy link
Contributor Author

I found:
4.1.0-dev.20201019 prefer use previous tsconfig
4.1.0-dev.20201020 prefer use latter tsconfig

@xiaoxiangmoe
Copy link
Contributor Author

xiaoxiangmoe commented Mar 4, 2022

@RyanCavanaugh @sheetalkamat I found this change after #41126

And volar follows the old behavior. Also some code template, like Angular CLI V10, create-vue depends on the old behavior.

Could you please pay attention to this issue? thank you very much.

@RyanCavanaugh RyanCavanaugh added the Not a Defect This behavior is one of several equally-correct options label Mar 4, 2022
@RyanCavanaugh
Copy link
Member

4.1 was released a year and a half ago and this is the first complaint we've seen of it. If a file is in multiple projects like this, the one we choose to load it in is arbitrary. We have a suggestion to allow users to pick the active tsconfig file, but without that, there isn't a bug bug here.

@haoqunjiang
Copy link

haoqunjiang commented Mar 7, 2022

this is the first complaint we've seen of it

Maybe because it's a subtle problem that many users won't notice?
Nevertheless, this doesn't imply the issue isn't common.

We can work around this issue in the command line.
But there's no easy way to fix this in the IDE/editor.

If a file is in multiple projects like this, the one we choose to load it in is arbitrary

Why? This makes it impossible to support the following use case:

  • src/Foo.ts and src/Bar.ts are front-end modules that are supposed to run in browsers;
  • src/__tests__/Foo.spec.ts is a Jest (or Vitest) spec module that imports and tests against src/Foo.ts. The test environment is Node.js with JSDOM.
  • No corresponding spec for src/Bar.ts
  • To differentiate the 2 environments, we need 2 different sets of tsconfigs:
    1. src/Bar.ts MUST be picked up by a tsconfig.app.json, which excludes the Node.js types;
    2. src/__tests__/Foo.spec.ts MUST be picked up by a tsconfig.test.json, which includes the Node.js types.
    3. Because src/Foo.ts is used in both the frontend project and the test project, it has to be included in both projects' tsconfigs. It would be type-checked twice in CI, to make sure it is both runnable in browsers and testable in Node.js.

In this scenario, we need src/* to be picked up by tsconfig.app.json by default, src/**/__tests__/* to be picked up by tsconfig.test.json by default.

Modules like src/Foo.ts should only be picked up by the tsconfig.test.json only when TypeScript parses src/__tests__/Foo.spec.ts and encounters an explicit import of src/Foo.ts.
But as tsconfig only supports simple glob patterns in include and exclude, we have to specify src/* in tsconfig.test.json too.

So to prevent src/Bar.ts from accidentally picked up by tsconfig.test.json, we need a deterministic order of references loading, be it left-to-right or right-to-left.


Similar use cases are also very common in server-side-rendered apps with many modules to be used in both the browser and Node.js context.

@haoqunjiang
Copy link

To solve the issue, I propose that:

  1. TypeScript should at least document the order of loading references;
  2. If possible, would you accept a PR that reverts the behavior to pre-4.1? Because:
    1. It was more intuitive IMHO.
    2. Several downstream libraries still depend on that behavior.

@sschneider-ihre-pvs
Copy link

I am facing the same issue in an nx monorepo where every app has its own three tsconfigs

tsconfig.json
tsconfig.app.json
tsconfig.spec.json

this is how the tsconfig.json looks like

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "strict": true,
    "esModuleInterop": true,
    "resolveJsonModule": true
  },
  "files": [],
  "include": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
  ]
}

vscode on the other side does not even pick this one, instead it picks the tsconfig.spec.json. If I remove the reference vscode does not find any tsconfig anymore

@github-actions
Copy link

github-actions bot commented Jun 8, 2023

This issue has been marked as 'Not a Defect' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Jun 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Not a Defect This behavior is one of several equally-correct options
Projects
None yet
Development

No branches or pull requests

4 participants