You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Module path maps are not resolved in emitted code #10866
% ./node_modules/.bin/tsc && node app.js
module.js:457
throw err;
^
Error: Cannot find module 'foo/utils'
at Function.Module._resolveFilename (module.js:455:15)
at Function.Module._load (module.js:403:25)
at Module.require (module.js:483:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (/home/mfischer/src/videmo/tsc-test/app.js:2:17)
at Module._compile (module.js:556:32)
at Object.Module._extensions..js (module.js:565:10)
at Module.load (module.js:473:32)
at tryModuleLoad (module.js:432:12)
at Function.Module._load (module.js:424:3)
Typescript is finding the right module, but in the emitted code, the module path is left as-is instead of applying the path aliases from tsconfig.json. Obviously node has no idea where to find the module. I would have expected typescript to resolve the module path and replace it with something that node can resolve.
If this behavior is intended, then how can the path maps be used to solve the relative-import-hell in conjunction with node?
Do you use some other bundling tool like browserify or webpack on the generated output? or do you expect this to run directly on node?
Reacted by Petr Peller, Gary Chamberlain, Ádám Szigeti, CIRPLAN, Kamil Mysliwiec, Nicky van Meurs, Angelo Gazzola, 洪春, xnsua, Saran Tanpituckpong ✔️ and 3 more
If this behavior is intended, then how can the path maps be used to solve the relative-import-hell in conjunction with node?
Well and to add context, "paths" is designed for use with loaders that allow remapping, unlike the Node.js require(). The intended behaviour is to allow TypeScript to resolve type information for various module IDs used by various loaders, not to rewrite module IDs. Basically it doesn't do what you thought it did. Nor should it in my opinion, it should only have the capability to mirror the resolution strategies of loaders.
Reacted by Daniel Rosenwasser and Alex Rickabaugh
Reacted by sandorvasas, Chris Devereux, Felix Grayson, Petr Peller, Gary Chamberlain, Moe, purplemana, sdeprez, Damian Majsner, Tom Medema and 19 more
Mohamed Hegazy (@mhegazy) I expected it to work directly with node. It's for a backend application. Is Kitson Kelly (@kitsonk) correct in stating that this is working as intended and typescript will not rewrite module paths?
Reacted by Juan, Kirill Groshkov, Paul Li, Roman, Ole Ersoy, Colin Luo, Chris Devereux, Gary Chamberlain, xyfir, Raschid and 10 more
yes, this was the intent - to mitigate the mismatch between runtime and design time experience when module (as it is written by user) can be resolved in runtime but failed to be found by the compiler. At this point compiler always assumes that module id provided by the user is correct and never tries to change it.
All right, thanks. It might be useful to document this better in order to prevent more people from being confused. I now use https://www.npmjs.com/package/module-alias to make it work with node.
Reacted by Lauri Lüüs, Qiu ChangJin, Edvin Vidmar, Dylan Stewart, Patrik Forsberg, Renzo, Lucas Souza, Ivan Perevezentsev, Vlad Balin, Chris Maas and 39 more
Reacted by Neo, Marc Bornträger, Michael Wieczorek, Bastien and cyorobert
Reacted by Neo, Marc Bornträger, Janusz Białobrzewski, Bastien, cyorobert, Anas TIOUR and Eric Dodson
Appreciating TS's position, here's a simple solution to the 90% use case for those of us using node, but wanting the convenience of using baseUrl relative require() calls without any fuss.
This solution hooks node's require() call, and resolves requests using the dirname of "main" to mimic baseUrl. It therefore assumes the baseUrl compiler option was also set to the same directory where the source "main.ts" was located.
To use, paste this tiny chunk of code at the top of your "main.ts".
If you're going to use the module-alias package that mika-fischer mentioned, note that the paths you register to the package shouldn't end in /, and the paths are relative to the path where package.json is (it may be obvious but it's good to get it clear),
Reacted by Ivan Perevezentsev, Vlad Balin, Anatoliy Arkhipov, Chris Maas, Ariel Weinberger, shekohex, Preston Pham, DMW007, Kirill Groshkov, Jorge Arco and 7 more
Reacted by Ariel Weinberger, Kirill Groshkov and Grégoire THIEBAULT
Well and to add context, "paths" is designed for use with loaders that allow remapping, unlike the Node.js require(). The intended behaviour is to allow TypeScript to resolve type information for various module IDs used by various loaders, not to rewrite module IDs. Basically it doesn't do what you thought it did. Nor should it in my opinion, it should only have the capability to mirror the resolution strategies of loaders.
Got here after wasting some time trying to set it up in a big project.
If this behaviour is not going to change the least you could do is to update the documentation before closing this issue.
The official documentation https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping%20docs does not say a thing about having to use "loaders that allow remapping" whatsoever.
Reacted by Bogdan Balan, Sebastian Lasse, Fille, Daniel, Kirill Groshkov, Alex Red, AngrySean, Yazeed Sabri, Christopher Baily, ivibe and 16 more
I really don´t understand what you are trying to point out by establishing that TS is not C++, most of us are well aware of that I think!
We have also established that alias/path mapping is used in production all over the world, so naturally, VS Code should support that, but it´s still not an argument for MS to craft the compiler to suit your setup!
What I´m having a hard time understanding is why you keep at it, the compiler works as it´s supposed to work, again, read the docs which clearly states what the feature is for!
I mean you can set up a working TS development environment with path aliases in like 2 minutes, if you don´t want to use WebPack, you can use TSPath to resolve all paths in all js files in 1 second, add it to the package.json as a run script and you don´t even have to think about it, the problem does not exist, the compiler stays the way it was meant to function and you can carry on happy hurray!?
Or if it is so important to you that the actual compiler does this for you, then I suggest you fork the compiler and implement it yourself, maybe it would be a big hit or maybe people are happy the way they are since they have set up their environments to support aliases.
Could the TypeScript team reconsider this issue? I think this thread offers some useful discussion on both viewpoints and given its recent popularity and the amount of time that's passed it should be looked at again.
Reacted by Saran Tanpituckpong ✔️, Mariusz Kujawski, tjuenger, Cody, Alex Soncodi, Tobi, Lauri Lüüs, Sviatoslav Sivov, Mia Heidenstedt, InvictusMB and 9 more
Reacted by Daniel Rosenwasser
Reacted by Fabio Spampinato, Saran Tanpituckpong ✔️, Mariusz Kujawski and Cody
Reacted by Saran Tanpituckpong ✔️, Mariusz Kujawski, Cody, Rodrigo Alves and Mike Mitterer
The status of this issue left me no other choice but to demote TS to type checker duty only.
Babel now has a decent support for TS syntax and together with babel-plugin-module-resolver does the job of emitting working code for this use case just fine.
The only downside is duplicating bits of configuration from tsconfig.json as Babel does not care about TS configs. But it is an acceptable price for working absolute paths in node projects and as a bonus I get the whole ecosystem with brilliant things like babel macros.
This is the minimum setup I got working as a drop in replacement for tsc compiler:
I just want to use typescript with absolute path, but seems i have to config webpack or babel or something, it's too hard to achieve this simple feature, it should be easier 😞
Reacted by Saran Tanpituckpong ✔️, Cody, tjuenger, ollie, Andreas Gutenberg and Varun Singh
I acknowledge this problem, I´m not sure I´ve been aware of this specific
problem due to my own personal setup, or maybe I was :) it´s not a super
heavy fix, the fix will simply be to simply (blindly) trust the distPath,
which is actually less and more simple code than the current solution, I´ll
try to have a fix available by tomorrow...
Den mån 28 jan. 2019 kl 15:59 skrev 叶伟伟 <notifications@github.com>:
Leaving this here because an actual documented use case for the current behavior of paths was not mentioned in this thread: @types/ packages do not backport features with regards to semver. They do however include updated types for older APIs that I can use. E.g. I'm using history@2 when history@3 is the latest.
"paths": {
"history": [ "history/v2" ]
}
The compiler would need an extra option to differentiate between type aliases and "code" aliases. If we change the behavior to actually emit the path aliases then we need to add the ability to the compiler to find the correct types version.
This is not an argument against the proposed behavior. I'd rather have emitted aliases and just™ working solution for versioning of types. Just wanted to provide some context why changing this might not be as trivial as people think it is.
I understand your frustration, but lots of people feeling a behaviour is correct, doesn't mean it is the right thing to do.
TypeScript rewriting module identifiers is a slippery slippery slope. What has been expressed multiple times in this thread is that TypeScript is configurable to model the behaviour of other module resolvers and other build tools, not replace or implement them.
Just because TypeScript can be configured to resolve modules in flexible ways doesn't not mean that TypeScript emits "broken code". Certain loaders and bundlers that mirror this configuration would work just fine.
If we were to be critical of anything, we could blame the team for naming the option something that might look like it fixes a problem it was never intended to fix, though the documentation for the option makes it clear that it does not change the emit.
Because a particular tool doesn't solve a problem you have doesn't always mean it is that tools fault. It maybe you are just don't have all the tools you need to solve your problem.
The issue is that TS will operate one way during development / testing, and another after compilation has completed.
If TS wants to be a module resolver, it needs to choose a pattern and stick to it. If I run something with ts-node it should operate exactly as if I compiled some TS and ran it with node.
Maybe module maps will alleviate the frustration in the future. But our position here along with the technical problems we want to solve are pretty explicit - path mapping reflects the behavior of an external resolution scheme (e.g. path mapping in AMD and System.js, aliases in Webpack and other bundlers). It doesn't imply we will change your paths.
I don't think any recent discussion has been constructive recently, nor do I foresee any future changes here, so I'm going to lock this issue.
Activity
mhegazy commentedon Sep 13, 2016
Do you use some other bundling tool like browserify or webpack on the generated output? or do you expect this to run directly on node?
kitsonk commentedon Sep 13, 2016
Well and to add context,
"paths"is designed for use with loaders that allow remapping, unlike the Node.jsrequire(). The intended behaviour is to allow TypeScript to resolve type information for various module IDs used by various loaders, not to rewrite module IDs. Basically it doesn't do what you thought it did. Nor should it in my opinion, it should only have the capability to mirror the resolution strategies of loaders.mika-fischer commentedon Sep 13, 2016
Mohamed Hegazy (@mhegazy) I expected it to work directly with node. It's for a backend application. Is Kitson Kelly (@kitsonk) correct in stating that this is working as intended and typescript will not rewrite module paths?
vladima commentedon Sep 13, 2016
yes, this was the intent - to mitigate the mismatch between runtime and design time experience when module (as it is written by user) can be resolved in runtime but failed to be found by the compiler. At this point compiler always assumes that module id provided by the user is correct and never tries to change it.
mhegazy commentedon Sep 13, 2016
similar response #9910 (comment)
mika-fischer commentedon Sep 14, 2016
All right, thanks. It might be useful to document this better in order to prevent more people from being confused. I now use https://www.npmjs.com/package/module-alias to make it work with node.
papercuptech commentedon Dec 20, 2016
Appreciating TS's position, here's a simple solution to the 90% use case for those of us using node, but wanting the convenience of using
baseUrlrelativerequire()calls without any fuss.This solution hooks node's
require()call, and resolves requests using the dirname of "main" to mimicbaseUrl. It therefore assumes thebaseUrlcompiler option was also set to the same directory where the source "main.ts" was located.To use, paste this tiny chunk of code at the top of your "main.ts".
Parziphal commentedon Sep 6, 2017
If you're going to use the
module-aliaspackage that mika-fischer mentioned, note that the paths you register to the package shouldn't end in/, and the paths are relative to the path wherepackage.jsonis (it may be obvious but it's good to get it clear),So if you have this in your tsconfig file:
You have to register this in your
package.json:jbgraug commentedon Dec 12, 2017
Got here after wasting some time trying to set it up in a big project.
If this behaviour is not going to change the least you could do is to update the documentation before closing this issue.
The official documentation https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping%20docs does not say a thing about having to use "loaders that allow remapping" whatsoever.
duffman commentedon Jan 14, 2018
install and run "tspath" in your project folder... https://www.npmjs.com/package/tspath
mattyclarkson commentedon Feb 6, 2018
@ef-carbon/tspm0ct0d4n commentedon Feb 22, 2018
Also you can try "momothepug/tsmodule-alias" to alias path resolution:
https://www.npmjs.com/package/@momothepug/tsmodule-alias
BorntraegerMarc commentedon May 1, 2018
Only https://www.npmjs.com/package/module-alias worked for me...
53 remaining items
duffman commentedon Jan 15, 2019
I really don´t understand what you are trying to point out by establishing that TS is not C++, most of us are well aware of that I think!
We have also established that alias/path mapping is used in production all over the world, so naturally, VS Code should support that, but it´s still not an argument for MS to craft the compiler to suit your setup!
What I´m having a hard time understanding is why you keep at it, the compiler works as it´s supposed to work, again, read the docs which clearly states what the feature is for!
I mean you can set up a working TS development environment with path aliases in like 2 minutes, if you don´t want to use WebPack, you can use TSPath to resolve all paths in all js files in 1 second, add it to the package.json as a run script and you don´t even have to think about it, the problem does not exist, the compiler stays the way it was meant to function and you can carry on happy hurray!?
Or if it is so important to you that the actual compiler does this for you, then I suggest you fork the compiler and implement it yourself, maybe it would be a big hit or maybe people are happy the way they are since they have set up their environments to support aliases.
MrXyfir commentedon Jan 15, 2019
Summoning the top five TypeScript contributors: Anders Hejlsberg (@ahejlsberg) Andy (Andrewkraft) (@Andy-MS) Daniel Rosenwasser (@DanielRosenwasser) Nathan Shively-Sanders (@sandersn) Sheetal Nandi (@sheetalkamat)
Could the TypeScript team reconsider this issue? I think this thread offers some useful discussion on both viewpoints and given its recent popularity and the amount of time that's passed it should be looked at again.
InvictusMB commentedon Jan 22, 2019
The status of this issue left me no other choice but to demote TS to type checker duty only.
Babel now has a decent support for TS syntax and together with
babel-plugin-module-resolverdoes the job of emitting working code for this use case just fine.The only downside is duplicating bits of configuration from
tsconfig.jsonas Babel does not care about TS configs. But it is an acceptable price for working absolute paths in node projects and as a bonus I get the whole ecosystem with brilliant things like babel macros.This is the minimum setup I got working as a drop in replacement for
tsccompiler:npm install --save-dev @babel/cli @babel/core @babel/preset-env @babel/preset-typescript babel-plugin-module-resolver @babel/plugin-proposal-class-properties @babel/plugin-proposal-object-rest-spreadpackage.json:tsc->tsc && babel ./src --out-dir ./dist --extensions ".ts,.js"tsconfig.json:{ "compilerOptions": { "baseUrl": ".", "paths": { "@mynamespace/*": ["src/*"] }, "outDir": "./dist", "noEmit": true, <-- "allowJs": true, "target": "ES2017", "module": "CommonJS", "lib": [ "ES2017" ] }, "include": [ "./src/**/*" ] }.babelrc:{ "presets": [ "@babel/preset-typescript", ["@babel/preset-env", { "targets": { "node": true } }] ], "plugins": [ ["module-resolver", { "root": ["./src"], "alias": { "@mynamespace": "./src" }, "extensions": [".js", ".ts"] }], "@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-object-rest-spread" ] }ywwhack commentedon Jan 28, 2019
I just want to use typescript with absolute path, but seems i have to config webpack or babel or something, it's too hard to achieve this simple feature, it should be easier 😞
duffman commentedon Jan 28, 2019
eps1lon commentedon Feb 7, 2019
Leaving this here because an actual documented use case for the current behavior of
pathswas not mentioned in this thread:@types/packages do not backport features with regards to semver. They do however include updated types for older APIs that I can use. E.g. I'm usinghistory@2whenhistory@3is the latest.The compiler would need an extra option to differentiate between type aliases and "code" aliases. If we change the behavior to actually emit the path aliases then we need to add the ability to the compiler to find the correct types version.
This is not an argument against the proposed behavior. I'd rather have emitted aliases and just™ working solution for versioning of types. Just wanted to provide some context why changing this might not be as trivial as people think it is.
https://github.com/Microsoft/TypeScript/issues/10866
Add option path mapping
cruhl commentedon Feb 14, 2019
For the second time during a company-wide TS workshop, I've had to explain this inane and embarrassing behavior...
Seriously!
What kind of language compiler, especially one whose primary sales pitch is more correctness for JavaScript, produces broken code as a "feature"?!?!
cruhl commentedon Feb 14, 2019
I'm sorry to have sounded so frustrated in my comment, but the community's views here are seemingly being ignored and downplayed repeatedly.
cruhl commentedon Feb 14, 2019
Just look at how many times this has been referenced... What a waste of time and attention for so many people.
kitsonk commentedon Feb 14, 2019
I understand your frustration, but lots of people feeling a behaviour is correct, doesn't mean it is the right thing to do.
TypeScript rewriting module identifiers is a slippery slippery slope. What has been expressed multiple times in this thread is that TypeScript is configurable to model the behaviour of other module resolvers and other build tools, not replace or implement them.
Just because TypeScript can be configured to resolve modules in flexible ways doesn't not mean that TypeScript emits "broken code". Certain loaders and bundlers that mirror this configuration would work just fine.
If we were to be critical of anything, we could blame the team for naming the option something that might look like it fixes a problem it was never intended to fix, though the documentation for the option makes it clear that it does not change the emit.
Because a particular tool doesn't solve a problem you have doesn't always mean it is that tools fault. It maybe you are just don't have all the tools you need to solve your problem.
dwjft commentedon Feb 14, 2019
Kitson Kelly (@kitsonk) everything you just said is way off the mark.
The issue is that TS will operate one way during development / testing, and another after compilation has completed.
If TS wants to be a module resolver, it needs to choose a pattern and stick to it. If I run something with
ts-nodeit should operate exactly as if I compiled some TS and ran it withnode.It does not, and that is the problem.
DanielRosenwasser commentedon Feb 14, 2019
Maybe module maps will alleviate the frustration in the future. But our position here along with the technical problems we want to solve are pretty explicit - path mapping reflects the behavior of an external resolution scheme (e.g. path mapping in AMD and System.js, aliases in Webpack and other bundlers). It doesn't imply we will change your paths.
I don't think any recent discussion has been constructive recently, nor do I foresee any future changes here, so I'm going to lock this issue.