Skip to content
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

tsconfig paths and module resolution errors in VS Code #8138

Closed
SpiraMira opened this issue Oct 21, 2017 · 42 comments · Fixed by #17586
Closed

tsconfig paths and module resolution errors in VS Code #8138

SpiraMira opened this issue Oct 21, 2017 · 42 comments · Fixed by #17586

Comments

@SpiraMira
Copy link

Bug Report or Feature Request (mark with an x)

- [x] bug report -> please search issues before submitting
- [ ] feature request

Versions.

@angular/cli: 1.4.9
node: 7.9.0
os: darwin x64
@angular/animations: 4.4.5
@angular/common: 4.4.5
@angular/compiler: 4.4.5
@angular/core: 4.4.5
@angular/forms: 4.4.5
@angular/http: 4.4.5
@angular/platform-browser: 4.4.5
@angular/platform-browser-dynamic: 4.4.5
@angular/router: 4.4.5
@angular/cli: 1.4.9
@angular/compiler-cli: 4.4.5
typescript: 2.3.4

macOS Sierra 10.12.6
VS Code 1.17.2

Repro steps.

My tsconfig path property seems broken.
When I replace my path mapped imports (@shared, @assets etc.) with the equivalent coded relative paths, typescript module resolution seems to work (vs code intellisense is happy)
I have a large angular 2 project and am used to aliasing my asset and shared directories this way.
NOTE: project builds and (seems) to run just fine
This has been reported often, but I can't make sense of the current state of this issue.
This more than annoying as VS Code reports Angular spurious errors on all of my components.
I also suspect this is why I get the infamous Can't read property isSkipSelf of null when I open my templates (html) in VS Code.
I was running 1.4.2 and just tried ~1.4.2, which resolves to 1.4.9 in my package.json, to no avail.
Will 1.5.x fix this?
How can I help debug this without providing a copy of my app?

Thanks in advance. Regards.

The log given by the failure.

Desired functionality.

Mention any other details that might be useful.

@filipesilva filipesilva added the needs: repro steps We cannot reproduce the issue with the information given label Oct 25, 2017
@filipesilva
Copy link
Contributor

Can you setup a minimal repro please? You can read here why this is needed. A good way to make a minimal repro is to create a new app via ng new repro-app and adding the minimum possible code to show the problem. Then you can push this repository to github and link it here.

@ThomasBeavers
Copy link

I am not the OP, but here is a sample repo showing a component imported via the path alias displaying the "Cannot find module" error in vscode, but successfully building with npm run build --prod.

https://github.com/Veabers/tsconfig-paths-repro-app

@sandangel
Copy link

vscode seem to only look into nearest tsconfig.json file, while angular read your tsconfig.app.json You should add relative path config to both tsconfig.json and tsconfig.app.json.

@mehs2690
Copy link

Hi @sandangel ,
I hope you are well, I followed the advice you gave to add the alias settings in both the tsconfig.json and the tsconfig.app.json, but when I'm writing the import statement I get the following:

pathsaliases

I know that this is not a priority, but I am worried when it is very possible that my application grows severely in subfolders and reaches a tedious depth of escirbir.

@sandangel
Copy link

sandangel commented Jan 13, 2018

@mehs2690 can you type environment in editor ( don't add import statement yet ) and then press Ctrl + . when cursor in environment to see what option vscode suggest? Remember that because tsconfig.json and tsconfig.json has different baseUrl so you have to align path config accordingly

here is my config:
tsconfig.json

"baseUrl": "./",
    "paths": {
      "@app/*": ["src/app/*"],
      "@env/*": ["src/environments/*"],
      "@views/*": ["src/app/views/*"]
    }

tsconfig.app.json

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "baseUrl": "./",
    "module": "es2015",
    "types": [],
    "paths": {
      "@app/*": ["app/*"],
      "@env/*": ["environments/*"],
      "@views/*": ["app/views/*"]
    }
  },
  "exclude": ["test.ts", "**/*.spec.ts"],
  "angularCompilerOptions": {
    "annotationsAs": "static fields",
    "annotateForClosureCompiler": true,
    "preserveWhitespaces": false,
    "fullTemplateTypeCheck": true
  }
}

@mehs2690
Copy link

@sandangel I have configured both the tsconfig.json and the tsconfig.app.json as you suggested, I wrote in the editor environment and got this:

notloadpaths

@sandangel
Copy link

can you try with Typescript Hero plugin?
here is my screenshot
screenshot from 2018-01-13 14 08 55

@mehs2690
Copy link

mehs2690 commented Jan 13, 2018

Thank you very much @sandangel ! with the Plugin of Typescript Hero it already detects the paths and it does not mark error in vscode. I tried compiling (ng build) and there was no error, I tried in prod mode and an error came out (ng build --prod) ERROR in ./src/main.ts
Module not found: Error: Can not resolve './$$_gendir/app/app.module.ngfactory', lastly I tried running (ng build --prod --aot = false) and everything went fine. but for the moment I can continue to develop with the help you gave me. regards

@fxck
Copy link

fxck commented Jan 15, 2018

Having problems as well. It does compile fine, but vscode cannot find it.

@mehs2690
Copy link

@fxck, Have you already tried installing the Plugin of Typescript Hero? also, it happens to me that you have to reopen the vscode so that the changes take them into account.

@Roaders
Copy link

Roaders commented Feb 1, 2018

I am having this issue as well and I am unable to install Typescript Hero as access is restricted from where I work.

For me I only get the issue in test specs.

In app.module.ts this is fine:

import { AppRoutingModule } from '@app';
import { AppComponent } from '@app';
import { SharedModule } from '@shared';

but in app.component.spec.ts I get the error here:

import { AppComponent } from '@app';

[ts] Cannot find module '@app'.

I have 3 tsconfig files:

tsconfig.json in src:

{
    "extends": "../tsconfig.json",
    "compilerOptions": {
        "outDir": "../out-tsc/app"
    },
    "exclude": [
        "test.ts",
        "**/*.spec.ts"
    ]
}

tsconfig.spec.json in src:

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/spec",
    "types": [
      "jasmine",
      "node"
    ]
  },
  "files": [
    "test.ts"
  ],
  "include": [
    "**/*.spec.ts",
    "**/*.d.ts"
  ]
}

and tsconfig.json in root:

{
    "compilerOptions": {
        "baseUrl": "src",
        "paths": {
            "@app": [
                "app/"
            ],
            "@ui": [
                "app/ui/"
            ],
            "@shared": [
                "app/modules/shared/"
            ]
        }
    }
}

When I am in app.module.ts and I do > Typescript: Go to project configuration I get taken to src/tsconfig.json. When I am in app.component.spec.ts and do the same I get a message saying Files in not part of a TypeScript project. When I go to configure tsconfig.json I get taken to the tsconfig.json in the root of the project.

This seems to be more of a VSCode issue than an angular issue so I will post this as an issue in VSCode.

@hansl hansl removed their assignment Feb 6, 2018
@filipesilva filipesilva added comp: cli/build and removed needs: repro steps We cannot reproduce the issue with the information given labels Feb 14, 2018
@mbrookson
Copy link

mbrookson commented Mar 17, 2018

Has there been any progress on this? Probably a VS Code issue rather than an Angular one. I can still replicate with the latest versions of each though. New cli project, trying to alias my src/app/ imports so they can be absolute (e.g. I want to be able to import @app/users/models/user.models.ts anywhere rather than ../../../users/models/user.models.ts with different relative paths where it is used).

I've tried adding "paths": { "@app/*": ["src/app/*"] } to the root tsconfig.json and it compiles but VS Code still shows a 'cannot fine module' error on the absolute import

@johankvint
Copy link

johankvint commented Mar 21, 2018

I had the same issue but it seams it was resolved with using a more "explicit" relative path in baseUrl in tsconfig.tswith "./src"

Before:

{
    "compilerOptions": {
        "baseUrl": "src",
        "paths": {
            "@app/*": ["app/*"],
        }
    }
}

After:

{
    "compilerOptions": {
        "baseUrl": "./src",
        "paths": {
            "@app/*": ["app/*"],
        }
    }
}

@DerekSchmid
Copy link

@johankvint, your solution of using ./src worked for me. I no longer need to use the TypeScript Hero extension either.

Something to watch out for if you use barrel files there is different setup. Let's suppose you have a guards folder in your app and your usual import is import * as fromGuards from '../../../guards';. I have found that I need to setup the following compilerOptions in order to get the desired effect. I'm not pleased with having to duplicate so much of the path, so please let me know if anyone has a better way to handle the barrels.

{
    "compilerOptions": {
        "baseUrl": "./src",
        "paths": {
            "@app/guards": ["app/guards/"],
            "@app/guards/*": ["app/guards/*"]
        }
    }
}

If you have app/guards/index.ts and a LoginGuard component you should now have the following options to import.

import * as fromGuards from '@app/guards';

or

import {LoginGuard} from '@app/guards/login.guard';

@johankvint
Copy link

@DerekSchmid Well yes if you only use @app/* you will get the desired effect:

{
    "compilerOptions": {
        "baseUrl": "./src",
        "paths": {
            "@app/*": ["app/*"]
        }
    }
}

@DerekSchmid
Copy link

@johankvint, do you mean that can work for barrel files? I receive a Cannot find module compiler error when trying to perform my imports.

Now, it does work if I explicitly import the index file... Maybe it is better to be more explicit anyways.

@johankvint
Copy link

@DerekSchmid Yes, my mistake. I just checked my project and I do not have any import * as .... from a barrel using the paths in tsconfig, only relative to the code.

@pablorsk
Copy link

pablorsk commented Jun 4, 2018

This works for me:

🔧 Move (or repeat) paths section from tsconfig.app.json to tsconfig.json

@lddubeau
Copy link

The basic problem here is that by default when the tools in TypeScript toolset try to determine which compiler configuration to use with any given file, they look for a file named tsconfig.json starting in the directory where the TS file is located. If it is not there, they recursively looks up the file system until they find a tsconfig.json file. They do not look for tsconfig.app.json, tsconfig.spec.json or tsconfig.lib.json or any other name.

The default can be overridden. Presumably, that's what angular-cli does when it invokes the TypeScript compiler or tslint. It uses -p or an API equivalent to pass it's specially named configuration files.

However, this falls apart when it comes to getting editors to automatically recognize those files. TypeScript editors that provide complete support for TypeScript, like VSCode, usually launch a tsserver instance. And tsserver being part of the TypeScript toolset, does its default thing when the editor request that it processes a file: it looks for a file named tsconfig.json. I've used tsserver in dozens of projects (including Angular projects that don't use angular-cli), and got it to find the proper tsconfig.json in all cases. (Of course the project has to be structured to take into account the default behavior of the TS toolset.) It only fails in projects that use angular-cli to generate configuration, due to the non-standard configuration file names that angular-cli uses.

An issue with the TypeScript project was opened here but it does not look like any modifications will be made to the TS toolset to handle angular-cli's unusual naming convention. I've not found a newer issue that indicates otherwise.

@kyleferguson
Copy link

I had to set module_resolution in compiler options to get this to work for me

{
    "compilerOptions": {
      "moduleResolution": "node",
      "baseUrl": "./",
      "paths": {
        "@/*": ["src/*"]
      }
}

@flash-me
Copy link

flash-me commented Nov 10, 2018

vscode seem to only look into nearest tsconfig.json file, while angular read your tsconfig.app.json You should add relative path config to both tsconfig.json and tsconfig.app.json.

Neither this

This works for me:

Move (or repeat) paths section from tsconfig.app.json to tsconfig.json

Nor this is a valid solution for the problem for the current "monorepo"-approach.

If we have multiple projects in one repo, the determination for a "project" in the context of angular is done by tsconfig files. Now imagine that you have 3 projects A & B & C, while B & C being a library project. As a good developer you want a clean separation between your concerns in such architecture / structure:

  • Project A depends on B & C, therefore it has a mapping to C and to B
  • Project B knows nothing about C & A
  • Project C knows nothing about B & A

You are going to solve this by adding the mapping into the tsconfig of the Project A and not in the root tsconfig of the repo, otherwise you would create a relation/mapping what you actually don't want..

We too suffer from this bug. At first I was thinking this is a bug in Webstorm, but after discovering this thread things got interesting.

@kurtommy
Copy link

Yeah we've the same problems, we've added two angular projects in the same repo and we've two different tsconfig files, because different apps require different alias.
the app is compiling and running fine but VSCode highlight every import in red, and the intellisense for paths is broken

@flash-me
Copy link

flash-me commented Jan 30, 2019

We use non-standard names for the each project tsconfig because there are files for two different compilations contexts side by side in the same folder. These are your app TS files, and your unit test TS files.
......
We didn't do this from the start because it was another file, and we were trying to keep the file count as low as we could. But maybe we should do this now when adding a new project.

Sounds valid. But as far as I understand the reason for having separate tsconfig files is due to the different compilation contexts, right? So why keeping those files at all? You could wrap the relevant settings into angular.json and just keep one tsconfig for each project for the IDE's.

You could even extend the cli to have a section "typescriptOptions" which then could have multiple "targets" or "configs" in the same manner like the other build/serve configs:

{
  "projects": {
   ....
   },
   "schematics": {
   ...
   },
   "typescriptOptions": {           // sample name...
      "configurations": {
         "latestChrome": { ... },
         "unitTests": { ... },
      }
   }
}

This could work, don't? At least I'm not aware of any restrictions / blocker for not doing this.

@filipesilva
Copy link
Contributor

I'm not a big fan of adding the TS options in the angular.json file to be honest. It makes TS options more opaque because you can't change the file on disk directly, removes the autocomplete for tsconfig that some editors have, and removes interop with other tools.

@flash-me
Copy link

flash-me commented Feb 2, 2019

I don't get it. You can also change the angular.json directly on the fs + one could just extend the json schema to reference the one from tsconfig in order to have autocomplete.
Can you give me an example for another tool that uses e. g. tsconfig.app.json etc?

In my example it was intended to leave at least one tsconfig.json and hide the additional ones, because even TypeScript itself has no support for other naming patterns

@filipesilva
Copy link
Contributor

I often run tsc -p src/tsconfig.app.json myself, for instance. Or ngc -p src/tsconfig.app.json. You could run other tools that take typescript configuration (like tslint) by pointing it at the file as well.

@flash-me
Copy link

flash-me commented Feb 3, 2019

Okay, but the tool devs have to provide such functionality, nothing out of the box. Can you tell Vscode to use a particular tsconfig for its autocomplete? Or can you configure the angular language service to use another tsconfig? Even if your IDE can handle other naming patterns, how does it know which one to use for a specific folder, if there are multiple tsconfigs. The one for unit tests also include the origin files...

The feedback I'm receiving pretty often is that it's not really clear which of those files is now being used from the IDE while you are developing / doing other tasks.

@mhamri
Copy link

mhamri commented Feb 3, 2019 via email

@lifenstein
Copy link

lifenstein commented Feb 15, 2019

I was having troubles with absolute and relative URLs myself; ended up following instructions at https://hackernoon.com/react-pro-tip-use-absolute-imports-for-better-readability-and-easy-refactoring-2ad5c7f2f957 which completely fixed the issues.

TL;DR:
Make a .env file in project root and add this:
NODE_PATH=src/

Then make a jsonconfig.json file in project root and add this:

{
  "compilerOptions": {
    "baseUrl": "src"
  }
}

I'm actually in a React codebase and don't even use typescript in it, yet setting the "javascript.implicitProjectConfig.checkJs": true in my vscode settings gives me all the intellisense I need with just these two changes!

@ruojianll
Copy link

ruojianll commented Feb 15, 2019

There are many folders in my VSCode workspace inspector, and VSCode may only use the first folder's tsconfig.json. If your tsconfig.json is not in the first folder, drag the folder to the first and try it again, it worked for me.

So one project one workspace and place the configure folder at first place.

@dagatsoin
Copy link

dagatsoin commented Feb 18, 2019

As there is no clear solution, I will past my working one:

folders:
-root
-tsconfig.json #the package config
--src #the source of my package
--demo
--tsconfig.json #the storybook config referencing my upper module as "@sproutch/ui"

Important note

I had to remove "rootDir": "src", from the root package config to make it work.

Here are the full files.

Package config

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "forceConsistentCasingInFileNames": true,
    "jsx": "react",
    "lib": ["es2017", "dom"],
    "module": "commonjs",
    "declaration": true,
    "moduleResolution": "node",
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noUnusedParameters": true,
    "outDir": "lib",
    "preserveConstEnums": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "strictNullChecks": true,
    "suppressImplicitAnyIndexErrors": true,
    "target": "es5",
    "types": ["node", "react", "react-dom", "react-native"]
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "build",
    "node_modules",
    "jest.config.js",
    "App.js",
    "babel.config.js",
    "metro.config.js"
  ],
  "compileOnSave": false
}

Storybook subfolder config

{
  "compilerOptions": {
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "baseUrl": "../",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "forceConsistentCasingInFileNames": true,
    "jsx": "react",
    "lib": ["es2017", "dom"],
    "module": "commonjs",
    "moduleResolution": "node",
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "outDir": "lib",
    "paths": {
      "@sproutch/ui": ["./src"]
    },
    "preserveConstEnums": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "strictNullChecks": true,
    "suppressImplicitAnyIndexErrors": true,
    "target": "es5",
    "types": ["node", "react", "react-dom", "react-native"]
  },
  "include": [
    "./stories/**/*",
  ],
  "exclude": [
    "./stories/**/*native*",
  ]
}

@smaranh
Copy link

smaranh commented Jan 17, 2020

Here is how I fixed it, turns out it is a problem with VSCode. Sometimes changes to tsconfig are not reflected in the IntelliSense. I closed VSCode and made sure no VSCode process was running. They reopened VSCode and Voila! IntelliSense now detects the @ 😩

@filipesilva
Copy link
Contributor

microsoft/TypeScript#37239 might help with this. It's described in https://devblogs.microsoft.com/typescript/announcing-typescript-3-9-beta/ as follows:

Support for “Solution Style” tsconfig.json Files
...
This file that really does nothing but manage other project files is often called a “solution” in some environments. Here, none of these tsconfig.*.json files get picked up by the server, but we’d really like the language server to understand that the current .ts file probably belonds to one of the mentioned projects in this root tsconfig.json.

TypeScript 3.9 adds support to editing scenarios for this configuration. For more details, take a look at the pull request that added this functionality.

@filipesilva filipesilva added the needs: discussion On the agenda for team meeting to determine next steps label Mar 30, 2020
@dgp1130 dgp1130 removed the needs: discussion On the agenda for team meeting to determine next steps label Apr 9, 2020
@dgp1130
Copy link
Collaborator

dgp1130 commented Apr 9, 2020

Discussed this in a meeting earlier and tsconfig "solutions" can be a great answer to this problem. We'll do some more investigation to see exactly how this can work and what release we can fit it into.

@alan-agius4
Copy link
Collaborator

Being tracked internal TOOL-1368

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jun 20, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.