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

Support custom root directory alias for imports #14907

Closed
jamietre opened this issue Nov 3, 2016 · 47 comments
Closed

Support custom root directory alias for imports #14907

jamietre opened this issue Nov 3, 2016 · 47 comments
Assignees
Labels
feature-request Request for new features or functionality javascript JavaScript support issues

Comments

@jamietre
Copy link

jamietre commented Nov 3, 2016

VSCode depends on being able to resolve imported references for intellisense. So when using something that rewrites import paths -- specifically: babel-plugin-module-resolver -- we lose intellisense.

This is very useful for large projects, because it avoids deeply nested path resolutions, e.g.

import 'thing-to-test' from '../../../../../src/feature/subfeature/helper/thing

These are a big nuisance because apart from being ugly & it's hard to locate the file in the first place, anytime you move a code block, you have to refactor them. The aforementioned module lets you define an alias like "~=/src" and then just:

import 'thing-to-test' from '~/feature/subfeature/helper/thing

Atom and Webstorm are both capable of being configured with information about such aliases to enable them to resolve the paths correctly.

Is there any way this capability can be added to VS Code? I really want to be able to continue to use these, but the loss of intellisense is tough to swallow.

@dbaeumer
Copy link
Member

dbaeumer commented Nov 3, 2016

@waderyan IMO tsserver 2.0.3 is able to do this. They now support a rootPath. But you need to test.

@waderyan
Copy link

@jamietre thank you for opening this issue. This fell through the cracks for me so apologize it took some time. We have done a fair amount of work here. Can you try again with VS Code Insiders? If it is still not working can you share a workspace with me to test out the issue.

@waderyan waderyan added info-needed Issue requires more information from poster javascript JavaScript support issues labels Nov 14, 2016
@jamietre
Copy link
Author

@waderyan no problem - but how do I test it? I assume there needs to be some config to tell it what aliases e.g. ~ mean.

@waderyan
Copy link

@jamietre apologize that my writing was unclear. Please test the situation you described in this issue. Do we still "[lose] IntelliSense" when import paths are rewritten? If you have a workspace that shows the issue can you share it with me.

@jamietre
Copy link
Author

jamietre commented Nov 15, 2016

I can create a workspace but it's quite simple really,

module 1:

import something from '~/folder1/folder2/module2'

where the true relative path might be ../../../folder1/folder2/module2.js if accessed relatively from the location of the current file.

I think you might be unclear on the situation I am describing (or feature I am requesting) because import paths aren't being rewritten by VS Code, they are being rewritten during my build process by a babel plugin. VS Code would have no knowledge of this process or what the mappings meant, unless it actually did some analysis of the compiled code, or had specific knowledge of the plugin I mentioned and parsed .babelrc to use the same config.

The simple solution would be for some configuration in VS Code where I can tell it that for this workspace, ~/ in an import means {projectRoot}/src/. But this alias could be anything, e.g. I might also have one called ~test/ that points to my test root. I don't see how anything would just start working unless I added config to tell VSCode what my aliases means. (Just to be sure I did try it in today's insider, still doesn't work)

@waderyan
Copy link

waderyan commented Dec 9, 2016

@jamietre thank you for your explanation. I looked around in Atom and WebStorm but couldn't find how to do this. Can you point it out for me? We may want to adopt something similar.

@mhegazy @bowdenk7 have either of you seen a request like this before? Is this something that could be done? Exploring the possible solutions right now.

@waderyan waderyan changed the title Feature request: support custom root directory alias for imports Support custom root directory alias for imports Dec 9, 2016
@waderyan waderyan added feature-request Request for new features or functionality and removed info-needed Issue requires more information from poster labels Dec 9, 2016
@marianban
Copy link

WebStorm has a feature called "resource root" which lets you use path aliases:
http://stackoverflow.com/questions/34943631/path-aliases-for-imports-in-webstorm

This would be a very handy feature for developers using webpack.

@jamietre
Copy link
Author

jamietre commented Dec 13, 2016

@Majomb thanks - sorry i totally missed this question. I am not an Atom user but the 'babel-plugin-module-alias' website says "Atom: Uses atom-autocomplete-modules and enable the babel-plugin-module-resolver option."

An implementation of this feature that's compatible with babel-plugin-module-alias would allow you to specify a prefix and a replacement. Whenever VS Code resolves a path in an "import", if it starts with the prefix from my config, then the prefix is replaced with my substituation path, The replaced value should handled as if it is rooted at the project workspace root. I could see a regex based implementation also having added value too.

e.g.

 {
    "~": "./src",
    "~test": "./test"
 }

This would result in an import in file {root}/test/common/util.js

import { thing } from "~/common/util"

being mapped to

import { thing } from "../../../src/common/util"

as far as VS code is concerned. It would then be able to find the file and intellisense and everything else would work. This is exactly what the babel plugin does when you compile. Obviously the benefit of using this babel-plugin-module-alias in the first place is not having to deak with & refactor crazy relative paths :)

@mhegazy
Copy link

mhegazy commented Dec 13, 2016

This is already supported using paths mapping. in your tsconfig.json/jsonfig.json add an entry to your path mapping rules to match the ~ to whatever root you need. e.g.:

{
    "compilerOptions": {
        "baseUrl": "./",  // all paths are relative to the baseUrl
        "paths": {
            "~/*" : ["*"]   // resolve any `~/foo/bar` to `<baseUrl>/foo/bar`
        }
    }
}

hope that helps.

@marianban
Copy link

@mhegazy thanks for quick response. Seems that those compiler options are only allowed in tsconfig.json files and are missing from jsconfig.json.

https://www.typescriptlang.org/docs/handbook/compiler-options.html (paths is marked with [2])
https://code.visualstudio.com/docs/languages/jsconfig (paths is not listed as available option)

@mhegazy
Copy link

mhegazy commented Dec 14, 2016

The option is honored in the two files. the schema needs to be updated in https://github.com/SchemaStore/schemastore/blob/master/src/schemas/json/jsconfig.json. PRs are welcomed.

@jamietre
Copy link
Author

jamietre commented Dec 14, 2016

It doesn't seem to work for me. In my jsconfig.json:

image

Is the syntax I'm using to specify the targets correct? I don't get intellisense when using the alias, and "go to definition" doesn't work.

@mhegazy
Copy link

mhegazy commented Dec 14, 2016

Please provide some repro project we can use to diagnose. here is what i see:

animation

@jamietre
Copy link
Author

That looks exactly like what I'd expect! I am using insider, though can't think why that would make a difference for this. Will try in the release just to be sure..

The project I've been playing with is pretty huge, I'll try it in something more trivial to determine if it's my project or the environment.

@weikinhuang
Copy link

Also the ability to specify additional module directories would be extremely useful as webpack allows you to do so:

{
...
  resolve: {
    modules: [path.join(__dirname, 'js'), 'node_modules'],
    ...
  },
...
}

This allows for the ability to reference source files without direct path resolutions such as

// from js dir
import api from 'data/api';

// from node modules
import _ from 'lodash';

@t1mmen
Copy link

t1mmen commented Jan 8, 2017

I'm attempting to get this working (in a similar setup as @weikinhuang) without any luck. Should this work already?

// jsconfig.json
{
    "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "allowSyntheticDefaultImports": true,
        "baseUrl": "./",
        "paths": {
          "components/": ["src/components/*"],
          "utils/": ["src/utils/*"],
          "redux/": ["src/redux/*"],
          "routes/": ["src/routes/*"],
          "api/": ["src/api/*"]
        }
    }
}
// Relevant webpack config:
const config = {
  resolve: {
    modulesDirectories: [
      'src',
      'node_modules',
    ],
    extensions: ['', '.json', '.js', '.jsx'],
   },
}
// src/components/SomeComponent.js

import AnotherComponent from 'components/AnotherComponent'; // doesn't work
import TestComponent from './TestComponent' // works as expected

@mhegazy
Copy link

mhegazy commented Jan 10, 2017

I'm attempting to get this working (in a similar setup as @weikinhuang) without any luck. Should this work already?

You are missing an * in your mappings:

// jsconfig.json
{
    "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "allowSyntheticDefaultImports": true,
        "baseUrl": "./",
        "paths": {
          "components/*": ["src/components/*"],
          "utils/*": ["src/utils/*"],
          "redux/*": ["src/redux/*"],
          "routes/*": ["src/routes/*"],
          "api/*": ["src/api/*"]
        }
    }
}

From these mappings, it seems that all you need is to set the baseUrl to src/.

all path mapping entries are relative to baseUrl. since all your path mapping entries are subfolders of the src directory, it would be easier to just not have path mappings.

you can read more about how path mapping works at: www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping

@t1mmen
Copy link

t1mmen commented Jan 10, 2017

@mhegazy, thank you so much, basePath: "src/" did the trick! May your day be as awesome as you are!

@mhegazy
Copy link

mhegazy commented Jan 12, 2017

thanks 🌷. glad it worked.

@mjbvz
Copy link
Contributor

mjbvz commented Jan 13, 2017

Closing as it sounds like this issue has been fixed.

@mjbvz mjbvz closed this as completed Jan 13, 2017
@devrelm
Copy link

devrelm commented Feb 7, 2017

I'm actually still seeing issues with red squigglies and no go-to-definition for mapped paths. I'll try to get a minimum-reproducible repo up, but for now the two things that we're doing that might be unexpected are:

  1. mapped path starts with an @ character
  2. paths is set in a base tsconfig, while baseUrl is set in a child tsconfig (one that inherits from the base tsconfig

@zealitude
Copy link

zealitude commented Mar 20, 2017

I am using Angular CLI
it divided the tsconfig into /tsconfig.json and /src/tsconfig.app.json
however, I found that vscode only able to read the first one, /tsconfig.json only and ignore the later

my workaround solution:

/tsconfig.json

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

/src/tsconfig.app.json

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

note: restart vs code is need

@OliverJAsh
Copy link
Contributor

https://code.visualstudio.com/docs/languages/jsconfig (paths is not listed as available option)

As @marianban pointed out, this feature is not documented. I've raised a PR to fix this at microsoft/vscode-docs#942.

@lifehackett
Copy link

This is still causing me issues. I've run through the various suggestions in this list, but can't figure out why it isn't working.

VSCode: 1.12.2
Typescript: 2.3.2

jsconfig.json

{
  "compilerOptions": {
    "checkJs": true,
    "target": "ES6",
    "baseUrl": "src/"
  },
  "exclude": [
    "node_modules",
    "lib",
    ".tmp",
    "build"
  ]
}

TypeScript definition file
screen shot 2017-06-01 at 3 33 38 pm

Relevant Portion of the Directory
screen shot 2017-06-01 at 3 34 09 pm

@mhegazy
Copy link

mhegazy commented Jun 1, 2017

set "moduleResolution": "node".

@lifehackett
Copy link

lifehackett commented Jun 1, 2017

Thank you! That got rid of the red squiggly and error, but I'm still not getting intellisense.

UPDATE
So, I get intellisense if I import path/to/dir/index.js, but if I just do path/to/dir which in node will give you the file index.js by default, I do not get intellisense.

@mhegazy
Copy link

mhegazy commented Jun 1, 2017

can you share a repro project?

@maitriyogin
Copy link

maitriyogin commented Jun 7, 2017

Hi,
I'm trying to fix this in my project which has no Typescript deps but is just ES6.
My web pack moduleDirectories is setup like this
modulesDirectories: ['node_modules', 'src']
I'v amended this to my jsconfig.json

"compilerOptions": {
        "target": "ES6",
        "moduleResolution": "node",
        "baseUrl": "./src"
    }

When I try and cmd click on say removeProps

import {removeProps} from "utils/thing_type_utils";

I'm not able to jump to that function.
Works fine with full path imports ...
Any ideas?
/Stephen.

@mhegazy
Copy link

mhegazy commented Jun 7, 2017

can you share a repro project?

@maitriyogin
Copy link

maitriyogin commented Jun 7, 2017 via email

@mhegazy
Copy link

mhegazy commented Jun 7, 2017

yup.
animation

@maitriyogin
Copy link

maitriyogin commented Jun 7, 2017 via email

@vvatikiotis
Copy link

@maitriyogin found anything? Seems I'm on the same boat as you. Module resolution as been working on and off for me, for the past year or so.

@rw3iss
Copy link

rw3iss commented Aug 1, 2017

FYI, to get webpack 3 to compile relative modules that are declared in tsconfig/jsconfig.json 'paths' property, you have to also add them to webpack config's 'resolve.modules' property, ie:

tsconfig.json:

"baseUrl": "./app",
"paths": {
    "~/*": ["./*"],
    "components/*": ["components/*"],
    "lib/*": ["lib/*"],
    "models/*": ["models/*"]
}

webpack.config.js:

resolve: {
    modules: [ 'node_modules', 'app', 'app/models', 'app/components', 'app/lib' ]
}

Hope it helps someone!

@tsmirnov
Copy link

tsmirnov commented Aug 9, 2017

@mhegazy setting moduleResolution works for me, but now I have the warning:

Property moduleResolution is not allowed

You have that warning on demo screenshot too. Is there any way to avoid the warning message?

@amritk
Copy link

amritk commented Aug 9, 2017

Having issues with this as well, it compiles fine in webpack, but I get the annoying red underline in vscode.
screenshot from 2017-08-09 13-40-00

tsconfig.json

{
    "compileOnSave": false,
    "compilerOptions": {
        "allowSyntheticDefaultImports": true,
        "lib": [
            "dom",
            "es2015",
            "es2016",
            "es6",
            "es2017"
        ],
        "target": "es2017",
        "module": "es6",
        "moduleResolution": "node",
        "noImplicitAny": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "removeComments": false,
        "baseUrl": ".",
        "paths": {
            "@base": ["."],
            "@community": ["src/vue/community"],
            "@components": ["src/vue/components"],
            "@src": ["src"],
            "@vue": ["src/vue"]
        },
        "preserveConstEnums": true,
        "sourceMap": true,
        "skipLibCheck": true
    }
}

webpack.base.conf.js

    resolve: {
        extensions: ['.ts', '.js', '.vue', '.json'],
        alias: {
            '@base': resolve('.'),
            '@community': resolve('src/vue/community'),
            '@components': resolve('src/vue/components'),
            '@src': resolve('src'),
            '@vue': resolve('src/vue')
        }
    },

@rw3iss
Copy link

rw3iss commented Aug 9, 2017 via email

@amritk
Copy link

amritk commented Aug 9, 2017

@rw3iss would the webpack config affect vscode? I thought vscode was resolving the paths from tsconfig.json

My webpack is working properly, its just vscode that can't seem to find the modules

@rw3iss
Copy link

rw3iss commented Aug 9, 2017 via email

@amritk
Copy link

amritk commented Aug 9, 2017

@rw3iss hey thanks for your help! turns out VSCode doesn't like them starting with an '@' symbol.

@rw3iss
Copy link

rw3iss commented Aug 9, 2017 via email

@yoyo-real
Copy link

I'm using Inseider. Intellisense did not work in the React project.
I tried variously, if the extension is jsx,jsx: "react"is mandatory.

jsconfig.json OK

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

jsconfig.json NG

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

@gengxuelei
Copy link

it's not ok in html,there is a snippets:

<script src="/static/jquery.js"></script>

but in fact the file is in '/www/static/jquery.js'.
when I press 'Ctrl' and click this path it tips:'file not found'

@wesleymostien
Copy link

wesleymostien commented Oct 12, 2017

Can't get this to work, please help. Intellisense is still not working.

screen shot 2017-10-12 at 18 38 36

Inside index.ts I already get folder completion ('src/components'), but no .vue file completion :

screen shot 2017-10-12 at 18 33 39

Inside 'Hello.vue', there's no Intellisense whatsoever :

screen shot 2017-10-12 at 18 36 14

tsconfig.json :

"compilerOptions": {
"target": "es2015",
"lib": ["dom", "es2015", "es2017"],
"module": "es6",
"moduleResolution": "node",
"experimentalDecorators": true,
"strictNullChecks": true,
"removeComments": true,
"suppressImplicitAnyIndexErrors": true,
"allowSyntheticDefaultImports": true,
"allowJs": true,
"sourceMap": true,
"outDir": "./dist/",
"baseUrl": "./src",
"paths": {
"components/": ["components/"]
}
},
"include": ["./src/ * * / *"],
"exclude": ["./node_modules/ * * / *"]

@c01nd01r
Copy link

jsconfig.json for vue-cli webpack template:

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

jsconfig.json located in the root of project

@mjbvz
Copy link
Contributor

mjbvz commented Oct 13, 2017

If you are running into problems related to import paths, please try asking on stackoverflow or posting a new issue

@microsoft microsoft locked and limited conversation to collaborators Oct 13, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature-request Request for new features or functionality javascript JavaScript support issues
Projects
None yet
Development

No branches or pull requests