Skip to content
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

Feature: Custom module resolution #2771

Closed
pauldraper opened this issue Nov 17, 2020 · 5 comments · Fixed by #3516
Closed

Feature: Custom module resolution #2771

pauldraper opened this issue Nov 17, 2020 · 5 comments · Fixed by #3516
Labels
enhancement New feature or request package: parser Issues related to @typescript-eslint/parser package: typescript-estree Issues related to @typescript-eslint/typescript-estree

Comments

@pauldraper
Copy link

Bundlers often allow custom module resolution. Some build tools cache .d.ts files to save type checking work.

The TS Compiler API allows TS users to customize module resolution via CompilerHost#resolveModuleNames.

I'd like something similar to https://github.com/benmosher/eslint-plugin-import#resolvers to allow me to provide my own module resolver.

@pauldraper pauldraper added package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for maintainers to take a look labels Nov 17, 2020
@bradzacher
Copy link
Member

Could you please explain more about what you need and why?

What specifically needs caching? Why does it need to be cached?
What are you trying to achieve?

@bradzacher bradzacher added awaiting response Issues waiting for a reply from the OP or another party and removed triage Waiting for maintainers to take a look labels Nov 17, 2020
@pauldraper
Copy link
Author

pauldraper commented Nov 17, 2020

Webpack and Babel are two examples of tools with customized resolution. I think https://github.com/benmosher/eslint-plugin-import#resolvers is decent proof of people wanting a variety of module resolvers.


In my particular case, I want to build a Bazel integration for typescript-eslint. Bazel is a polyglot build tool for monorepos. There are two issues with module resolution:

(a) The node_modules file layout is tricky to achieve and prevents Bazel from download packages lazily as required by build targets.
(b) For best performance, .d.ts declarations of dependencies are cached as outputs on disk, reducing future work done by the TS compiler.

I need to flexibility to resolve these modules in these various places. It's possible to write a bunch of symlinks/hardlinks but that's complex and not great for performance.

So I've implemented Node.js Module.requireFilename, TS resolveModuleNames, Rollup resolveId, ESLint import/resolver, etc.

One tool that doesn't allow custom resolution is TS ESLint.

@bradzacher
Copy link
Member

bradzacher commented Nov 17, 2020

Webpack and Babel are two examples of tools with customized resolution. I think benmosher/eslint-plugin-import#resolvers is decent proof of people wanting a variety of module resolvers.

the import resolvers exist because eslint-plugin-import is a general-purpose plugin which has to support all js-like languages and all styles of module resolutions.
It makes no assumptions about how you resolve your modules so that it can support everything.


OTOH we are built on top of TS - so we support exactly what TS supports out of the box.
This is substantially more limited in scope because it is
essentially it supports relative, node style resolution, and anything its paths option supports.

We've never had a usecase for anything more than that because 99.99999% of users don't create custom build scripts on top of the compiler API - paths satisfies most usecases.


Happy to accept a PR if you would like to add in a parserOptions for this.
Something like this solution, maybe?

moduleResolver: string.
This option would accept an absolute (or relative to CWD) path to a JS file.
This JS file must export default (or export =) the following signature:

interface ModuleResolver {
  version: 1;
  resolveModuleNames: ModuleResolver;
}

Where ModuleResolver is the function type listed here: https://github.com/microsoft/TypeScript/blob/76cf8fd78b204b9153192e2d8ea7cb2ff8a4a972/src/compiler/watchPublic.ts#L102-L103


Off topic:

(b) For best performance, .d.ts declarations of dependencies are cached as outputs on disk, reducing future work done by the TS compiler.

How much time does this actually save?
On the surface it seems like it would cost you time and memory in a lot of cases as

@bradzacher bradzacher added enhancement New feature or request package: parser Issues related to @typescript-eslint/parser package: typescript-estree Issues related to @typescript-eslint/typescript-estree and removed awaiting response Issues waiting for a reply from the OP or another party package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin labels Nov 17, 2020
@pauldraper
Copy link
Author

pauldraper commented Nov 17, 2020

OTOH we are built on top of TS - so we support exactly what TS supports out of the box.

Sure, I get that.

FWIW implementing the lower-level API described in #1442 would also meet my needs.

paths satisfies most usecases.

I'd have to think if node_modules stuff (multiple versions of a module name) could be handled.

How much time does this actually save?

For big monorepos (5,000+ files), a lot. The majority of a TS compile is type inference and checking.

And not only does reusing .d.ts files save re-processing unchanged dependencies, it also allows short-circuited compile if the declaration signature does not change (like a change within a function).


Happy to accept a PR if you would like to add in a moduleResolver for this.

Sounds good.

@bradzacher
Copy link
Member

In #3484 @uniqueiniquity has added a new API which enables you to really do "whatever you want".

parserOptions.programs accepts an array of ts.Programs. So you can build on top of the TS compiler API to create a program with whatever semantics or features you need for your project.

The only requirement we place on it is that all files being linted (and their dependencies, for typechecking purposes) exist within the ts.Program.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 12, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request package: parser Issues related to @typescript-eslint/parser package: typescript-estree Issues related to @typescript-eslint/typescript-estree
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants