nrwl / nx

Smart Monorepos ยท Fast CI
https://nx.dev
MIT License
23.57k stars 2.36k forks source link

Cannot find all references to shared lib's interfaces in VS Code #3106

Open andriychuma opened 4 years ago

andriychuma commented 4 years ago

Current Behavior

VS Code cannot discover references to shared entities that are defined in an nx lib. E.g. in a fresh new angular-nest nx monorepo VS Code cannot find all references to the Message interface defined in api-interfaces.ts. As a consequence, we cannot rename the entity throughout the workspace.

As far as I understood, it happens due to separate Typescript projects we have for apps and libs, and due to the fact, VS Code relies on the Typescript server while identifying references. This issue was described in this Typescript ticket and fixed within this one. It is not reproducible in WebStorm, which perhaps uses another way of reference discovery in a workspace.

That's rather not a bug of nx per se, but the initial configuration bug/improvement.

Expected Behavior

Find all references and Rename features should work in VS Code throughout all the nx monorepo Typescript subprojects.

To have it working, every nx shared lib should have the following Typescript options enabled: E.g. in libs/api-interfaces/tsconfig.json

{
  ...
  "compilerOptions": {
    ...
    "composite": true,
    "declaration": true
  }
}

More details for the composite option is described here.

Also, we might want to reference lib projects from within application projects. However, I don't know how beneficial it might be in nx monorepos since it's not required for fixing the current issue. E.g. in apps/api/tsconfig.json:

{
  ..
  "references": [
      { "path": "../../libs/api-interfaces" }
  ]
}

Steps to Reproduce

  1. Run npx create-nx-workspace@latest test.
  2. Select angular-nest.
  3. Proceed further with any app name and stylesheet format.
  4. Open the workspace with VS Code.
  5. Open api-interfaces.ts (this file should be the first and the only file opened after running VS Code).
  6. Find references to the Message interface via Shift+F12 or Alt+Shift+F12.

Actual result: no reference found.

Environment

  @nrwl/angular : 9.3.0
  @nrwl/cli : 9.3.0
  @nrwl/cypress : 9.3.0
  @nrwl/eslint-plugin-nx : Not Found
  @nrwl/express : Not Found
  @nrwl/jest : 9.3.0
  @nrwl/linter : 9.3.0
  @nrwl/nest : 9.3.0
  @nrwl/next : Not Found
  @nrwl/node : 9.3.0
  @nrwl/react : Not Found
  @nrwl/schematics : Not Found
  @nrwl/tao : 9.3.0
  @nrwl/web : Not Found
  @nrwl/workspace : 9.3.0
  typescript : 3.8.3
Disane87 commented 4 years ago

Just stumbled upon this a few minutes ago. :-(

amayer42 commented 4 years ago

Thanks for posting this @andriychuma. I attempted your suggested workaround and had success with utilizing "Find all references" again. I'm curious though, do the typescript settings need to be made in each lib? I was able to make the change in the root tsconfig and it seems to work.

It seems like this should be fine since all of the individual lib tsconfig files inherit from the root right?

amayer42 commented 4 years ago

Well, I noticed that changing this value at the root level does fix the "Find all references" issue, but it breaks lots of other things with imports, so it seems that you are correct that it would have to be done in all libs. Suppose I will have to spend a bit more time understanding the fix. Thanks again for posting though.

Areen3 commented 4 years ago

Hello,

I have this problem in my application based on monorepo nx

my example looks like this my-app use -> my-library <- used by my - library-second

first case close all files in VSC and reopen and open file main.ts from my-app you see two referencs 1) from app (1 file) 2) from my-library (2 files) 3) refenece from my-library-second don't show

second case close all files in VSC and reopen and open file index.ts from from my-library you see only one referencs 1) from app (1 file) - not show 2) from my-library (2 files) 3) refenece from my-library-second don't show

third case open from my-library-second shows like firs case

I think the problem is this VSC / TS does not analyze correctly when opening organization of the project, whether or not the method include, files, or refeneces was chosen

example is at: https://github.com/Areen3/find-references look at: https://github.com/microsoft/vscode/issues/80423 https://github.com/nrwl/nx/issues/3106

andriychuma commented 4 years ago

Yes @amayer42 , it looks like the composite flag should be introduced for libs only. Also, after upgrading NX and Angular to 10, the workaround I described in the issue doesn't work. Some changes were introduced to TS configs, so that I needed to extend my fix. Here's what I came up with.

Workaround for NX 10

  1. Add a root level tsconfig.json. This file is the "solution" tsconfig as per the following recommendation. It is not involved in the build process. It looks like tsserver requires a root level tsconfig.json to correctly handle multiple related TS-projects (see the related issue https://github.com/microsoft/vscode/issues/12463).

    {
    "extends": "./tsconfig.base.json",
    "files": [],
    "include": [],
    "references": [
    { "path": "./apps/<app1-name>" },
    { "path": "./apps/<app2-name>" },
    { "path": "./libs/<lib1-name>" },
    { "path": "./libs/<lib2-name>" }
    ]
    }
  2. Add a root level tsconfig.base-lib.json, which will be the base configuration file for all the monorepo libraries. It will basically make our lib projects composite.

    {
    "extends": "./tsconfig.base.json",
    "compilerOptions": {
    "composite": true,
    "declaration": true
    }
    }
  3. For every monorepo library modify the /libs/<lib-name>/tsconfig.json file. Inherit it from the root tsconfig.base-lib.json and remove files and include entries.

    Before

    {
    "extends": "../../tsconfig.base.json",
    "files": [],
    "include": [],
    "references": [
    {
      "path": "./tsconfig.lib.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
    ]
    }

    After

    {
    "extends": "../../tsconfig.base-lib.json",
    "references": [
    {
      "path": "./tsconfig.lib.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
    ]
    }
  4. Restart TS server or VS Code.

From now on, all the monorepo projects are automatically discoverable by TS server and you can find usages/refactor library's interfaces in VS Code.

Works in the following environment

  nx : Not Found
  @nrwl/angular : 10.2.1
  @nrwl/cli : 10.2.1
  @nrwl/cypress : 10.2.1
  @nrwl/eslint-plugin-nx : Not Found
  @nrwl/express : Not Found
  @nrwl/jest : 10.2.1
  @nrwl/linter : 10.2.1
  @nrwl/nest : 10.2.1
  @nrwl/next : Not Found
  @nrwl/node : 10.2.1
  @nrwl/react : Not Found
  @nrwl/schematics : Not Found
  @nrwl/tao : 10.2.1
  @nrwl/web : Not Found
  @nrwl/workspace : 10.2.1
  typescript : 3.9.7
Areen3 commented 4 years ago

Thanks @andriychuma

Thank you for your help... I did as you wrote and it works ๐Ÿ‘ however with minor problems here is link to my example: https://github.com/Areen3/nx-reference

When you turn on references you shoud add to tsconfig.lib.json all files that your library depends on image and here is with importing files image

Maybe you know a better way than to add all the imported files to tsconfig so that renaming works? The point is that adding all imported libraries to tsconfig.lib.json as well will be a pain.

andriychuma commented 4 years ago

@Areen3 , I see you made your apps composite by extending /apps/<app-name>/tsconfig.json from /tsconfig.base.lib.json. Actually, you might want to use /tsconfig.base.lib.json as a base config for your libs only /libs/*. For /apps/* use the regular one /tsconfig.base.json.

Areen3 commented 4 years ago

Thanks You have right, I corrected it

Do You complete the include area in your applications (in tsconfig)?

I found out about completing references in tsconfig.json it helps only VSC to avoid underlining aliases however, if we want to build app, missing include section causes compilation errors because not all files are in project directory

According to me, it is quite onerous, I have about 30 libraries (at the moment) and I will have about 100 so listing them all in the include part will be a pain Please write down how you deal with the rename option - use include to rename or do something else???

I have a second question, I noticed that monorepo NX imports do not always fit well (by VSCode) my settings.json: "typescript.preferences.importModuleSpecifier": "non-relative",

I tried the original importer with VSCode, AutoImport, TypeScriptImport with different configurations and in 20% of cases, the imports do not use aliases and look like this: image

I was looking on the internet, the problem is arising but I failed to find a sufficient solution do you have a suggestion, it would be very useful

thank you very much

johannesschobel commented 3 years ago

Dear @andriychuma ,

I just stumbled upon the exact same issue, however, in another context: I noticed, that my VSCode was not able to "update imports after renaming" anymore, and i was buffled by this fact.

Then this got me hooked and i was thinking this must be some joke :thinking:

I then inspected the tsconfig files from the generated library and found, that the main one (tsconfig.json) has this empty files and includes arrays, which are then "overwritten" by the tsconfig.lib.json and tsconfig.spec.json files respectively.

When i removed those empty arrays, i got errors, that the other 2 files must have the composite: true flag, otherwise it wont work.

Adding the latter solved the issue for me - and i can refactor again :laughing:

Dear @vsavkin , @FrozenPandaz , may someone look into this issue? i can confirm the issue described by @andriychuma as i ran into this issue myself today. It costed me about 5 hours, until i found the solution!

All the best

johannesschobel commented 3 years ago

Dear @andriychuma ,

thank you for your proposed solution in comment ( https://github.com/nrwl/nx/issues/3106#issuecomment-703154400 ), however, this does not work for me (see issue with updating file imports).

Do you have, by chance, the same issue? Does your solution work for the latest NX?

All the best

drewwiens commented 3 years ago

Since the workarounds in this thread do seem to work, but don't compile, at least in Nx 11.0, I made a CLI tool to quickly apply and un-apply them to a workspace: https://www.npmjs.com/package/farp

quolpr commented 3 years ago

I don't recommend that solution to anyone, it is pretty radical, but what I made(tested only on react repos). I deleted all tsconfig*.json files from all dirs and made just one tsconfig.json in root dir:

{
  "compileOnSave": false,
  "files": [
    "./node_modules/@nrwl/react/typings/cssmodule.d.ts",
    "./node_modules/@nrwl/react/typings/image.d.ts"
  ],
  "include": [
    "**/*.js",
    "**/*.jsx",
    "**/*.ts",
    "**/*.tsx"
  ],
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "rootDir": ".",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "importHelpers": true,
    "target": "es2015",
    "module": "esnext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "skipLibCheck": true,
    "skipDefaultLibCheck": true,
    "baseUrl": ".",
    "paths": {
      "<your-lib>": ["libs/<your-lib>/src/index.ts"]
    },
    "incremental": true,
    "jsx": "react",
    "allowJs": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  },
  "exclude": [
    "node_modules",
    "tmp", 
    "**/*.spec.ts", 
    "**/*.spec.tsx", 
    "**/*.stories.tsx", 
    "dist",
    "apps/<your-app>-e2e", 
    "apps/<your-other-app>-e2e", 
  ]
}

And then inside of each lib/app new tsconfig.app.json/tsconfig.lib.json file:

{
  "extends": "../../tsconfig.json"
}

As a benefit, it also solves https://github.com/nrwl/nx/issues/3664 (you can make a type check command that will check types of all your source code. It is good for CI at least) with just one command:

tsc -p ./tsconfig.json --noEmit

quolpr commented 3 years ago

NOTE: this is a solution only for NX 11, and as I suppose you may lose upgradeability to the future NX versions

tomtaz commented 3 years ago

Hello there,

Here is my fix that addresses everything and breaks nothing that I'm aware of. Ping me otherwise. I would be interested to know about the performance impact on build time for large repos with many apps/libs.

In tsconfig.base.json, add this:

{
  "includes": ["**/*.ts"]
}

Replace the tsconfig.json of every library by:

{
  "extends": "../../tsconfig.base.json"
}
johannesschobel commented 3 years ago

Dear @tomtaz ,

i think, a better solution is as follows: 1) leave your tsconfig.base.json as is 2) in every app / lib folder look for the tsconfig.json file and adapt as follows:

{
  "extends": "../../tsconfig.base.json",
+  // "files": [],
+  "include": ["**/*.ts"],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
  ]
}

i.e., comment out the files array and add **/*.ts to the include. This will have the same effect, but follows the nrwl approach more accurately, i guess.

tomtaz commented 3 years ago

Hi @johannesschobel ,

I tried what you proposed, it does not solve every issue I have.

johannesschobel commented 3 years ago

Maybe @vsavkin or @FrozenPandaz can join and provide feedback and maybe a hotfix for nrwl/nx. This issue may be a serious problem in the long run. You can also take a look at microsoft/vscode#4508 where i reported similar problems / issues with additional information

github-actions[bot] commented 3 years ago

This issue has been automatically marked as stale because it hasn't had any recent activity. It will be closed in 14 days if no further activity occurs. If we missed this issue please reply to keep it active. Thanks for being a part of the Nx community! ๐Ÿ™

drewwiens commented 3 years ago

If we missed this issue please reply to keep it active.

Bump

javieroc commented 3 years ago

I was following the tutorial from nx docs and vscode not recognize @myorg/data shared lib, someone had this issue?

Thanks!

alvaromartmart commented 3 years ago

This is still an issue ๐Ÿ˜• and it really breaks the DX while refactoring code (i.e. I cannot just simply rename properties/methods etc. that might be shared used outside a lib, I have to rely on search & replace to be sure)

asbrum commented 3 years ago

Still existing in Nx 12.x, any progress on this?

IT-CASADO commented 3 years ago

We also cannot use refactoring methods like 'renaming' in VS Code. This slows down the development time massively. This issue needs more attention by the NX team!

We also have many issues with "Goto Definition" or "Find References". Most of the time its very slow and intellisense if often not up-to-date . See also microsoft/vscode#4508 .

We switched to NX because of faster build times. We got it, but this problem negates all advantages of NX.

johannesschobel commented 3 years ago

Dear @FrozenPandaz ,

i know, you nx guys may be very busy because of your conference, but this issue is a real road block for larger projects. may you distribute this issue to someone who may be able to work on the latter? Maybe the solution provided by @JakeGinnivan is suitable and can be incorporated somehow!?

All the best and thanks for your awesome work! Johannes

github-actions[bot] commented 2 years ago

This issue has been automatically marked as stale because it hasn't had any recent activity. It will be closed in 14 days if no further activity occurs. If we missed this issue please reply to keep it active. Thanks for being a part of the Nx community! ๐Ÿ™

johannesschobel commented 2 years ago

unstall this issue @vsavkin @FrozenPandaz , can you please tell us, wo is responsible for dealing with this issue? ;) This is a major issue that should be addressed, i think

alvaromartmart commented 2 years ago

unstall this issue @vsavkin @FrozenPandaz , can you please tell us, wo is responsible for dealing with this issue? ;) This is a major issue that should be addressed, i think

I agree. For me this issue is a deal breaker

itspers commented 2 years ago

All this modern web-development is pretty sad. On real world project with dozen apps and 50 shared libs VScode is basically acts as text editor, spending seconds each time to understand where to go with ctrl+click, and its not only TS/JS, its same for Angular - also spinning CPU each time you hover something or ctrl+click...

@vsavkin just uses IDEA, jetbrains IDEs have no such problems, but they dont have proper NX extension - existing 3rd party one breaks after each update, nowdays for example custom generators not working...

There was hope that this exponential grow of VSCode will make it as powerfull as IDEA in few years, but majory of users using it to write Hello-world apps with React and filming Youtube videos - there is just no demand to fix this.

I think best option is to switch to become some Unity or Android developer to fix this problem ๐Ÿ˜

normtronics commented 2 years ago

@FrozenPandaz Any updates on this?

itPiligrim commented 2 years ago

Up โ†‘

ljacho commented 2 years ago

Up โ†‘

evelant commented 1 year ago

@andriychuma is this still an issue? I just stumbled upon this issue and it's making me question whether I should continue to work on integrating nx into my existing repo. If it's going to break TS dev experience (which is already poor without nx) then I'll have to rethink things.

johannesschobel commented 1 year ago

which is already poor without nx

Seriously? The TS Dev Experience is one of the smoothest in my opinion..

andriychuma commented 1 year ago

@evelant, the issue is not fixed yet, but I don't think it should be a pitfall on your Nx monorepo journey. Even being fixed, it's quite likely you wouldn't avoid additional manual adjustments. A multi-project TypeScript repository with project interdependencies should have a properly configured dependency tree for IntelliSense/TSServer to work properly in VS Code. When you add a new app or lib into your monorepo, Nx CLI doesn't know its future relationships with other apps, that's where manual intervention might be needed.

I took the latest Nx v15.2.1 and tried to identify the config adjustments needed for IntelliSense to work fine. There might be some edge cases that I didn't test, but the following tweaks fix the issue.

I created a fresh new monorepo and added three projects:

Here's the initial structure of tsconfigs:

โ”œโ”€โ”€ apps
โ”‚   โ”œโ”€โ”€ client
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.app.json
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.editor.json
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.json
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.spec.json
โ”‚   โ”œโ”€โ”€ server
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.app.json
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.json
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.spec.json
โ”œโ”€โ”€ libs
โ”‚   โ”œโ”€โ”€ shared
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.json
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.lib.json
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.spec.json
โ”œโ”€โ”€ tsconfig.base.json

Then I tweaked them a little bit and added a solution-like tsconfig in the root folder:

โ”œโ”€โ”€ apps
โ”‚   โ”œโ”€โ”€ client
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.app.json
              "compilerOptions": {
                "composite": false, // added
                "declaration": false // added
              },
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.editor.json
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.json
              "include": ["**/*.ts"], // modified
              // "references": [...], // removed whole section
              "compilerOptions": {
                "composite": true, // added
                "declaration": true // added
              },
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.spec.json
โ”‚   โ”œโ”€โ”€ server
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.app.json
              "compilerOptions": {
                "composite": false, // added
                "declaration": false // added
              },
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.json
              "include": ["**/*.ts"], // modified
              // "references": [...], // removed whole section
              "compilerOptions": {
                "composite": true, // added
                "declaration": true // added
              },
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.spec.json
โ”œโ”€โ”€ libs
โ”‚   โ”œโ”€โ”€ shared
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.json
              "include": ["**/*.ts"], // modified
              // "references": [...], // removed whole section
              "compilerOptions": {
                "composite": true, // added
                "declaration": true // added
              },
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.lib.json
โ”‚   โ”‚   โ”œโ”€โ”€ tsconfig.spec.json
โ”œโ”€โ”€ tsconfig.base.json
โ”œโ”€โ”€ tsconfig.json (added the solution tsconfig file)
      {
        "references": [
          {
            "path": "apps/client/tsconfig.json"
          },
          {
            "path": "apps/server/tsconfig.json"
          }
        ]
      }

Now if you export an interface from the shared lib and use it in client and server, it will be properly discoverable by IntelliSense from any place.

evelant commented 1 year ago

@andriychuma Thanks for the details! I actually ended up using https://github.com/google/wireit with pnpm workspaces and that provides me with everything I need for now. I don't think I really need the extra capabilities of nx at the moment. Wireit does a fantastic job of running my build tasks in parallel with caching and has very simple configuration.

FWIW I ended up needing a similar tsconfig setup, nx or not. I think that's just how ts generally ends up needing to be configured to work in a monorepo layout.

kbihler commented 1 year ago

There is a possible gotcha hidden in your project tsconfig.json file that has not been mentioned here. If you have set baseUrl then VS code cannot find your module in libs (typescript error). This results in the problem described.

"compilerOptions": {
    "baseUrl": ".",
}

Remove it and it works again. If you do your internal imports without path navigation

import { thing } from 'components/thing';

then you will need to add it back in

import { thing } from '../components/thing'; 

Hope that helps someone!

div-cowboy commented 1 year ago

Ran into this problem, and figured out my issue. Context: I'm re-platforming an old Next build to a new Next environment using Typescript and NX, but I have some libraries from the old build with components in regular js/jsx. The solve was updating allowJs to be true, and updating includes to: ["*/.js"] in my library's ts.config

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "allowJs": true,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": false
  },
  "files": [],
  "includes": ["**/*.js"],
  "references": [
    {
      "path": "./tsconfig.lib.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
  ],
  "extends": "../../../../tsconfig.base.json"
}
github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it hasn't had any recent activity. It will be closed in 14 days if no further activity occurs. If we missed this issue please reply to keep it active. Thanks for being a part of the Nx community! ๐Ÿ™

BurningEnlightenment commented 1 year ago

AFAICT this still hasn't been fixed.

EthanML commented 1 year ago

This still seems like a very pressing issue - if it's not something that can/will be "fixed" by Nx itself, is it possible that a recommended approach to TS config could be published in the docs somewhere so that Nx users making use of VS Code (presumably most of them?) aren't losing core basic Typescript functionality like Rename?

How are the Nx team working around this in their projects?

jaysoo commented 1 year ago

AN issue is opened here, and we're getting help from the vscode folks on it. https://github.com/microsoft/TypeScript/issues/56268

tsopeh commented 11 months ago

The https://github.com/microsoft/TypeScript/issues/56268 issue got closed ("Working as Intended"). We need some official Nx docs/resource we can follow in order to solve this problem

alfaproject commented 9 months ago

Has anyone tried the solution suggested here? https://jakeginnivan.medium.com/using-typescript-project-references-in-nx-b3462b2fe6d4

zilia-gmethot commented 7 months ago

This is still a major issue for me. It is impossible to find consumers of let's say a function that is part of a shared Nx library by using the Find all references feature of the TypeScript langage server used by VS code, which is by far the most used IDE in web development. Want to rename a symbol? Now all code that depends on it is broken because it wasn't updated. And having to search by string matching is really inefficient and prone to error.

Has anyone found a solution yet?

AaronConlon commented 6 months ago

The microsoft/TypeScript#56268 issue got closed ("Working as Intended"). We need some official Nx docs/resource we can follow in order to solve this problem

2024-04-15 SOS

david-gettins commented 3 months ago

I have a similar issue from test files in an nx/next project. The non-spec files can find the lib at it's tsconfig path but not spec files...

david-gettins commented 3 months ago

The issue in my case was that the nx/next generated app set up it's tsconfigs like so:

-> tsconfig.json -> tsconfig.spec.json

As soon as I changed it to match other nx generated projects I start to get lib paths being found in spec files i.e.

-> tsconfig.app.json -> tsconfig.json -> tsconfig.spec.json

Not 100% sure, but it seems to be related to fact the app tsconfig (was tsconfig.json, now tsconfig.app.json) has includes and excludes defined. What is now my project's tsconfig.json has no include and exclude defined, but now has references.

Akuket commented 1 month ago

Hello,

Any news on this topic ?