VS Code: “Cannot find module” from root path The Next CEO of Stack OverflowHow do I hide certain files from the sidebar in Visual Studio Code?Gulp sourcemaps with TypeScript and BabelImporting lodash into angular2 + typescript applicationTypescript compiler cannot find locally installed npm moduleAngular 2 TypeScript ErrorsPaths property in tsconfig doesn't workWebpack + React + TypeScript: Module not found … in … node_modules/react/Typescript does not resolve definition file for npm packageVSCode typescript importing json file highlighting issueVisual Studio Code not finding any TS or node packages
What do "high sea" and "carry" mean in this sentence?
WOW air has ceased operation, can I get my tickets refunded?
If I blow insulation everywhere in my attic except the door trap, will heat escape through it?
Unreliable Magic - Is it worth it?
I believe this to be a fraud - hired, then asked to cash check and send cash as Bitcoin
Why Were Madagascar and New Zealand Discovered So Late?
Science fiction novels about a solar system spanning civilisation where people change their bodies at will
Can the Reverse Gravity spell affect the Meteor Swarm spell?
Would this house-rule that treats advantage as a +1 to the roll instead (and disadvantage as -1) and allows them to stack be balanced?
What makes a siege story/plot interesting?
Is a stroke of luck acceptable after a series of unfavorable events?
Why didn't Theresa May consult with Parliament before negotiating a deal with the EU?
Term for the "extreme-extension" version of a straw man fallacy?
What's the point of interval inversion?
Trouble understanding the speech of overseas colleagues
Only print output after finding pattern
Rotate a column
Can a single photon have an energy density?
How do we know the LHC results are robust?
What is the purpose of the Evocation wizard's Potent Cantrip feature?
Why do remote companies require working in the US?
Fastest way to shutdown Ubuntu Mate 18.10
Anatomically Correct Strange Women In Ponds Distributing Swords
Inappropriate reference requests from Journal reviewers
VS Code: “Cannot find module” from root path
The Next CEO of Stack OverflowHow do I hide certain files from the sidebar in Visual Studio Code?Gulp sourcemaps with TypeScript and BabelImporting lodash into angular2 + typescript applicationTypescript compiler cannot find locally installed npm moduleAngular 2 TypeScript ErrorsPaths property in tsconfig doesn't workWebpack + React + TypeScript: Module not found … in … node_modules/react/Typescript does not resolve definition file for npm packageVSCode typescript importing json file highlighting issueVisual Studio Code not finding any TS or node packages
I cannot seem to solve a module import issue with Visual Studio Code:

I've a setup a sample repo to illustrate this problem, with a directory structure like this:
➜ tree -I node_modules
.
├── README.md
├── packages
│ ├── jsx
│ │ └── jsx.jsx
│ ├── tjs
│ │ └── tjs.js
│ ├── tscript
│ │ └── tscript.js
│ └── tsx
│ └── tsx.tsx
├── src
│ ├── entry.ts
│ └── localjs.js
└── tsconfig.json
I'd like to have this setup work with babel-typescript, but my investigation indicates that the problem seems to be intrinsic to VSCode, so I've left it out of the sample.
I've tried all the permutations of the paths for tsconfig.json that I've seen i.e.
"paths":
"*": [
"*",
"packages/*",
"packages/*/index.tsx",
"packages/*/index.jsx",
"packages/*/index.js"
],
"$1": [
"packages/$1/$1"
],
"~/*": [
"packages/*"
],
"~/$1": [
"packages/$1/$1"
],
"*/$1": [
"*/$1/$1",
"packages/$1/$1",
"*/packages/$1/$1"
]
The handbook doesn't offer much insight.
typescript visual-studio-code
add a comment |
I cannot seem to solve a module import issue with Visual Studio Code:

I've a setup a sample repo to illustrate this problem, with a directory structure like this:
➜ tree -I node_modules
.
├── README.md
├── packages
│ ├── jsx
│ │ └── jsx.jsx
│ ├── tjs
│ │ └── tjs.js
│ ├── tscript
│ │ └── tscript.js
│ └── tsx
│ └── tsx.tsx
├── src
│ ├── entry.ts
│ └── localjs.js
└── tsconfig.json
I'd like to have this setup work with babel-typescript, but my investigation indicates that the problem seems to be intrinsic to VSCode, so I've left it out of the sample.
I've tried all the permutations of the paths for tsconfig.json that I've seen i.e.
"paths":
"*": [
"*",
"packages/*",
"packages/*/index.tsx",
"packages/*/index.jsx",
"packages/*/index.js"
],
"$1": [
"packages/$1/$1"
],
"~/*": [
"packages/*"
],
"~/$1": [
"packages/$1/$1"
],
"*/$1": [
"*/$1/$1",
"packages/$1/$1",
"*/packages/$1/$1"
]
The handbook doesn't offer much insight.
typescript visual-studio-code
add a comment |
I cannot seem to solve a module import issue with Visual Studio Code:

I've a setup a sample repo to illustrate this problem, with a directory structure like this:
➜ tree -I node_modules
.
├── README.md
├── packages
│ ├── jsx
│ │ └── jsx.jsx
│ ├── tjs
│ │ └── tjs.js
│ ├── tscript
│ │ └── tscript.js
│ └── tsx
│ └── tsx.tsx
├── src
│ ├── entry.ts
│ └── localjs.js
└── tsconfig.json
I'd like to have this setup work with babel-typescript, but my investigation indicates that the problem seems to be intrinsic to VSCode, so I've left it out of the sample.
I've tried all the permutations of the paths for tsconfig.json that I've seen i.e.
"paths":
"*": [
"*",
"packages/*",
"packages/*/index.tsx",
"packages/*/index.jsx",
"packages/*/index.js"
],
"$1": [
"packages/$1/$1"
],
"~/*": [
"packages/*"
],
"~/$1": [
"packages/$1/$1"
],
"*/$1": [
"*/$1/$1",
"packages/$1/$1",
"*/packages/$1/$1"
]
The handbook doesn't offer much insight.
typescript visual-studio-code
I cannot seem to solve a module import issue with Visual Studio Code:

I've a setup a sample repo to illustrate this problem, with a directory structure like this:
➜ tree -I node_modules
.
├── README.md
├── packages
│ ├── jsx
│ │ └── jsx.jsx
│ ├── tjs
│ │ └── tjs.js
│ ├── tscript
│ │ └── tscript.js
│ └── tsx
│ └── tsx.tsx
├── src
│ ├── entry.ts
│ └── localjs.js
└── tsconfig.json
I'd like to have this setup work with babel-typescript, but my investigation indicates that the problem seems to be intrinsic to VSCode, so I've left it out of the sample.
I've tried all the permutations of the paths for tsconfig.json that I've seen i.e.
"paths":
"*": [
"*",
"packages/*",
"packages/*/index.tsx",
"packages/*/index.jsx",
"packages/*/index.js"
],
"$1": [
"packages/$1/$1"
],
"~/*": [
"packages/*"
],
"~/$1": [
"packages/$1/$1"
],
"*/$1": [
"*/$1/$1",
"packages/$1/$1",
"*/packages/$1/$1"
]
The handbook doesn't offer much insight.
typescript visual-studio-code
typescript visual-studio-code
asked Mar 8 at 12:47
Brian M. HuntBrian M. Hunt
36.6k59177298
36.6k59177298
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
You already got an answer from Wex suggesting that you rename your files to have the basename index plus the appropriate extension and use the mapping "*"*: ["*", "packages/*"]. You mentioned in a comment that you'd rather avoid renaming the files. Besides avoiding renames, I'm not a fan of having a lot of files be named index.<some_extension>. When working, my eyes are naturally drawn to the basename of the files I'm working on or getting reports about. Having to distinguish files that have near-identical basenames by directory is possible but requires more cognitive work on my part to look away from the basename and at the path, or more work at the keyboard for completion. (It takes longer to type. There's only so much help the IDE can provide.) It is enough to be annoying.
First, let's deal with the dead ends. I see no evidence that ~ and $1 are treated specially in paths. I went to check tsc's code and see nothing there that handles such patterns. It could be that I missed it, but I think they are just not special. Also, ignoring extensions for the moment, your desired mapping is something packages/<package_name>/<package_name>.ext The package name appears twice. So it would be tempting to set a mapping like "*": ["packages/*/*.ext"] but that's explicitly not allowed by TypesScript: tsc will give you an error about the two asterisks appearing in the desired mapping. So that's not an option either.
Use package.json
You could dodge the renaming issue by adding a package.json to each package with a "main" field that points to the file you want to be considered the entry point of your package. For instance, packages/jsx/package.json could contain this:
"main": "jsx.jsx"
By providing similar files for all other packages, you can reduce the relevant configuration to:
"baseUrl": "",
"paths":
"*": ["packages/*", "*"]
,
Or you can use "baseUrl" to point to your packages and omit "paths" entirely:
"baseUrl": "packages/",
Make sure that you lint the package.json files because tsc will simply ignore them silently if there's any syntactic mistake in these files.
Add index Files that Reexport your Entry Module
Another method would be to use index files that simply reexport all of the file you'd otherwise want to be the entry point of your package. The files you currently have would remain there but would be referenced by appropriately designed index files. For instance, packages/tsx/index.ts could be:
export default from "./tsx";
If all your packages just provide a default export, they could all follow the pattern above. Otherwise, if a package exports multiple symbols and just want to reexport everything, you can do:
export * from "./myModule";
If you do this for all your packages, you don't need to rename anything but you'd have additional index files to satisfy the "*": ["*", "packages/*"] mapping.
In a comment, you mentioned using a tool like Barrelsby to generate index files. I'd be concerned about the impact on development. I can see generating an index file acting as a facade as part of publishing your project. So people consuming the published project deal with a file generated by Barrelsby or some other tool. However, your index files appear to me to be internal to your project. So in order to get proper IDE support while developing the index files will have to already exist before contributors start contributing. So contributors would have to run something that generates the index files before they start contributing. You would also have generated files that live side by side with files that are authored directly by developers. I try to avoid this in my projects.
If it were my project and I decided to add index files to satisfy the tsconfig.json mapping, I'd aim to structure my project so that the index files boil down to one of the two cases above, and skip using a code generator. (Actually, I'd aim for the 2nd of the two cases above, because I prefer to avoid default exports. See here for a discussion of the issues with default exports.)
Individually Map The Packages
If the other solutions are problematic for your specific project, you can provide one mapping per package:
"paths":
"jsx": ["packages/jsx/jsx.jsx"],
"tjs": ["packages/tjs/tjs.js"],
"tscript": ["packages/tscript/tscript.js"],
"tsx": ["packages/tsx/tsx.tsx"],
,
This means adding a mapping each time you add a new package. Whether or not this is viable depends on your specific project. You could also use a baseUrl set to "packages/" and remove packages/ from all the paths above:
"baseUrl": "packages/",
"paths":
"jsx": ["jsx/jsx.jsx"],
"tjs": ["tjs/tjs.js"],
"tscript": ["tscript/tscript.js"],
"tsx": ["tsx/tsx.tsx"],
,
This makes the whole thing less verbose though you still have to provide one mapping per package.
Thank you very much, @Louis. Editing the tsconfig for each module would be madness (we add/remove/edit 2-3 a week, we'd be clobbering git commits routinely, and our tsconfig would be thousands of lines long). So that's not very practical. However I stumbled across a plugin — module-plugin-d-ts? Do you think this or perhaps another TS plugin might assist in solving this problem?
– Brian M. Hunt
Mar 10 at 16:23
Sounds like you've got a special case. I don't seemodule-plugin.d.tsas pertaining to your problem. It illustrates how you can augment a module. For instance, when you load a jQuery plugin, jQuery itself gains new methods. e.g If you load Bootstrap, then jQuery gets$().modal,$().dropdown, ... which are not on the stock jQuery. It is puzzling at first to figure how to declare the interface for such a plugin. Search for "module plugin" on this page for the context tomodule-plugin.d.ts.
– Louis
Mar 10 at 16:56
1
@BrianM.Hunt Comments are too small to respond to your Barrelsby idea, so I've added a new section to my answer.
– Louis
Mar 10 at 20:31
1
I actually tried puttingpackage.jsoninto thepackages/*/subdirectories... but it did not work. I still have that trial on disk, so I went back to it just now and looked again. Sigh I had an errant trailing comma in the JSON, which causedtscto silently pretend that thepackage.jsonis absent. Once I removed the comma, it worked. If I had not made that mistake, I would have mentioned it in the first place. I'm going to edit my answer to include that possibility.
– Louis
Mar 13 at 17:46
1
And thanks for the bounty!
– Louis
Mar 13 at 17:48
|
show 4 more comments
Part of the issue with your current tsconfig.json is that you are using include: [], so no code will actually be matched by your config!
I couldn't find any examples of using the $1 pattern the way you have it in your sample config, nor do I think what you are trying to do is possible based on some research (see also: #5039). Are you able to rename package/package.jsx to package/index.jsx? Then your paths config could trivially be changed to:
"paths":
"*": ["*", "packages/*"]
,
Thanks @wex. I copied the$1code from a comment on #24116, though that's it. That's a great link to #5039, I'll dig into it more. Thanks for the suggestion to rename packages topackage/index.js. It'd involve a huge number lot of file changes, so we'd prefer to avoid it, but it's good to know it's a backstop.
– Brian M. Hunt
Mar 9 at 1:42
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55063550%2fvs-code-cannot-find-module-from-root-path%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
You already got an answer from Wex suggesting that you rename your files to have the basename index plus the appropriate extension and use the mapping "*"*: ["*", "packages/*"]. You mentioned in a comment that you'd rather avoid renaming the files. Besides avoiding renames, I'm not a fan of having a lot of files be named index.<some_extension>. When working, my eyes are naturally drawn to the basename of the files I'm working on or getting reports about. Having to distinguish files that have near-identical basenames by directory is possible but requires more cognitive work on my part to look away from the basename and at the path, or more work at the keyboard for completion. (It takes longer to type. There's only so much help the IDE can provide.) It is enough to be annoying.
First, let's deal with the dead ends. I see no evidence that ~ and $1 are treated specially in paths. I went to check tsc's code and see nothing there that handles such patterns. It could be that I missed it, but I think they are just not special. Also, ignoring extensions for the moment, your desired mapping is something packages/<package_name>/<package_name>.ext The package name appears twice. So it would be tempting to set a mapping like "*": ["packages/*/*.ext"] but that's explicitly not allowed by TypesScript: tsc will give you an error about the two asterisks appearing in the desired mapping. So that's not an option either.
Use package.json
You could dodge the renaming issue by adding a package.json to each package with a "main" field that points to the file you want to be considered the entry point of your package. For instance, packages/jsx/package.json could contain this:
"main": "jsx.jsx"
By providing similar files for all other packages, you can reduce the relevant configuration to:
"baseUrl": "",
"paths":
"*": ["packages/*", "*"]
,
Or you can use "baseUrl" to point to your packages and omit "paths" entirely:
"baseUrl": "packages/",
Make sure that you lint the package.json files because tsc will simply ignore them silently if there's any syntactic mistake in these files.
Add index Files that Reexport your Entry Module
Another method would be to use index files that simply reexport all of the file you'd otherwise want to be the entry point of your package. The files you currently have would remain there but would be referenced by appropriately designed index files. For instance, packages/tsx/index.ts could be:
export default from "./tsx";
If all your packages just provide a default export, they could all follow the pattern above. Otherwise, if a package exports multiple symbols and just want to reexport everything, you can do:
export * from "./myModule";
If you do this for all your packages, you don't need to rename anything but you'd have additional index files to satisfy the "*": ["*", "packages/*"] mapping.
In a comment, you mentioned using a tool like Barrelsby to generate index files. I'd be concerned about the impact on development. I can see generating an index file acting as a facade as part of publishing your project. So people consuming the published project deal with a file generated by Barrelsby or some other tool. However, your index files appear to me to be internal to your project. So in order to get proper IDE support while developing the index files will have to already exist before contributors start contributing. So contributors would have to run something that generates the index files before they start contributing. You would also have generated files that live side by side with files that are authored directly by developers. I try to avoid this in my projects.
If it were my project and I decided to add index files to satisfy the tsconfig.json mapping, I'd aim to structure my project so that the index files boil down to one of the two cases above, and skip using a code generator. (Actually, I'd aim for the 2nd of the two cases above, because I prefer to avoid default exports. See here for a discussion of the issues with default exports.)
Individually Map The Packages
If the other solutions are problematic for your specific project, you can provide one mapping per package:
"paths":
"jsx": ["packages/jsx/jsx.jsx"],
"tjs": ["packages/tjs/tjs.js"],
"tscript": ["packages/tscript/tscript.js"],
"tsx": ["packages/tsx/tsx.tsx"],
,
This means adding a mapping each time you add a new package. Whether or not this is viable depends on your specific project. You could also use a baseUrl set to "packages/" and remove packages/ from all the paths above:
"baseUrl": "packages/",
"paths":
"jsx": ["jsx/jsx.jsx"],
"tjs": ["tjs/tjs.js"],
"tscript": ["tscript/tscript.js"],
"tsx": ["tsx/tsx.tsx"],
,
This makes the whole thing less verbose though you still have to provide one mapping per package.
Thank you very much, @Louis. Editing the tsconfig for each module would be madness (we add/remove/edit 2-3 a week, we'd be clobbering git commits routinely, and our tsconfig would be thousands of lines long). So that's not very practical. However I stumbled across a plugin — module-plugin-d-ts? Do you think this or perhaps another TS plugin might assist in solving this problem?
– Brian M. Hunt
Mar 10 at 16:23
Sounds like you've got a special case. I don't seemodule-plugin.d.tsas pertaining to your problem. It illustrates how you can augment a module. For instance, when you load a jQuery plugin, jQuery itself gains new methods. e.g If you load Bootstrap, then jQuery gets$().modal,$().dropdown, ... which are not on the stock jQuery. It is puzzling at first to figure how to declare the interface for such a plugin. Search for "module plugin" on this page for the context tomodule-plugin.d.ts.
– Louis
Mar 10 at 16:56
1
@BrianM.Hunt Comments are too small to respond to your Barrelsby idea, so I've added a new section to my answer.
– Louis
Mar 10 at 20:31
1
I actually tried puttingpackage.jsoninto thepackages/*/subdirectories... but it did not work. I still have that trial on disk, so I went back to it just now and looked again. Sigh I had an errant trailing comma in the JSON, which causedtscto silently pretend that thepackage.jsonis absent. Once I removed the comma, it worked. If I had not made that mistake, I would have mentioned it in the first place. I'm going to edit my answer to include that possibility.
– Louis
Mar 13 at 17:46
1
And thanks for the bounty!
– Louis
Mar 13 at 17:48
|
show 4 more comments
You already got an answer from Wex suggesting that you rename your files to have the basename index plus the appropriate extension and use the mapping "*"*: ["*", "packages/*"]. You mentioned in a comment that you'd rather avoid renaming the files. Besides avoiding renames, I'm not a fan of having a lot of files be named index.<some_extension>. When working, my eyes are naturally drawn to the basename of the files I'm working on or getting reports about. Having to distinguish files that have near-identical basenames by directory is possible but requires more cognitive work on my part to look away from the basename and at the path, or more work at the keyboard for completion. (It takes longer to type. There's only so much help the IDE can provide.) It is enough to be annoying.
First, let's deal with the dead ends. I see no evidence that ~ and $1 are treated specially in paths. I went to check tsc's code and see nothing there that handles such patterns. It could be that I missed it, but I think they are just not special. Also, ignoring extensions for the moment, your desired mapping is something packages/<package_name>/<package_name>.ext The package name appears twice. So it would be tempting to set a mapping like "*": ["packages/*/*.ext"] but that's explicitly not allowed by TypesScript: tsc will give you an error about the two asterisks appearing in the desired mapping. So that's not an option either.
Use package.json
You could dodge the renaming issue by adding a package.json to each package with a "main" field that points to the file you want to be considered the entry point of your package. For instance, packages/jsx/package.json could contain this:
"main": "jsx.jsx"
By providing similar files for all other packages, you can reduce the relevant configuration to:
"baseUrl": "",
"paths":
"*": ["packages/*", "*"]
,
Or you can use "baseUrl" to point to your packages and omit "paths" entirely:
"baseUrl": "packages/",
Make sure that you lint the package.json files because tsc will simply ignore them silently if there's any syntactic mistake in these files.
Add index Files that Reexport your Entry Module
Another method would be to use index files that simply reexport all of the file you'd otherwise want to be the entry point of your package. The files you currently have would remain there but would be referenced by appropriately designed index files. For instance, packages/tsx/index.ts could be:
export default from "./tsx";
If all your packages just provide a default export, they could all follow the pattern above. Otherwise, if a package exports multiple symbols and just want to reexport everything, you can do:
export * from "./myModule";
If you do this for all your packages, you don't need to rename anything but you'd have additional index files to satisfy the "*": ["*", "packages/*"] mapping.
In a comment, you mentioned using a tool like Barrelsby to generate index files. I'd be concerned about the impact on development. I can see generating an index file acting as a facade as part of publishing your project. So people consuming the published project deal with a file generated by Barrelsby or some other tool. However, your index files appear to me to be internal to your project. So in order to get proper IDE support while developing the index files will have to already exist before contributors start contributing. So contributors would have to run something that generates the index files before they start contributing. You would also have generated files that live side by side with files that are authored directly by developers. I try to avoid this in my projects.
If it were my project and I decided to add index files to satisfy the tsconfig.json mapping, I'd aim to structure my project so that the index files boil down to one of the two cases above, and skip using a code generator. (Actually, I'd aim for the 2nd of the two cases above, because I prefer to avoid default exports. See here for a discussion of the issues with default exports.)
Individually Map The Packages
If the other solutions are problematic for your specific project, you can provide one mapping per package:
"paths":
"jsx": ["packages/jsx/jsx.jsx"],
"tjs": ["packages/tjs/tjs.js"],
"tscript": ["packages/tscript/tscript.js"],
"tsx": ["packages/tsx/tsx.tsx"],
,
This means adding a mapping each time you add a new package. Whether or not this is viable depends on your specific project. You could also use a baseUrl set to "packages/" and remove packages/ from all the paths above:
"baseUrl": "packages/",
"paths":
"jsx": ["jsx/jsx.jsx"],
"tjs": ["tjs/tjs.js"],
"tscript": ["tscript/tscript.js"],
"tsx": ["tsx/tsx.tsx"],
,
This makes the whole thing less verbose though you still have to provide one mapping per package.
Thank you very much, @Louis. Editing the tsconfig for each module would be madness (we add/remove/edit 2-3 a week, we'd be clobbering git commits routinely, and our tsconfig would be thousands of lines long). So that's not very practical. However I stumbled across a plugin — module-plugin-d-ts? Do you think this or perhaps another TS plugin might assist in solving this problem?
– Brian M. Hunt
Mar 10 at 16:23
Sounds like you've got a special case. I don't seemodule-plugin.d.tsas pertaining to your problem. It illustrates how you can augment a module. For instance, when you load a jQuery plugin, jQuery itself gains new methods. e.g If you load Bootstrap, then jQuery gets$().modal,$().dropdown, ... which are not on the stock jQuery. It is puzzling at first to figure how to declare the interface for such a plugin. Search for "module plugin" on this page for the context tomodule-plugin.d.ts.
– Louis
Mar 10 at 16:56
1
@BrianM.Hunt Comments are too small to respond to your Barrelsby idea, so I've added a new section to my answer.
– Louis
Mar 10 at 20:31
1
I actually tried puttingpackage.jsoninto thepackages/*/subdirectories... but it did not work. I still have that trial on disk, so I went back to it just now and looked again. Sigh I had an errant trailing comma in the JSON, which causedtscto silently pretend that thepackage.jsonis absent. Once I removed the comma, it worked. If I had not made that mistake, I would have mentioned it in the first place. I'm going to edit my answer to include that possibility.
– Louis
Mar 13 at 17:46
1
And thanks for the bounty!
– Louis
Mar 13 at 17:48
|
show 4 more comments
You already got an answer from Wex suggesting that you rename your files to have the basename index plus the appropriate extension and use the mapping "*"*: ["*", "packages/*"]. You mentioned in a comment that you'd rather avoid renaming the files. Besides avoiding renames, I'm not a fan of having a lot of files be named index.<some_extension>. When working, my eyes are naturally drawn to the basename of the files I'm working on or getting reports about. Having to distinguish files that have near-identical basenames by directory is possible but requires more cognitive work on my part to look away from the basename and at the path, or more work at the keyboard for completion. (It takes longer to type. There's only so much help the IDE can provide.) It is enough to be annoying.
First, let's deal with the dead ends. I see no evidence that ~ and $1 are treated specially in paths. I went to check tsc's code and see nothing there that handles such patterns. It could be that I missed it, but I think they are just not special. Also, ignoring extensions for the moment, your desired mapping is something packages/<package_name>/<package_name>.ext The package name appears twice. So it would be tempting to set a mapping like "*": ["packages/*/*.ext"] but that's explicitly not allowed by TypesScript: tsc will give you an error about the two asterisks appearing in the desired mapping. So that's not an option either.
Use package.json
You could dodge the renaming issue by adding a package.json to each package with a "main" field that points to the file you want to be considered the entry point of your package. For instance, packages/jsx/package.json could contain this:
"main": "jsx.jsx"
By providing similar files for all other packages, you can reduce the relevant configuration to:
"baseUrl": "",
"paths":
"*": ["packages/*", "*"]
,
Or you can use "baseUrl" to point to your packages and omit "paths" entirely:
"baseUrl": "packages/",
Make sure that you lint the package.json files because tsc will simply ignore them silently if there's any syntactic mistake in these files.
Add index Files that Reexport your Entry Module
Another method would be to use index files that simply reexport all of the file you'd otherwise want to be the entry point of your package. The files you currently have would remain there but would be referenced by appropriately designed index files. For instance, packages/tsx/index.ts could be:
export default from "./tsx";
If all your packages just provide a default export, they could all follow the pattern above. Otherwise, if a package exports multiple symbols and just want to reexport everything, you can do:
export * from "./myModule";
If you do this for all your packages, you don't need to rename anything but you'd have additional index files to satisfy the "*": ["*", "packages/*"] mapping.
In a comment, you mentioned using a tool like Barrelsby to generate index files. I'd be concerned about the impact on development. I can see generating an index file acting as a facade as part of publishing your project. So people consuming the published project deal with a file generated by Barrelsby or some other tool. However, your index files appear to me to be internal to your project. So in order to get proper IDE support while developing the index files will have to already exist before contributors start contributing. So contributors would have to run something that generates the index files before they start contributing. You would also have generated files that live side by side with files that are authored directly by developers. I try to avoid this in my projects.
If it were my project and I decided to add index files to satisfy the tsconfig.json mapping, I'd aim to structure my project so that the index files boil down to one of the two cases above, and skip using a code generator. (Actually, I'd aim for the 2nd of the two cases above, because I prefer to avoid default exports. See here for a discussion of the issues with default exports.)
Individually Map The Packages
If the other solutions are problematic for your specific project, you can provide one mapping per package:
"paths":
"jsx": ["packages/jsx/jsx.jsx"],
"tjs": ["packages/tjs/tjs.js"],
"tscript": ["packages/tscript/tscript.js"],
"tsx": ["packages/tsx/tsx.tsx"],
,
This means adding a mapping each time you add a new package. Whether or not this is viable depends on your specific project. You could also use a baseUrl set to "packages/" and remove packages/ from all the paths above:
"baseUrl": "packages/",
"paths":
"jsx": ["jsx/jsx.jsx"],
"tjs": ["tjs/tjs.js"],
"tscript": ["tscript/tscript.js"],
"tsx": ["tsx/tsx.tsx"],
,
This makes the whole thing less verbose though you still have to provide one mapping per package.
You already got an answer from Wex suggesting that you rename your files to have the basename index plus the appropriate extension and use the mapping "*"*: ["*", "packages/*"]. You mentioned in a comment that you'd rather avoid renaming the files. Besides avoiding renames, I'm not a fan of having a lot of files be named index.<some_extension>. When working, my eyes are naturally drawn to the basename of the files I'm working on or getting reports about. Having to distinguish files that have near-identical basenames by directory is possible but requires more cognitive work on my part to look away from the basename and at the path, or more work at the keyboard for completion. (It takes longer to type. There's only so much help the IDE can provide.) It is enough to be annoying.
First, let's deal with the dead ends. I see no evidence that ~ and $1 are treated specially in paths. I went to check tsc's code and see nothing there that handles such patterns. It could be that I missed it, but I think they are just not special. Also, ignoring extensions for the moment, your desired mapping is something packages/<package_name>/<package_name>.ext The package name appears twice. So it would be tempting to set a mapping like "*": ["packages/*/*.ext"] but that's explicitly not allowed by TypesScript: tsc will give you an error about the two asterisks appearing in the desired mapping. So that's not an option either.
Use package.json
You could dodge the renaming issue by adding a package.json to each package with a "main" field that points to the file you want to be considered the entry point of your package. For instance, packages/jsx/package.json could contain this:
"main": "jsx.jsx"
By providing similar files for all other packages, you can reduce the relevant configuration to:
"baseUrl": "",
"paths":
"*": ["packages/*", "*"]
,
Or you can use "baseUrl" to point to your packages and omit "paths" entirely:
"baseUrl": "packages/",
Make sure that you lint the package.json files because tsc will simply ignore them silently if there's any syntactic mistake in these files.
Add index Files that Reexport your Entry Module
Another method would be to use index files that simply reexport all of the file you'd otherwise want to be the entry point of your package. The files you currently have would remain there but would be referenced by appropriately designed index files. For instance, packages/tsx/index.ts could be:
export default from "./tsx";
If all your packages just provide a default export, they could all follow the pattern above. Otherwise, if a package exports multiple symbols and just want to reexport everything, you can do:
export * from "./myModule";
If you do this for all your packages, you don't need to rename anything but you'd have additional index files to satisfy the "*": ["*", "packages/*"] mapping.
In a comment, you mentioned using a tool like Barrelsby to generate index files. I'd be concerned about the impact on development. I can see generating an index file acting as a facade as part of publishing your project. So people consuming the published project deal with a file generated by Barrelsby or some other tool. However, your index files appear to me to be internal to your project. So in order to get proper IDE support while developing the index files will have to already exist before contributors start contributing. So contributors would have to run something that generates the index files before they start contributing. You would also have generated files that live side by side with files that are authored directly by developers. I try to avoid this in my projects.
If it were my project and I decided to add index files to satisfy the tsconfig.json mapping, I'd aim to structure my project so that the index files boil down to one of the two cases above, and skip using a code generator. (Actually, I'd aim for the 2nd of the two cases above, because I prefer to avoid default exports. See here for a discussion of the issues with default exports.)
Individually Map The Packages
If the other solutions are problematic for your specific project, you can provide one mapping per package:
"paths":
"jsx": ["packages/jsx/jsx.jsx"],
"tjs": ["packages/tjs/tjs.js"],
"tscript": ["packages/tscript/tscript.js"],
"tsx": ["packages/tsx/tsx.tsx"],
,
This means adding a mapping each time you add a new package. Whether or not this is viable depends on your specific project. You could also use a baseUrl set to "packages/" and remove packages/ from all the paths above:
"baseUrl": "packages/",
"paths":
"jsx": ["jsx/jsx.jsx"],
"tjs": ["tjs/tjs.js"],
"tscript": ["tscript/tscript.js"],
"tsx": ["tsx/tsx.tsx"],
,
This makes the whole thing less verbose though you still have to provide one mapping per package.
edited Mar 13 at 18:05
answered Mar 10 at 15:50
LouisLouis
98k22189238
98k22189238
Thank you very much, @Louis. Editing the tsconfig for each module would be madness (we add/remove/edit 2-3 a week, we'd be clobbering git commits routinely, and our tsconfig would be thousands of lines long). So that's not very practical. However I stumbled across a plugin — module-plugin-d-ts? Do you think this or perhaps another TS plugin might assist in solving this problem?
– Brian M. Hunt
Mar 10 at 16:23
Sounds like you've got a special case. I don't seemodule-plugin.d.tsas pertaining to your problem. It illustrates how you can augment a module. For instance, when you load a jQuery plugin, jQuery itself gains new methods. e.g If you load Bootstrap, then jQuery gets$().modal,$().dropdown, ... which are not on the stock jQuery. It is puzzling at first to figure how to declare the interface for such a plugin. Search for "module plugin" on this page for the context tomodule-plugin.d.ts.
– Louis
Mar 10 at 16:56
1
@BrianM.Hunt Comments are too small to respond to your Barrelsby idea, so I've added a new section to my answer.
– Louis
Mar 10 at 20:31
1
I actually tried puttingpackage.jsoninto thepackages/*/subdirectories... but it did not work. I still have that trial on disk, so I went back to it just now and looked again. Sigh I had an errant trailing comma in the JSON, which causedtscto silently pretend that thepackage.jsonis absent. Once I removed the comma, it worked. If I had not made that mistake, I would have mentioned it in the first place. I'm going to edit my answer to include that possibility.
– Louis
Mar 13 at 17:46
1
And thanks for the bounty!
– Louis
Mar 13 at 17:48
|
show 4 more comments
Thank you very much, @Louis. Editing the tsconfig for each module would be madness (we add/remove/edit 2-3 a week, we'd be clobbering git commits routinely, and our tsconfig would be thousands of lines long). So that's not very practical. However I stumbled across a plugin — module-plugin-d-ts? Do you think this or perhaps another TS plugin might assist in solving this problem?
– Brian M. Hunt
Mar 10 at 16:23
Sounds like you've got a special case. I don't seemodule-plugin.d.tsas pertaining to your problem. It illustrates how you can augment a module. For instance, when you load a jQuery plugin, jQuery itself gains new methods. e.g If you load Bootstrap, then jQuery gets$().modal,$().dropdown, ... which are not on the stock jQuery. It is puzzling at first to figure how to declare the interface for such a plugin. Search for "module plugin" on this page for the context tomodule-plugin.d.ts.
– Louis
Mar 10 at 16:56
1
@BrianM.Hunt Comments are too small to respond to your Barrelsby idea, so I've added a new section to my answer.
– Louis
Mar 10 at 20:31
1
I actually tried puttingpackage.jsoninto thepackages/*/subdirectories... but it did not work. I still have that trial on disk, so I went back to it just now and looked again. Sigh I had an errant trailing comma in the JSON, which causedtscto silently pretend that thepackage.jsonis absent. Once I removed the comma, it worked. If I had not made that mistake, I would have mentioned it in the first place. I'm going to edit my answer to include that possibility.
– Louis
Mar 13 at 17:46
1
And thanks for the bounty!
– Louis
Mar 13 at 17:48
Thank you very much, @Louis. Editing the tsconfig for each module would be madness (we add/remove/edit 2-3 a week, we'd be clobbering git commits routinely, and our tsconfig would be thousands of lines long). So that's not very practical. However I stumbled across a plugin — module-plugin-d-ts? Do you think this or perhaps another TS plugin might assist in solving this problem?
– Brian M. Hunt
Mar 10 at 16:23
Thank you very much, @Louis. Editing the tsconfig for each module would be madness (we add/remove/edit 2-3 a week, we'd be clobbering git commits routinely, and our tsconfig would be thousands of lines long). So that's not very practical. However I stumbled across a plugin — module-plugin-d-ts? Do you think this or perhaps another TS plugin might assist in solving this problem?
– Brian M. Hunt
Mar 10 at 16:23
Sounds like you've got a special case. I don't see
module-plugin.d.ts as pertaining to your problem. It illustrates how you can augment a module. For instance, when you load a jQuery plugin, jQuery itself gains new methods. e.g If you load Bootstrap, then jQuery gets $().modal, $().dropdown, ... which are not on the stock jQuery. It is puzzling at first to figure how to declare the interface for such a plugin. Search for "module plugin" on this page for the context to module-plugin.d.ts.– Louis
Mar 10 at 16:56
Sounds like you've got a special case. I don't see
module-plugin.d.ts as pertaining to your problem. It illustrates how you can augment a module. For instance, when you load a jQuery plugin, jQuery itself gains new methods. e.g If you load Bootstrap, then jQuery gets $().modal, $().dropdown, ... which are not on the stock jQuery. It is puzzling at first to figure how to declare the interface for such a plugin. Search for "module plugin" on this page for the context to module-plugin.d.ts.– Louis
Mar 10 at 16:56
1
1
@BrianM.Hunt Comments are too small to respond to your Barrelsby idea, so I've added a new section to my answer.
– Louis
Mar 10 at 20:31
@BrianM.Hunt Comments are too small to respond to your Barrelsby idea, so I've added a new section to my answer.
– Louis
Mar 10 at 20:31
1
1
I actually tried putting
package.json into the packages/*/ subdirectories... but it did not work. I still have that trial on disk, so I went back to it just now and looked again. Sigh I had an errant trailing comma in the JSON, which caused tsc to silently pretend that the package.json is absent. Once I removed the comma, it worked. If I had not made that mistake, I would have mentioned it in the first place. I'm going to edit my answer to include that possibility.– Louis
Mar 13 at 17:46
I actually tried putting
package.json into the packages/*/ subdirectories... but it did not work. I still have that trial on disk, so I went back to it just now and looked again. Sigh I had an errant trailing comma in the JSON, which caused tsc to silently pretend that the package.json is absent. Once I removed the comma, it worked. If I had not made that mistake, I would have mentioned it in the first place. I'm going to edit my answer to include that possibility.– Louis
Mar 13 at 17:46
1
1
And thanks for the bounty!
– Louis
Mar 13 at 17:48
And thanks for the bounty!
– Louis
Mar 13 at 17:48
|
show 4 more comments
Part of the issue with your current tsconfig.json is that you are using include: [], so no code will actually be matched by your config!
I couldn't find any examples of using the $1 pattern the way you have it in your sample config, nor do I think what you are trying to do is possible based on some research (see also: #5039). Are you able to rename package/package.jsx to package/index.jsx? Then your paths config could trivially be changed to:
"paths":
"*": ["*", "packages/*"]
,
Thanks @wex. I copied the$1code from a comment on #24116, though that's it. That's a great link to #5039, I'll dig into it more. Thanks for the suggestion to rename packages topackage/index.js. It'd involve a huge number lot of file changes, so we'd prefer to avoid it, but it's good to know it's a backstop.
– Brian M. Hunt
Mar 9 at 1:42
add a comment |
Part of the issue with your current tsconfig.json is that you are using include: [], so no code will actually be matched by your config!
I couldn't find any examples of using the $1 pattern the way you have it in your sample config, nor do I think what you are trying to do is possible based on some research (see also: #5039). Are you able to rename package/package.jsx to package/index.jsx? Then your paths config could trivially be changed to:
"paths":
"*": ["*", "packages/*"]
,
Thanks @wex. I copied the$1code from a comment on #24116, though that's it. That's a great link to #5039, I'll dig into it more. Thanks for the suggestion to rename packages topackage/index.js. It'd involve a huge number lot of file changes, so we'd prefer to avoid it, but it's good to know it's a backstop.
– Brian M. Hunt
Mar 9 at 1:42
add a comment |
Part of the issue with your current tsconfig.json is that you are using include: [], so no code will actually be matched by your config!
I couldn't find any examples of using the $1 pattern the way you have it in your sample config, nor do I think what you are trying to do is possible based on some research (see also: #5039). Are you able to rename package/package.jsx to package/index.jsx? Then your paths config could trivially be changed to:
"paths":
"*": ["*", "packages/*"]
,
Part of the issue with your current tsconfig.json is that you are using include: [], so no code will actually be matched by your config!
I couldn't find any examples of using the $1 pattern the way you have it in your sample config, nor do I think what you are trying to do is possible based on some research (see also: #5039). Are you able to rename package/package.jsx to package/index.jsx? Then your paths config could trivially be changed to:
"paths":
"*": ["*", "packages/*"]
,
answered Mar 8 at 22:49
WexWex
11.6k95091
11.6k95091
Thanks @wex. I copied the$1code from a comment on #24116, though that's it. That's a great link to #5039, I'll dig into it more. Thanks for the suggestion to rename packages topackage/index.js. It'd involve a huge number lot of file changes, so we'd prefer to avoid it, but it's good to know it's a backstop.
– Brian M. Hunt
Mar 9 at 1:42
add a comment |
Thanks @wex. I copied the$1code from a comment on #24116, though that's it. That's a great link to #5039, I'll dig into it more. Thanks for the suggestion to rename packages topackage/index.js. It'd involve a huge number lot of file changes, so we'd prefer to avoid it, but it's good to know it's a backstop.
– Brian M. Hunt
Mar 9 at 1:42
Thanks @wex. I copied the
$1 code from a comment on #24116, though that's it. That's a great link to #5039, I'll dig into it more. Thanks for the suggestion to rename packages to package/index.js. It'd involve a huge number lot of file changes, so we'd prefer to avoid it, but it's good to know it's a backstop.– Brian M. Hunt
Mar 9 at 1:42
Thanks @wex. I copied the
$1 code from a comment on #24116, though that's it. That's a great link to #5039, I'll dig into it more. Thanks for the suggestion to rename packages to package/index.js. It'd involve a huge number lot of file changes, so we'd prefer to avoid it, but it's good to know it's a backstop.– Brian M. Hunt
Mar 9 at 1:42
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55063550%2fvs-code-cannot-find-module-from-root-path%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown