Implements a custom resolveModuleName option#862
Implements a custom resolveModuleName option#862johnnyreilly merged 11 commits intoTypeStrong:masterfrom
Conversation
src/interfaces.ts
Outdated
| export type CustomResolveModuleName = ( | ||
| moduleName: string, | ||
| containingFile: string, | ||
| options: typescript.CompilerOptions, |
There was a problem hiding this comment.
Could this be called compilerOptions also please?
src/servicesHost.ts
Outdated
| compilerOptions, | ||
| moduleResolutionHost | ||
| ); | ||
| const tsResolver = (moduleName: string, containingFile: string, compilerOptions: typescript.CompilerOptions, moduleResolutionHost: typescript.ModuleResolutionHost) => |
There was a problem hiding this comment.
Given tsResolver is a pure function could we break this out in to a separate function please? That saves creating a new function each time this runs.
|
Thanks for this! Could you address the comments and fix the linting errors that are showing up in CI please? |
|
Regarding testing, it would be good to implement an execution test to cover this. You can find out more about these here: https://github.com/TypeStrong/ts-loader/blob/master/test/execution-tests/README.md A good example to clone as a basis for your test might be this one: https://github.com/TypeStrong/ts-loader/tree/master/test/execution-tests/3.0.1_projectReferences or https://github.com/TypeStrong/ts-loader/tree/master/test/execution-tests/3.0.1_resolveJsonModule |
src/servicesHost.ts
Outdated
| const tsResolution = customResolveModuleName | ||
| ? customResolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionHost, tsResolver) | ||
| : tsResolver(moduleName, containingFile, compilerOptions, moduleResolutionHost); | ||
| ? customResolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionHost, applyTsResolver.bind(null, compiler)) |
There was a problem hiding this comment.
I hadn't expected the .bind(null, compiler) would be necessary... I'm guessing it is? What happens without it? Presumably some kind of this issue?
There was a problem hiding this comment.
No, we simply need the compiler variable to be able to call compiler.resolveModuleName (and compiler is obtained from instance, which isn't a global)
| { | ||
| "compilerOptions": { | ||
| "noEmitOnError": true, | ||
| "resolveJsonModule": true |
There was a problem hiding this comment.
can we remove the "resolveJsonModule": true please? It doesn't do any harm but it might lead someone who was reading the test to believe that it was necessary for resolveModuleName to work. (Not least because of the similarity in naming 😄 )
| import * as app from '../src/app'; | ||
|
|
||
| // We don't actually care about the result of the following operations; | ||
| // what we care about is typescript resolving json as modules |
There was a problem hiding this comment.
Could you amend the comment to reflect what the intention of the test is please?
There was a problem hiding this comment.
I left the comment because it's actually the same intent - we don't care about what is being built, just about TS being able to make the resolution
There was a problem hiding this comment.
Oh, I see a "json" is in the comment - will change it 👍
|
Good work on the changes @arcanis! I've a couple more comments that I've added just now. Well done on the execution test. Looks good! Question though: it looks like it's only resolving types from Does that sound sensible? Or have I misunderstood your intent? |
|
@johnnyreilly I wasn't entirely sure if the generated code had to be tested as well, since I wasn't sure whether ts-loader was entirely relying on TypeScript for the resolution or not (versus only using it for the type resolution, leaving the regular Webpack resolver setup the links between the packages). What do you think? |
Yes please!
It's a good question. https://github.com/TypeStrong/ts-loader/blob/master/src/resolver.ts Funnily enough, it's on my radar to try out using TypeScript for resolve module names resolution too, but as yet I haven't. See: #757 (comment) |
|
Let me know if that matches what you had in mind :) |
src/servicesHost.ts
Outdated
| containingFile, | ||
| compilerOptions, | ||
| moduleResolutionHost, | ||
| applyTsResolver.bind(null, compiler) |
There was a problem hiding this comment.
Seeing a .bind my perf spider sense is tingling!
https://stackoverflow.com/questions/42117911/lambda-functions-vs-bind-memory-and-performance
I wonder if we could switch this to a lamba instead? It'll be slightly more verbose but hopefully should perform better...
| @@ -0,0 +1,13 @@ | |||
| import * as app from '../src/app'; | |||
|
|
|||
| // We don't actually care about the result of the following operations; | |||
There was a problem hiding this comment.
This is not true actually; we do care about the result of the following operations! Can we amend the comment to make test intent clearer please? We care both about type resolution and that the code executes...
|
Thanks chap! I've put a few comments in and I've also fixed the failing comparison test on your branch. I think the execution test is better but it's still not quite what I had in mind; let me explain: As I understand it That being the case you'd likely not consume them with raw TypeScript files in; you'd either:
Or
If my understanding is correct then ideally our tests should be covering those scenarios rather than exporting raw .ts. It's possible my understanding of this feature is not quite right; feel free to set me straight! 😄 |
|
I think the first scenario you mention isn't relevant to I've updated |
|
Cool - thanks for that! I've just fixed up the linting errors; hopefully we should now see a clean CI 😄 Question: in the test you only make use of the That being the case, does it make sense for the All things being equal, I suspect we're pretty much there! |
|
Ping @arcanis 😉 |
|
Sorry, was flying yesterday 🙂 So it don't use those values yet (and I'm not too familiar with TS to know what they're used for, tbh), but since the TS resolveModuleName hook requires all four of them I figured it'd make sense to also accept them, since they're easily available to us while the hook doesn't have any way to know them otherwise l. One particular advantage is that it will make it easier for different projects/loaders to use the same custom resolveModuleName implementation (which would be a bit more difficult if they were each expecting a different set of parameters). |
|
That sounds reasonable! Do you have anymore work to do on this or is this ready to merge from your perspective? |
|
Nope, I think it's ready on my side! |
|
Nice! Thanks for your work! Would you be able to update the That'll help me as I look to merge / publish this. |
d351782 to
bee1c37
Compare
|
Here you go! Minor, right? 👍 |
|
Thanks! Published with v5.3.0 |
Solves #861 - This PR adds a new
resolveModuleNameoption that can be used to help TypeScript figure out the location of the files on the disk. It mimics the TypeScript API.I published a first implementation as part of ts-pnp, and it can be tested using the pnp-webpack-plugin which provides an integration.
I'm not too sure how and where I should test this - any advice?