-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Using baseUrl and paths on node #9259
Comments
this is already supported in TS today. if you run tsc it should resolve your module. i would say this is specific to how ts-node works. |
Yes. Tsc compiles successfully. But as you mentioned in the past, there is no change(path rewrite) on the emitted js files. If I run the test js file through node, would result in the same error |
But that is the purpose of these settings, to allow module loaders than can remap modules to remap modules. The CommonJS loader in NodeJS was not designed as a module loader that is configurable in this way, because the base assumption is that you would have access to a file system with a very deterministic resolution pattern for resolving modules. I personally would not want TypeScript to re-write MIDs, but giving the flexibility to resolve modules in the way my loader will resolve modules at run-time, which TypeScript 2.0 does perfectly. Especially with CJS under NodeJS, because the default loader is not configurable in that sense, any remapping by TypeScript would require making invalid assumptions about the run-time environment and likely result in code that does not work at run-time and certainly not a distributable package that could be consumed by anyone using Because of the assumptions made by the CJS loader in NodeJS we distribute our packages in UMD format and recommend people use an AMD loader that easily allows remapping, even when running under NodeJS. But knowing that there is a "cowpath" to CJS we include an |
Fully understand that is how it should be used, just that I found this use case interesting because it creates a mental disconnect between what's appear to be working on the IDE but failed on runtime. One option is to add a |
To make sure I deliver my message correctly, I don't want to suggest a feature that doesn't have a real use case. In this case, it is like "I abuse the system and complain it doesn't work". Fully aware of that. Just want to open the discussion to see if this would lead to some interesting possibilities. 🌷 |
That seem clearly the domain for tooling outside of the scope of TypeScript. Especially considering the design goals:
And anti-goal:
|
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 This solution hooks node's To use, paste this tiny chunk of code at the top of your "main.ts". import * as path from 'path'
import * as fs from 'fs'
(function() {
const CH_PERIOD = 46
const existsCache = {d:0}; delete existsCache.d
const baseUrl = path.dirname(process['mainModule'].filename)
const moduleProto = Object.getPrototypeOf(module)
const origRequire = moduleProto.require
moduleProto.require = function(request) {
let existsPath = existsCache[request]
if(existsPath === undefined) {
existsPath = ''
if(!path.isAbsolute(request) && request.charCodeAt(0) !== CH_PERIOD) {
const ext = path.extname(request)
const basedRequest = path.join(baseUrl, ext ? request : request + '.js')
if(fs.existsSync(basedRequest)) existsPath = basedRequest
else {
const basedIndexRequest = path.join(baseUrl, request, 'index.js')
existsPath = fs.existsSync(basedIndexRequest) ? basedIndexRequest : ''
}
}
existsCache[request] = existsPath
}
return origRequire.call(this, existsPath || request)
}
})() |
@papercuptech This is brilliant. I modified your code and it worked like a charm in my isomorphic react project. (function () {
const baseUrl = path.join(cwd, tsConfig.compilerOptions.baseUrl);
const moduleProto = Object.getPrototypeOf(module);
const origRequire = moduleProto.require;
const pathKey = {};
for (const [key, value] of Object.entries(tsConfig.compilerOptions.paths)) {
pathKey[key.slice(0, -2)] = value[0].slice(0, -2);
}
moduleProto.require = function (request) {
if (request[0] === '@') {
const pathName = request.match(/(@.*?)\//)[1];
const relativeToBase = path.relative(path.dirname(this.id), baseUrl);
existsPath = relativeToBase + '/' + pathKey[pathName] + request.slice(pathName.length);
return origRequire.call(this, existsPath || request)
}
return origRequire.call(this, request);
};
})(); Here I'm assuming that the "paths": {
"@pages/*": ["./ui/pages/*"],
"@components/*": ["./ui/components/*"],
}, where the keys in the paths start with |
@papercuptech So many people on the internet want this. Would be a neat idea to implement this into a stable package possibly. |
Maybe you'd be interested in https://github.com/jonaskello/tsconfig-paths? |
Yes. Thank you. |
The problem with this is, that Here is a link to another issue about it #18951 |
Re-writing module names is really quite dangerous and not something TypeScript should involve itself with. Providing the right tooling to make what is written work like it would at run-time under different loaders is the most logical solution. TypeScript is not a module loader. While the default loader with NodeJS does not support remapping, there are many loaders and bundlers that run under NodeJS that provide a lot of flexibility and configuration. We should tools what they are designed for. |
Probably, it would be good to have open plugin API for the compiler (there is one not stable yet) and convenient way of applying plugins to the standard compilation process (there is none as I'm aware of), something like babel has. This would allow solving such tasks. |
Typescript should give an option to allow "directory expansion" for path alias defined in "tsconfig.json" and used in module importation. it would be nice to have something like:
TS Code: Compilation: |
Oh wow I just got burned by this - thought it was a shortcut for easy readability. Is there an open request for similar functionality to paths but like shortcuts instead? |
@arogozine you could instead try to use one of the following three strategies:
You can define an "index.ts" inside your "module" or "submodule directory", then you should "export" many "alias import" as you want, for instance, if you have an "AnimalModule" with an structure like:
// DogModule/index.ts:
// CatModule/index.ts:
// IguanaModule/index.ts:
Then you can use any module defined before like this:
And Also you can now define submodules declarations inside a parent module like the following example: // AnimalModule/index.ts:
Using AnimalModule definition like this:
UPDATE: As @unional said, it's better to re-export:
|
As a side note, it would be better to not rely on namespacing. i.e. // instead of
import * as cat1 from "./cats/kind1/cat1.ts";
import * as cat2 from "./cats/kind2/cat2.ts";
import * as cat3 from "./cats/kind3/cat3.ts";
export {cat1, cat2, cat3};
// just re-export
export * from './cats/kind1/cat1.ts'
export * from './cats/kind2/cat2.ts'
export * from './cats/kind3/cat3.ts' Tree shaking and namespacing doesn't work well together. |
@unional awesome! It's a better way, thanks. |
I notice the feature is for
requirejs
andsystemjs
. And as this comment said, the emitted js code is unchanged by the configuration:#5039 (comment)
So the primary usage is to resolve packages in various locations (e.g.
jspm_packages
) for transpilation.I have the following interesting use case. It worked for me so far as I was using
jspm
, i.e. the actual module loading happens on the browser. However it fails when I try to do the same usingts-node
(fail because it runs onnode
and the reason above).Is there a way to support this?
Here is the example:
i.e., using
paths
so tests can reference the source as if it is a regular module.🌷
Reference issue on
ts-node
: TypeStrong/ts-node#138The text was updated successfully, but these errors were encountered: