-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Intellisense not resolving modules when using exports
in package.json
#56412
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
Comments
We need an actual repro. Also, please post code, not screenshots of code. |
I finally got Intellisense to work and respect the Here is a working repo: https://github.com/magnusriga/my-turborepo Leaving my config below in case it is helpful to anyone else. The below is slightly different to the repo above, it uses a Package B's package.json (note the {
"name": "@acme/ui",
"version": "3.0.1",
"private": true,
"sideEffects": [
"**/*.css"
],
"exports": {
".": {
"types": "./types/index.d.ts",
"import": "./dist/index.js"
},
"./*": {
"types": "./types/*.js",
"import": "./dist/*.js"
}
},
"scripts": {
"build": "rimraf dist && tsc -p",
"clean": "rm -rf dist",
"dev": "rimraf dist types .Cache && tsc --watch",
"lint": "eslint src/",
"test": "jest",
"check-types": "tsc --noEmit"
},
"jest": {
"preset": "jest-presets/jest/browser"
},
"devDependencies": {
"@babel/preset-react": "latest",
"@types/react": "latest",
"@types/react-dom": "latest",
"@types/styled-components": "latest",
"autoprefixer": "latest",
"eslint-config-custom": "workspace:*",
"fs-extra": "latest",
"rimraf": "latest",
"postcss": "latest",
"react": "latest",
"tailwind-config": "workspace:*",
"tailwindcss": "latest",
"tsconfig": "workspace:*",
"typescript": "latest",
"watch": "latest"
},
"peerDependencies": {
"react": "latest",
"styled-components": "latest"
}
} Package A's import // Intellisense shows only the exported packages when writing the RHS path, which was my goal here
import { Button } from '@acme/ui/components/button'; Package B's {
"extends": "tsconfig/react-library.json",
"compilerOptions": {
"allowJs": true,
"declaration": true,
"noEmit": false,
"noEmitOnError": true,
"incremental": true,
"outDir": "dist",
"declarationDir": "types",
"tsBuildInfoFile": ".Cache/tsc.buildinfo.json",
"rootDir": "src",
"sourceMap": true,
"inlineSources": true,
"sourceRoot": "src",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["src/components/*"],
"@utils/*": ["src/utils/*"],
"@lib/*": ["src/lib/*"],
"@styles/*": ["src/styles/*"],
"@ui/*": ["src/ui/*"],
"@context/*": ["src/context/*"],
"@templates/*": ["src/templates/*"],
"@public/*": ["public/*"]
}
},
"include": ["./src"],
"exclude": [
"dist",
"build",
".Cache",
"types",
"node_modules",
"cypress",
"test",
"**/__tests__/*",
"jest.setup.tsx"
]
} {
"$schema": "https://json.schemastore.org/tsconfig",
"display": "React Library",
"extends": "./base.json",
"compilerOptions": {
"jsx": "react-jsx",
}
} {
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Default",
"compilerOptions": {
"esModuleInterop": true,
"skipLibCheck": true,
"target": "es2022",
"resolveJsonModule": true,
"isolatedModules": true,
"moduleDetection": "force",
"strict": true,
"noUncheckedIndexedAccess": true,
"moduleResolution": "Bundler",
"module": "ESNext",
"noEmit": true,
"lib": ["es2022", "dom", "dom.iterable"],
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"preserveWatchOutput": true
},
"exclude": ["node_modules"]
} |
@magnusriga can you please provide instructions on how to reproduce the problem in the context of the repo you shared? |
@andrewbranch I actually got it to work. I posted a working repo above to showcase the settings needed to make it work (in case it is useful to others in the future). @mjbvz can mark it as resolved (I am unable to, since I am no longer the OP). |
Hey folks, can this be reopened please? Here is a bare-minimum example: https://github.com/virtuallyunknown/esm-exports-no-intellisense To reproduce:
The problem can be observed in packages/two/test.js where there is no Intellisense. Why? Because the package we're exporting from - Adding a {
"name": "@repo/one",
"version": "1.0.0",
"author": "me",
"type": "module",
+ "main": "./src/index.js",
"exports": {
".": {
"import": "./src/index.js"
}
}
} Also, apologies if this is not the correct place to ask. My reason to ask here is because I saw this was redirected from the VSCode repo. |
@virtuallyunknown this is a known issue regarding the default settings that VS Code passes to TS Server (which powers JavaScript IntelliSense). The current defaults are very forgiving, which is good because we don’t know what kind of project a JS user has without additional config, but they lack support for newer features like package.json {
"compilerOptions": {
"module": "nodenext"
}
} |
@andrewbranch thanks for taking your time to explain the issue to me, I really appreciate it. I have tried the In my personal opinion it's important that developers can make use of all ESM features so we can finally move away from CJS and all start using one unified system, but I also understand you guys probably have more pressing issues that require your attention. Cheers! |
Hey @andrewbranch sorry to bother you again, but I have a follow-up question. In my demo (mono)repository we export some files from You can see the basic project overview here, and I updated my demo repository as well with a reproducible example, where the same problem as before arises if
So I guess my question is if there is a similar workaround for this particular problem? One might think to themselves that this is quite a weird setup to have, but my use case is that I put build scripts in the root of each sub-project (where test.js currently is), and my typescript files reside in the src directory. If all of this is taking too much of your time then no worries, I will work with what I currently have, cheers. |
What’s happening here is the presence of the I think the most conventional workaround would be to put your scripts in their own directory with their own tsconfig.json/jsconfig.json. Alternatively, you could name your package-level tsconfigs something else (tsconfig.src.json) and reference them from a root-level solution tsconfig.json: {
"files": [],
"references": [
{ "path": "./packages/two/tsconfig.src.json" },
{ "path": "./tsconfig.scripts.json" }
]
} The trick is to make it so that the nearest file named literally |
@andrewbranch Thanks for the awesome support here. I made a change to my repo and now have issues again. If you have time, could you check out my last comment in this PR: vercel/turborepo#6575 Long story short, Turbo's example is a monorepo with, among others, a next.js package and a Also, I got it to work if I used a conditional export, any idea why that is? I.e. what is the difference between these: Works: "./*": {
"import": "./src/*.tsx"
} Does not work: "./*": "./src/*.tsx" Lastly, is there a way for IntelliSense to support both TS and JS files? These did not work: 1) "./*.tsx": {
"import": "./src/*.tsx"
},
"./*.js": {
"import": "./src/*.js"
} 2) "./*": {
"import": "./src/*"
} |
That sounds like a bug. Can you provide a specific repro?
It’s hard to tell exactly what the intent is here without a repro, but something that seems relevant is file extension substitution. Any time TS sees a request to resolve a file ending in |
I have actually tried manually including the {
"extends": ["@repo/tsconfig/tsconfig.node.json"],
"include": ["./src/", "./test.js"],
"exclude": ["**/node_modules", "**/.*/"]
} Another thing I tested just now is having both jsconfigs and tsconfigs next to one another in a package-level directory, but to no avail either (probably because tsconfig takes precedence as you suggested). The explanation you provided makes sense of what is happening, and one of the workarounds of having the scripts in their own directory with a dedicated I think at this point the best/most sane way to move forward is to keep an So yeah, I think I am leaving it like that for the moment, and thanks again for being so helpful, I also learned a thing or two about the way this works which can be useful knowledge in the future :) |
Probably need to add |
I just tested and unfortunately it doesn't do anything in terms of intellisense.
And if
|
Hi @andrewbranch . Please find the repo here: https://github.com/magnusriga/turbo-tailwind.git First issue IntelliSense works for Second issue I actually got both these to work now: Works: "./*": {
"import": "./src/*.tsx"
} Also works: "./*": "./src/*.tsx" However, this does not work to export both my js and ts: "./*": "./src/*" Any idea how to achieve the latter (exporting both the TS and JS)? |
For whatever it is worth @virtuallyunknown : I also had the issue with the "missing declaration files" ESlint error when importing a JS file, and got it to go away by adding this to my tsconfig: |
Can you be more specific about how to repro and what your expected and actual behavior is? This is a big repo with many files, and both “IntelliSense” and “works” are loaded terms 😁 |
Hey man, don't get me wrong, I appreciate your help, but I wouldn't actually suggest disabling Of course this is just my opinion and maybe you have a better use case than I do, but for me this would weaken the type system which I'm not a fan of. |
@virtuallyunknown What you say makes complete sense, but I couldn't find any other good way to remove that ESLint error you mentioned, which I got when importing a JS file into a TS file. Obviously the JS file does not have type declarations in the first place, so ideally it should not check that file when it sees that it is JS and not TS. Other suboptimal ways the remove the error included changing |
Yes, sorry. Just open the repo I linked in your vscode, then follow these steps:
|
@magnusriga the ![]() |
Legend @andrewbranch , thank you so much. Re. my second question above, is it possible to export both JS and TS files with a wild card export, and still be able to see the IntelliSense suggestions when importing? |
@andrewbranch I got the drop-down suggestions to work, following your suggestions. Thank you so much. What does not work is ctrl-clicking on the right-hand-side of the import (the path) or on the left-hand-side (the module name). It just states:
Screenshots: Do you get the same issue on the repo I shared? Side question, if you have time: How come the |
The TS bug is that the path completions suggested
TypeScript doesn't know anything about the boundaries of these "packages," because you haven't set up project references. Each package here has its own independent TS project that contains all files you reference, compiled under the single tsconfig for that package. The tsconfigs in other packages are completely independent and never even discovered by the TS project you're editing.
Probably what you were seeing here is that imports in the |
Got it @andrewbranch . So, there is no way to change the In other words, I only have two options, either state the file extension in the OPTION 1 // Package one
import { Card } from '@repo/ui/card.tsx'; // Package two
"exports": { "./*": "./src/*" } OPTION 2 // Package one
import { Card } from '@repo/ui/card'; // Package two
"exports": { "./card": "./src/card.tsx" } Is it correct that I am limited to these two? If so, which one is better practice? PS: If it matters, my modules do not need to support CommonJS, only ES. Thanks! |
That's correct, at least according to the |
@andrewbranch One other thing I noticed which may also be a bug: In words, the left-hand-side Intellisense does not work when importing a js file. I.e. the exported function Bar does not show up as a suggestion. EDIT: Subpaths in "exports": {
"./foo/bar": "./src/bar.js",
} |
This is working as intended. JavaScript files imported from
This appears to be a bug. |
Is there any way to make that work like it does for internal packages, @andrewbranch ? Internal package example with JS import: PS: The package is indeed from node_modules, but it is our own internally defined package (from within the monorepo). |
Yes, I'll try that out and see if there are any objections. |
Not sure if I misunderstood you @andrewbranch . Did you know of a way to make the left hand side of the import statements work with IntelliSense, when importing a JS file from node_modules (which in reality is from our own monorepo)? If so, how do I do it? Thanks! |
Update to TypeScript 5.4 when it comes out. #56946 |
@andrewbranch Quick and somewhat related question, that might or might not be a bug: In node it is possible to self-reference a package. So, using the repo in this thread, TS and JS modules in The problem I am facing is that I am not getting any autocomplete for my own package when typing the right-hand-side of the import above. Specifically, ctrl+space at Since node supports self-referencing, it would be great if Intellisense did too. PS: Quick side-question that is also related. The @-rules in tsconfig's |
Reposting from VSCode repo for @magnusriga. I transferred the original issue to the wrong repo and now can't transfer it back
Does this issue occur when all extensions are disabled?: Yes
Steps to Reproduce:
exports
fieldmain
andtypes
fields and see that Intellisense starts working againIntellisense Works When
main
andtypes
are set:Package B's
package.json
Package A's
import
(notice the Intellisense pop-up. It is possible to ctrl-click the path.)Intellisense Does Not Work When only
exports
is set:Package B's
package.json
(removedmain
andtypes
)Package A's
import
(not possible to crl+click to find the package, i.e. no Intellisense)The text was updated successfully, but these errors were encountered: