microsoft / vscode

Visual Studio Code

Home Page:https://code.visualstudio.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Peek/Go To Definition & Click to Open do not work with Webpack alias

damonbauer opened this issue · comments

  • VSCode Version: 1.8.0-insider
  • OS Version: OSX El Capitan 10.11.6

Using normal, path based imports, Peek/Go To Definition and CMD+Click to open file from import work wonderfully. When using a Webpack alias, Peek/Go To no longer work. It kind of "fails silently" in that nothing appears (not even an error message).

Steps to Reproduce:

  1. Add an alias to a webpack config file
  2. Import a file using an ES6 import with the path to the file that includes the Webpack alias

Desired Behavior:

  1. Using a Webpack alias inside an ES6 import, Peek/Go To Definition display in the same manner as when using a full path inside an import.
  2. CMD+Click to Open File from import statement works with both full paths and webpack aliases

I've created a reduced repo that demonstrates the behavior: https://github.com/damonbauer/webpack-alias-demo/

I'm setting an alias in the webpack config to map the word app to the path of /src. Then in a file, I'm importing another with ES6 imports.

Edit: I'm also using the PathIntellisense extension with custom mappings so I can get path autocompletion when using an alias in an import. Perhaps there could be something helpful in that repo?

EDIT: I only seem to be able to get path autocompletion, not "peek" or "Go to definition" with the feature described below. I've recently switched computers (from a PC to a Mac), and could have sworn it worked on the PC. Will investigate and update once I know more.


It may be of interest to note that the latest release of WebStorm brings this feature. I mention this not to suggest making the switch, but rather to further underline that this could be a very useful feature :)

I'd like to clarify what @damonbauer states above: the feature can be achieved manually with the Path Intellisense extension, by defining path-intellisense.mappings in your vscode settings. The example they provide in the documentation is as follows:

{
    "path-intellisense.mappings": {
        "/": "${workspaceRoot}",
        "lib": "${workspaceRoot}/lib",
        "global": "/Users/dummy/globalLibs"
    },
}
commented

+1 Very useful to me.

@wanecek Were you able to get Peek Definition and CMD+Click working with the path-intellisense.mappings? Adding those mappings did allow for suggestions as I'm typing an import statement and using a webpack alias, but didn't seem to change the functionality at all with Peek Definition or CMD+Click. If you were able to get that working somehow, I'd love to see more details on your setup.

+1 would be super awesome to have this. We just moved all the import paths in our project to use webpack aliases and I miss the command clicking. I can only get the autocomplete to work with path-intellisense.mappings.

You can accomplish this using the "paths" option. Full writeup here. TL;DR add

{
  "compilerOptions": {
    // This must be specified if "paths" is set
    "baseUrl": ".",
    // Relative to "baseUrl"
    "paths": {
      "*": [
        "*",
        "mypath/*"
      ]
    }
  }
}

to your jsconfig.json or tsconfig.json in your project's root.

can't get this to work :

"path-intellisense.mappings": {
"/": "${workspaceRoot}",
"components": "${workspaceRoot}/src/components"
},

OR / AND

{
"compilerOptions": {
"target": "es2015",
"lib": ["dom", "es2015", "es2017"],
"module": "commonjs",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true
"baseUrl": ".",
"paths": {
"components/": ["", "src/components/"]
}
},
"exclude": ["./node_modules/**/
"]
}

Hey @wesleymostien, I ended up solving it by putting a jsconfig.json in the root of my project, with the following content:

{
  // This file is required for VSCode to understand webpack aliases
  "compilerOptions": {
    // This must be specified if "paths" is set
    "baseUrl": ".",
    // Relative to "baseUrl"
    "paths": {
      "@/*": ["./src/*"],
    }
  }
}

which works fine for me. I think you might be missing the asterix (*) in your example :)

@wanecek doesn't seem to matter

now I have this :

"baseUrl": "./src",
"paths": {
  "components": ["./components/*"]
}

so, I can import absolute mapping with 'components/....' . That part works!

But the problem is, Intellisense doesn't show me *.vue files, can this be fixed?

so, I can import absolute mapping with 'components/....' . That part works!

Not sure I understand this... Did you get the Intellisense features (e.g. the type-hint tooltips on hover) working or not?

If not, you might want to give this a try as well.

"paths": {
  "components/*": ["./components/*"]
}

For the path-intellisense, I have the path-intellisense extension, and have extended it with this in the workspace settings:

"path-intellisense.mappings": {
  "@": "${workspaceRoot}/src"
},

Yeah, I've got this working, not sure what's making it work though.
Try installing the veturextension if you haven't already.

However, I think this issue is getting out of topic. Send me an email instead (see my GH profile) and I'll try to help you :)

tried all solutions provided here, no one is correctly working :( ctrl+click still no reaction

commented

I've found solution
I had import SomeComponent from '@/someComponent
Changing it into import SomeComponent from '@/someComponent/index made peek/goto definition working

I have jsconfig.json in my project root with these settings

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "~/*": ["./src/*"],
      "@/*": ["./src/components/*"]
    }
}
commented

in general it doesn't matter if there's index in that path. It's important to place another path level after @/something/...(here)...

If you have that file hierarchy Folder -> ComponentFolder -> index.js you can write import component from '@/Folder/ComponentFolder' and it will work if you paths is "@/*": ["./src/"] in this case

Do not forget to make sure that in your visual studio code settings "javascript.validate.enable" is true.
In my case I disabled it it, thats why I didn't got intellisense.
Now everything is ok.

Sorry my improvised English

Somehow I still can't get this to work.

I've got a jsconfig.json

My webpak resolve config

let config = {
	...,
	resolve: {
		modules: [
			path.resolve(__dirname, './src/js'),
			'node_modules'
		]
	},
	...
}

My jsconfig.json

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

@nickngqs , don't know how it works but try this on jsconfig:
"modules/*": ["*", "./src/modules/*"]

I was having trouble and somehow the extra wildcard helped me. Maybe someone could add something about it.

My .jsconfig looks like:

{
    "module": "es6",
    "compilerOptions": {
        "module": "es6",
        "target": "es5",
        "allowSyntheticDefaultImports": true,
        "baseUrl": "./source/",
        "paths": {
            "*": ["./assets/js/*"],
            "vendor/*": ["./vendors/js/*"]
        }
    },
    "exclude": [
        "node_modules"
    ],
    "compileOnSave": false
}

And works like a charm

commented

I'm having the same problem, but I do not get any suggestions at all, as soon as I'm in the alias directory...

For Example if I am using:
import Button from 'third/Button'
the "Button" part I would have to type in manually, there is no suggestion.

I have followed this guide, but no success.

My jsconfig.json:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "allowSyntheticDefaultImports": true,
    "baseUrl": ".",
    "paths": {
      "first": ["./src/first"],
      "second": ["./src/second"],
      "third": ["./src/style/css/home"],
    }
  },
  "exclude": [
    ".gitlab",
    ".storybook",
    ".vscode",
    "node_modules",
    "public"
  ]
}

Any ideas?

commented

If your project structure looks like

src
| Component
| | comp2.js
| hello.js

and you import your file like this

import hello from 'hello'
import comp2 from 'Component/comp2'

then your jsconfig.json should look like

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

Hello all,

 “moduleResolution”: “node”,

Seems to be necessary if you have your exports from your alias in an index.js file. Ta!

commented

Both did not work for me. Here is a more detailed setup, can anyone point me to the right direction?

See #30290(Go to definition for .jsx does not work). I was trying all the snippets from this thread with no luck until I found that it worked on .js files, but not .jsx, where I did all the testing.

I built a minimal broken test project (zip, 3kB) for my use case. Can anyone give a look at it? Ping @mjbvz

Extract the zip and see README.md: like other people, path autocompletion works, but not "peek" or "Go to definition".

  • npm install && npm run build && node dist/index.js
    → Install & build both succeed, indicating Webpack is happy. Run logs [1, 2, 3].
  • Now, run code /path/to/project and open src/index.js
    On line 5, try to F12 on getLinks
    No definition found for 'getLinks' 😢

Am I still doing something wrong in my jsconfig.json, or is this a bug? (the multiple levels of exports, maybe?)

@ronjouch Try asking on stack overflow

@mjbvz with help on SO / Why does VSCode's “Go to definition” fail on my project using Webpack alias, I confirm it's a vscode bug of the Webpack aliases jsconfig feature:

  • Webpack is happy with my minimal broken test project (zip, 3kB) and builds it successfully.
  • VS Code isn't, fails on Go to Definition, and can be "fixed" by messing with jsconfig and the exports:
    • jsconfig.json: change paths to "api/*": ["./src/api/*"]
    • src/api/resources/index.js: change import/export to import * as Links from './links'; export {Links};

With that, Go to Definition works.

→ To me, looks like a bug of vscode's Webpack aliases jsconfig feature.

See #30290(Go to definition for .jsx does not work). I was trying all the snippets from this thread with no luck until I found that it worked on .js files, but not .jsx, where I did all the testing.

Did you ever get this working for jsx files @tomaskikutis ?

Yep, I got it working using this jsconfig.json:

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es6",
        "jsx": "preserve",
        "paths": {
            "apps/*": [
                "./scripts/apps/*",
            ],
            "core/*": [
                "./scripts/core/*",
            ],
        },
        "baseUrl": ".",
    },
    "exclude": [
        "node_modules",
        "bower_components",
        "po",
    ]
}

Here's an example of a working import

import {Modal} from 'core/ui/components/Modal/Modal';

If you're interested, you can try it out here: https://github.com/superdesk/superdesk-client-core/tree/9072076

See /scripts/apps/authoring/authoring/previewModal.jsx or any other *.jsx file

Cheers mate! Turns out that it's the "jsx": "preserve" line that fixed it for me although I set mine to "jsx": "react". I think you essentially just need to set jsx to whichever option is relevant in the compilerOptions

This should be natively supported by VSCode (the thing to resolve paths according to webpack aliases)? Typescript should be removed as a tag also, as it is webpack not typescript related.

@bosung90

If your project structure looks like

src
| Component
| | comp2.js
| hello.js

and you import your file like this

import hello from 'hello'
import comp2 from 'Component/comp2'

then your jsconfig.json should look like

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

This doesn't seem to work for me.

I've created a barebones babel project to demonstrate my issue here https://github.com/aminnaggar/vscode-module-resolution am I missing something?

commented

@aminnaggar Its been a long time, and I just stopped using it because it isn't consistent.

"I've created a barebones babel project to demonstrate my issue here https://github.com/aminnaggar/vscode-module-resolution am I missing something?"

@aminnaggar in comment #16320 (comment) (above, and repeated below), I also confirm the bug with a minimal test case passing Babel but failing to F12. Ping @mjbvz @damonbauer ; I hope this bug with clear reproduction scenarios can be prioritized in some future iteration 🙂.

With help on SO / Why does VSCode's “Go to definition” fail on my project using Webpack alias, I confirm it's a vscode bug of the Webpack aliases jsconfig feature:

  • Webpack is happy with my minimal broken test project (zip, 3kB) and builds it successfully.
  • VS Code isn't, fails on Go to Definition, and can be "fixed" by messing with jsconfig and the exports:
    • jsconfig.json: change paths to "api/*": ["./src/api/*"]
    • src/api/resources/index.js: change import/export to import * as Links from './links'; export {Links};

With that, Go to Definition works.

→ To me, looks like a bug of vscode's Webpack aliases jsconfig feature.

Is there no solution for this as of this time? I'm going crazy working in a new Vue project and i dont think i can handle it.

For those that may still be having trouble with this issue, the location of the jsconfig file is important! I was trying to put it in the root of the repo and no combination of path/baseUrl would allow the Peek/Go To Definition to work. It was after I moved it into src that I could get it to work (The realization came from reading this issue microsoft/vscode-docs#119).

commented

Setting "paths" in jsconfig.json can solve webpack alias problems.
But meanwhile, "Peek/Go To Definition" will not work for packages in node_modules with their own typing definition files(e.g. axios).

@suyi91 try remove target config, that should work

Setting "paths" in jsconfig.json can solve webpack alias problems.
But meanwhile, "Peek/Go To Definition" will not work for packages in node_modules with their own typing definition files(e.g. axios).

commented

this helped me a lot (jsconfig.json)

Me too, but it didn't solve my problems.

I'm still into trouble with this 😢
I have already tried all workarounds on Github/Stackoverflow/Internet... and nothing solves the "Go to definition" issue.

The webpack build process and intellisense completion feature goes well, btw.

Screenshot from 2019-09-08 20-21-53

My configs:
webpack.config.js

module.exports = {
    ...
    resolve: {
        alias: {
            "~": path.resolve(__dirname, 'src'),
            Styles: path.resolve(__dirname, 'src', 'assets', 'styles'),
            Images: path.resolve(__dirname, 'src', 'assets', 'images'),
        }
    },
    ...
};

jsconfig.json

{
    "exclude": ["node_modules", "dist"],
    "compilerOptions": {
        "module": "es6",
        "allowSyntheticDefaultImports": false,
        "baseUrl": "./",
        "paths": {
            "~/*": ["src/*"],
            "Styles/*": ["src/assets/styles/*"],
            "Images/*": ["src/assets/images/*"]
        }
    }
}

After dealing with this for a little bit:

{
    "compilerOptions": {
        "target": "esnext",
        "jsx": "preserve",
        "baseUrl": ".",
        "paths": {
            "@/*": ["src/*"]
        }
    }
}

resolve both Ctrl+Click, Peek, GoToDef and path completion for me. Specifically adding an undocumented "jsx": "preserve". Don't forget to restart VSC, as it had an impact in some cases...

What doesn't work is the import App from '@/modules' where the App is a module in src/modules/index.jsx.

After dealing with this for a little bit:

{
    "compilerOptions": {
        "target": "esnext",
        "jsx": "preserve",
        "baseUrl": ".",
        "paths": {
            "@/*": ["src/*"]
        }
    }
}

resolve both Ctrl+Click, Peek, GoToDef and path completion for me. Specifically adding an undocumented "jsx": "preserve". Don't forget to restart VSC, as it had an impact in some cases...

What doesn't work is the import App from '@/modules' where the App is a module in src/modules/index.jsx.

you saved my day man! they key was the undocumented "jsx": "preserve", option.

It's working for me using React components and .JSX files:

  • Path completion / path-intellisense
  • Ctrl+Click and go to the JSX file
  • Right Click + Go to Definition
  • Right Click + Peek Definition
  • Right Click + Go to Type Definition

Here is my config file:

{
  "compilerOptions": {
    "jsx": "preserve",
    "baseUrl": ".",
    "paths": {
      "*": [
        "*",
        "src/*"
      ]
    }
  },
  "exclude": ["node_modules"]
}

Finally got this working with React jsx, with go to definition and all. You need jsconfig.json, looking like this (note you need the "jsx": "react" property, and to specify the trailing 'index.jsx' in the aliases, if using the implicit class-as-folder-name paradigm):

{ 
    "compilerOptions": {
        "baseUrl": "./src",
        "paths": { 
            "shared/*":       ["./components/shared/*/index.jsx"],
            "components/*":   ["./components/*/index.jsx"],
            "stores/*":       ["./lib/stores/*"],
            "services/*":     ["./lib/services/*"],
            "utils/*":        ["./lib/utils/*"]
        },
        "module": "commonjs",
        "target": "es6",
        "moduleResolution": "classic",
        "jsx": "react"
    }
}

Then imports like this all work:

import UserApi from 'services/api/UserApi';
import EditArea from 'components/views/Blog/EditArea';
import EditableLabel from 'shared/EditableLabel';

Hope it helps!

Hey, @claudio-moya / @rw3iss! I really appreciate your help!
I made it work with a simpler version than that was suggested, but it is working perfectly. The "jsx": "react" do the trick!

{
    "exclude": ["node_modules", "dist"],
    "compilerOptions": {
        "jsx": "react",
        "baseUrl": "./src",
        "paths": {
            "~/*": ["./*"]
        }
    }
}

Here is a working example view from a simple CRA that I tested right now!

Peek 2019-12-06 14-59

If your project structure looks like

src
| Component
| | comp2.js
| hello.js

and you import your file like this

import hello from 'hello'
import comp2 from 'Component/comp2'

then your jsconfig.json should look like

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

I was defining all properties OUTSIDE of compilerOptions and therefore it wasn't working. The dumbest thing I've wasted time on.

commented

Peek to definition works fine just only with js-ts-tsx-jsx files.
You can recheck correct configuration here: https://github.com/Yegorich555/WebpackMustHave/tree/vscode-peek-definition
But it doesn't work at all with images, fonts etc.

I configured path-intellisense.mappings in .vscode/settings.json and it affects on path_autocomplete but peek-definition doesn't work at the same time. What is solution can be for this???

@Yegorich555 I don't think TS can or should complete images, fonts, etc. All of them have a behaviour defined only in webpack loaders' sense (or other bundler). They don't make sense as ES or TS modules at all. So TS can't and shouldn't hook into bundlers's compilation process

commented

@troglotit I see your point and it makes sense. But I would like to see organic and cohesive system for frontend-development. Vue is a good extension for developing *.vue on VSCode but it's related to vue and unfortunately webpack doesn't provide anything similar for native js and ts...

we should have an extension that can automatically tap into webpack config bridge vscode gap

commented

Yes. It makes sense.

Vue uses Vetur which itself is an LSP server. Maybe more sound architectural solution would be "Webpack LSP server" which uses tsserver as a library for js/ts, and with additional servers for other kinds of artifacts.

Finally got this working with React jsx, with go to definition and all. You need jsconfig.json, looking like this (note you need the "jsx": "react" property, and to specify the trailing 'index.jsx' in the aliases, if using the implicit class-as-folder-name paradigm):

{ 
    "compilerOptions": {
        "baseUrl": "./src",
        "paths": { 
            "shared/*":       ["./components/shared/*/index.jsx"],
            "components/*":   ["./components/*/index.jsx"],
            "stores/*":       ["./lib/stores/*"],
            "services/*":     ["./lib/services/*"],
            "utils/*":        ["./lib/utils/*"]
        },
        "module": "commonjs",
        "target": "es6",
        "moduleResolution": "classic",
        "jsx": "react"
    }
}

Then imports like this all work:

import UserApi from 'services/api/UserApi';
import EditArea from 'components/views/Blog/EditArea';
import EditableLabel from 'shared/EditableLabel';

Hope it helps!

Thanks for this @rw3iss, super helpful. Also had trouble with baseUrl as ./src and getting go-to-definition to work. Got this to work without defining all subpaths after src using the following, in case it helps anyone:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "moduleResolution": "classic",
    "jsx": "preserve",
    "baseUrl": "./src",
    "paths": {
      "*": ["./*/index"]
    }
  },
}

"paths": {
  "*": ["./*/index"]
}

Cool, nice way to avoid all the aliases! Thanks for sharing.

Yep, I got it working using this jsconfig.json:

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es6",
        "jsx": "preserve",
        "paths": {
            "apps/*": [
                "./scripts/apps/*",
            ],
            "core/*": [
                "./scripts/core/*",
            ],
        },
        "baseUrl": ".",
    },
    "exclude": [
        "node_modules",
        "bower_components",
        "po",
    ]
}

Here's an example of a working import

import {Modal} from 'core/ui/components/Modal/Modal';

If you're interested, you can try it out here: https://github.com/superdesk/superdesk-client-core/tree/9072076

See /scripts/apps/authoring/authoring/previewModal.jsx or any other *.jsx file

Did Command Click work for you?

Hey @wesleymostien, I ended up solving it by putting a jsconfig.json in the root of my project, with the following content:

{
  // This file is required for VSCode to understand webpack aliases
  "compilerOptions": {
    // This must be specified if "paths" is set
    "baseUrl": ".",
    // Relative to "baseUrl"
    "paths": {
      "@/*": ["./src/*"],
    }
  }
}

which works fine for me. I think you might be missing the asterix (*) in your example :)

Totally forgot about (*) asterisk thing, thanks

Hey, @claudio-moya / @rw3iss! I really appreciate your help!
I made it work with a simpler version than that was suggested, but it is working perfectly. The "jsx": "react" do the trick!

{
    "exclude": ["node_modules", "dist"],
    "compilerOptions": {
        "jsx": "react",
        "baseUrl": "./src",
        "paths": {
            "~/*": ["./*"]
        }
    }
}

Here is a working example view from a simple CRA that I tested right now!

Peek 2019-12-06 14-59

Thanks! It is working with CRA as expected!

Sad to see this issue to be still open for so many years. I hope it will be fixed someday soon.

After a lot of attempts, this worked in my case:

{
  "compilerOptions": {
    "baseUrl": ".",
    "allowJs": true,
    "resolveJsonModule": true,
    "jsx": "preserve",
    "module": "commonjs",
    "target": "es5",
    "sourceMap": true,
    "paths": {
      "$root/*": ["./*"],
      "@/*": ["src/*"]
    }
  },
  "include": [
    "**/*",
    "**/*.json"
  ],
  "exclude": [
    "node_modules"
  ]
}

I still can not get CTRL + CLICK working for absolute paths.

I have tried every setting in jsconfig, webpacking resolve, path intellisene plugin for VSCode... nothing changes.

I've been wrestling with not being able to "click open Component files" for a month since implementing webpack aliases, and found the solution from this thread.

"jsx": "react" did the trick for my simple configuration. Thanks everyone.

{
  "compilerOptions": {
    "jsx": "react", // This was the fix
    "baseUrl": ".",
    "paths": {
      "@js/*": ["js/*"]
    }
  },
  "exclude": ["node_modules", "static"]
}

For anyone still struggling, I created a gist of my config that FINALLY works, without any errors etc after a few hours of googling.
It's so so slick, I adore it! It takes a few seconds to "warm up" and index everything, but once it has.. it's like night and day 🎉

It's likely I have redundancies in there.. but it's Friday evening and I am just glad it works 😅