TypeScript: Module path maps are not resolved in emitted code
TypeScript Version: 2.0.2
Code
tsconfig.json
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"baseUrl": ".",
"paths": {
"foo/*": ["*"]
}
}
}
app.ts
import {Foo} from 'foo/utils';
console.log(Foo);
utils.ts
export const Foo = 'Foo';
Expected behavior:
% ./node_modules/.bin/tsc && node app.js
Foo
Actual behavior:
% ./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)
app.js
"use strict";
const utils_1 = require('foo/utils');
console.log(utils_1.Foo);
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?
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 116
- Comments: 76 (9 by maintainers)
Links to this issue
Commits related to this issue
- Looks like VS Code tried to be helpful and automatically use my path alias to /src for all files in /src. Unfortunately, this breaks the compiled js because the paths don't get resolved in the js. Wor... — committed to IntelliTect/Coalesce by ascott18 6 years ago
- :building_construction: Remove path mapping All declarations are broken with path mapping. Remove the useless feature that break all path in declaration files. Microsoft/TypeScript#10866 has been cl... — committed to gluons/vue-thailand-address by gluons 6 years ago
- https://github.com/Microsoft/TypeScript/issues/10866 — committed to FRC-3313-Team/scouting-back by LouieK22 5 years ago
- Add option path mapping Does not work currently due to Microsoft/TypeScript#10866 — committed to hristinaStanoeva/CatProject by PetarMetodiev 5 years ago
Can someone tell me what the point of this feature is if the pathnames emitted are actually incorrect? That is to say, if the TypeScript compiler is happy with it, but the end result isn’t runnable - what’s the use case for this feature?
I love TypeScript but this is insanity.
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.
Can this not just be added as a compiler option? Clearly it’s a popular request. Knowing nothing of the workings of the compiler, shouldn’t implementing it be super simple? Why force us to jump through hoops elsewhere when it can be so easily solved directly with the TypeScript compiler, where it makes the most sense?
I’m a little confused on this issue. It has been closed and labelled ‘Working as Intended’. Am I to understand Typescript is intended to output invalid source? Seems odd.
Beggars can’t be choosers, but using Typescript avoids many frustrating aspects of vanilla JS and I count relative imports (‘…/…/…/…/…/utils/parser’) to be one of them. It would be amazing if Typescript could clean these up!
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.Summoning the top five TypeScript contributors: @ahejlsberg @andy-ms @DanielRosenwasser @sandersn @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.
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 docs does not say a thing about having to use “loaders that allow remapping” whatsoever.
@mhegazy Can you or someone else let us know if now two years later maybe the TypeScript team would possibly take a look at this again and reconsider?
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:@mhegazy I expected it to work directly with node. It’s for a backend application. Is @kitsonk correct in stating that this is working as intended and typescript will not rewrite module paths?
@codeitcody Seems like it. It’s dumb that it would output something that simply doesn’t work without some third-party package but that’s the reality.
This issue has been around for 2 years and has no official word on whether it’s going to be implemented or not.
Considering this is required and basic functionality to use one of the best features of TypeScript in your Node.js projects, it’s pretty awful how it is being treated.
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?
We had the same problem at Dropbox and open-sourced this transformer https://github.com/dropbox/ts-transform-import-path-rewrite
@duffman
Highly disagree. Unless you were joking, I really couldn’t tell.
TypeScript should compile code that works without needing a third-party tool to complete the job that was only partially implemented into the native compiler.
I seriously don´t understand why this thread goes on and on and on… We all know about the “path hell”, and that you (by using aliases) can really clean up that mess, everyone in this thread knows this!
The aliases are interpreted by the TypeScript compiler, it compiles exactly as it should, it should most definitely not poke around in the resulting javascript, if you want to use aliases you will have to solve this yourselves!
…or start threads at Apple, Google and Microsoft asking them to implement functionality in their JavaScript engines so that they can interpet your aliases 😉
The TypeScript compiler does exactly what it should do!
If you are working in the Angular world the road is paved, if you want to run your code directly in Node you will need a tool to resolve the paths, and I have made such tool just for you, it´s been used in production for over a year now, it´s being used by the largest newspaper here in Sweden, I made this so that you can go bare bone with Node, I´m not trying to sell anything here, I don´t make money from this 😃
And yes, there are tools like “tsmodule-alias” and similar hacks, you can actually make it work if you are very very careful, but it´s a mess, there are workarounds using ts-node, shell scripts etc etc…yadda yadda
I finally felt that enough is enough so I locked myself away and made TsPath the compile time aliases
#> npm install -g tspatj #myproject> tsc #myproject> tspath
or
#myproject> tspath --f headless (proved very useful on the build server)
and then you´re done, your javascript files now have the correct relative paths, isn´t that what we want here?
Cheers! 😃
https://www.npmjs.com/package/tspath
Den sön 13 jan. 2019 kl 22:20 skrev Fabio Spampinato < notifications@github.com>:
Welcome to the club @def14nt. We’re a happy group of dreamers, starry-eyed as we gaze into a better future, patiently awaiting the day when TypeScript will implement the simple and sensible compiler option to make our lives easier. When that day finally is upon us, be sure to check the sky for the portly pink bodies of the pigs as they majestically fly away into the sunset on their newfound wings.
I don’t get it. Even with me knowing little about the TS codebase, this shouldn’t be hard to implement. I’ve just started using a shared project with client and server… why does TS present the paths functionality in the first place, then makes me jump through hoops to actually use it? Why does TS assume that I want to use a bundler/loader with every project I make? I’m trying to use TS to simplify my projects, not tack on more tooling libraries to compensate for a 90% implemented TS feature.
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 😞
You really don´t understand this, do you? The code is not broken, if it´s broken it is because you have configured the compiler to generate code that your “platform” does not support, in this case, aliases!
In your case, don´t use aliases, “you” don´t support them, seriously!
Even if this would be a 1 line fix (of course that´s not the case) it´s a matter of what a compiler should and should not do! This feature has been added in order to SUPPORT LOADERS not the other way around, read up on Path Mapping in the official documentation, so again, you are using it wrong!
Again, this feature is for Loaders/Resolvers, you have misunderstood how it works, so no, Microsoft should not alter the compiler so that you can paste aliases without an environment that supports it!
Den tis 15 jan. 2019 kl 04:41 skrev Fabio Spampinato < notifications@github.com>:
This is a feature which makes the compiler output broken code, code that could be working if they only wrote 1 line of code for properly resolving those paths.
The fact that TS needs an external bundler just so that the outputted code can be executed is plain ridiculous.
If this thread was full of people requesting that
tscalso do minification or some such, I’d agree with you. However it isn’t. It’s people requesting that the compiler generate executable code. I really don’t think that’s too much to ask from a compiler, do you?install and run “tspath” in your project folder… https://www.npmjs.com/package/tspath
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 fromtsconfig.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:.babelrc:https://austinknight.com/wp-content/uploads/2015/04/DesignVSUX.jpeg
Please help to upvote this post on Reddit: https://www.reddit.com/r/typescript/comments/a07jlr/path_maps_cannot_be_resolved_by_tsc_works_as/ Don’t know why it needs this huge discussion here. It should be easy to solve this bug. An option in tsconfig and everyone can decide if he want’s the current behavior (for whatever reason) or a working approach.
Well, isn’t this a nice problem to fall upon.
It does seem very counterproductive to have a feature that essentially renders your app unusable without jumping through hoops (i.e installing more dependencies to workaround the issue).
@ef-carbon/tspmI 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.
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.
I’ve created a compile-time solution where you can continue using
tsc. https://github.com/joonhocho/tscpathsMicrosoft/TypeScript#15479 (comment)
+1!
Take a look at https://github.com/momoThePug/tsmodule-alias
2018-05-31 15:04 GMT-05:00 edufschmidt notifications@github.com:
similar response https://github.com/Microsoft/TypeScript/issues/9910#issuecomment-234729007
Just look at how many times this has been referenced… What a waste of time and attention for so many people.
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”?!?!
Development team should add support for alias resolution. I suggest add a key for compiler resolution in tsconfig.
It would be nice Microsoft!!!
We beg you, we need your help to improve applications with alias.
😦 everybody here is sad and angry(, and hungry) because of lag of consistency. Typescript is awesome, I love it…
We Love it!
Best regards a Homeless developer…
El mar., 15 de ene. de 2019 08:02, Mike S. notifications@github.com escribió:
By the way, my opinion is following:
As aliases are builtin in compiler and compilation of project with them is OK. It may make users think, that it works way it’s suggesting (and this issue is pretty much good proof I’m right). It even seems illogical - why something works in “official” editor (vscode - especially when using “auto import” feature, vscode uses aliased path), why copiler also works OK, when resulting code is not working? Saying “js engine don’t support it” makes me wanting to ask even more - wasn’t TS meant as a thing to mitigate some of JS “problems”?
I would expect one of two solutions of this:
Saying “it’s correct behavior” is, I think, wrong. It’s not. TS is not assembly language, not even a C/C++.
I agree with you. I think, TS was developed for frontend, 'cause webpack already implements quite well ts alias paths, and with Requirejs is also the same thing. But for Nodejs projects it’s so hard. 😦
El jue., 20 de sept. de 2018 02:50, Josh Pike notifications@github.com escribió:
I too managed to get this working with module-alias, with the downside that I have to keep track of my aliases both within tsconfig.json and package.json. Has anyone found a simpler solution?
The solution pointed out by @mattyclarkson also works, but I couldn’t find a way of using it side-by-side with ts-node. Any ideas?