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
feat: Add support for TypeScript config files #117
base: main
Are you sure you want to change the base?
Changes from 3 commits
5e5fc4c
50676fa
9ab30b5
c0c0714
247393f
d13d556
5e68795
24dac1d
3863834
d5e16db
0e09c10
3c37a94
e0da6c3
24b0893
ef591fc
7dfea39
de7e87a
fb612ed
f60a15c
fef64ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
- Repo: eslint/eslint | ||
- Start Date: 2024-03-09 | ||
- RFC PR: <https://github.com/eslint/rfcs/pull/117> | ||
- Authors: [Arya Emami](https://github.com/aryaemami59) | ||
|
||
# Add Support for TypeScript Config Files | ||
|
||
## Summary | ||
|
||
Add support for TypeScript config files (`eslint.config.ts`, `eslint.config.mts`, `eslint.config.cts`) | ||
|
||
<!-- One-paragraph explanation of the feature. --> | ||
|
||
## Motivation | ||
|
||
<!-- Why are we doing this? What use cases does it support? What is the expected | ||
outcome? --> | ||
|
||
The primary motivation for adding support for TypeScript configuration files to ESLint is to enhance the developer experience and accommodate the evolving JavaScript ecosystem. As TypeScript's popularity continues to grow, more projects are adopting TypeScript not only for their source code but also for their configuration files. This shift is driven by TypeScript's ability to provide compile-time type checks and IntelliSense. By supporting `eslint.config.ts`, `eslint.config.mts`, and `eslint.config.cts`, ESLint will offer first-class support to TypeScript users, allowing them to leverage these benefits directly within their ESLint configuration. | ||
|
||
## Detailed Design | ||
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
<!-- | ||
This is the bulk of the RFC. | ||
|
||
Explain the design with enough detail that someone familiar with ESLint | ||
can implement it by reading this document. Please get into specifics | ||
of your approach, corner cases, and examples of how the change will be | ||
used. Be sure to define any new terms in this section. | ||
--> | ||
|
||
The goal is to seamlessly support TypeScript configuration files in ESLint. To achieve this, ESLint will need to recognize and parse TypeScript configuration files in the same way it does for JavaScript configuration files. This will involve creating the configuration file resolution logic to recognize `.ts`, `.mts`, and `.cts` files as valid ESLint configuration files. We will need to treat `eslint.config.mts` files as ECMAScript Modules (ESM) and `eslint.config.cts` files as CommonJS (CJS). The module resolution for `eslint.config.ts` files will depend on the `type` field in the nearest `package.json`. The maintainers of ESLint have raised some valid concerns some of which include: | ||
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
- There should not be extra overhead for JavaScript users. This means this change should not have a significant impact (if any at all) affecting users who use plain JavaScript config files. | ||
- The external tools that are used to parse the config files written in TypeScript should not create side effects. Specifically, it is imperative that these tools do not interfere with Node.js's native module resolution system by hooking into or altering the standard `import/require` mechanisms. This means tools like [`ts-node`](https://github.com/TypeStrong/ts-node) and [`tsx`](https://github.com/privatenumber/tsx) might not be suitable for this purpose. | ||
|
||
So far the tool that seems to be the most suitable for this purpose is [`jiti`](https://github.com/unjs/jiti). It does not introduce side effects and performs well, demonstrating its reliability. It also seems to be more battle-tested given some established frameworks such as [Nuxt](https://github.com/nuxt/nuxt) and [Tailwind CSS](https://github.com/tailwindlabs/tailwindcss) have been using it to load their configuration files. | ||
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Documentation | ||
|
||
<!-- | ||
How will this RFC be documented? Does it need a formal announcement | ||
on the ESLint blog to explain the motivation? | ||
--> | ||
|
||
The documentation for this feature will be added to the [ESLint User Guide](https://eslint.org/docs/user-guide/configuring) page. The documentation will explain how to use TypeScript configuration files and the differences between JavaScript and TypeScript configuration files. | ||
|
||
## Drawbacks | ||
|
||
<!-- | ||
Why should we *not* do this? Consider why adding this into ESLint | ||
might not benefit the project or the community. Attempt to think | ||
about any opposing viewpoints that reviewers might bring up. | ||
|
||
Any change has potential downsides, including increased maintenance | ||
burden, incompatibility with other tools, breaking existing user | ||
experience, etc. Try to identify as many potential problems with | ||
implementing this RFC as possible. | ||
--> | ||
|
||
This change will most likely require at least one external tool as either a dependency or a peer dependency. | ||
|
||
## Backwards Compatibility Analysis | ||
|
||
<!-- | ||
How does this change affect existing ESLint users? Will any behavior | ||
change for them? If so, how are you going to minimize the disruption | ||
to existing users? | ||
--> | ||
|
||
This goal is to minimize the disruption to existing users. The primary focus is to ensure that the existing JavaScript configuration files continue to work as expected. The changes will only affect TypeScript users who are using TypeScript configuration files. The changes will not affect the existing JavaScript configuration files. | ||
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Alternatives | ||
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
<!-- | ||
What other designs did you consider? Why did you decide against those? | ||
|
||
This section should also include prior art, such as whether similar | ||
projects have already implemented a similar feature. | ||
--> | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there is a community project: https://github.com/antfu/eslint-ts-patch to support it. would like to hear the author :) / @antfu There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It uses jiti to support ts file. Which already mentioned #117 (comment) that it doesn't currently support top-level await. I would personally recommend using https://github.com/egoist/bundle-require instead which is more robust and will respect tsconfig.json. The downside is that it would introduce There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like @eslint/config-inspector uses bundle-require as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the inspector uses that because we need to know the dependencies of the config to do automatic reloads. Supporting TS was a free side-effect. Even if ESLint doesn't need information on dependencies, I think it's still a good way to support TS. Vite uses the same approach to load There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does These temp files are a major source of problems with vite, see vitejs/vite#9470. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that TLA shouldn't be a blocker for this. 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tsx is mentioned in the RFC as a non-viable alternative because it uses custom loaders. Does that also hold when There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally, I see TLA as a language spec requirement, and I don't think whether to support it should be up to whether we can imagine use-cases. But if we want evaluate usage, here are examples of TLA in configs (Vite, Rollup, Next, Jest, esbuild, etc):
But just to be clear, I'm only sharing it as an option. Personally, I would like to have popular compilers supported as optional peer dependencies to accommodate different preferences and environments. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Interesting. There are also ESLint configs that use TLA: https://github.com/search?q=path%3A%2Feslint%5C.config%5C.m%3Fjs%24%2F+%2F%5Econst+.%2B+%3D+await+%2F&type=code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is already a workaround for TLA available: export default (async () => {
await whatever();
}()); We |
||
## Open Questions | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When using the ts configs, does it check the ts type, or is it just erasure typings? |
||
|
||
<!-- | ||
This section is optional, but is suggested for a first draft. | ||
|
||
What parts of this proposal are you unclear about? What do you | ||
need to know before you can finalize this RFC? | ||
|
||
List the questions that you'd like reviewers to focus on. When | ||
you've received the answers and updated the design to reflect them, | ||
you can remove this section. | ||
--> | ||
|
||
1. How is caching going to work with TypeScript config files? | ||
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
2. Should we look at the nearest `tsconfig.json` file to determine the module resolution for `eslint.config.ts` files? Most likely not, but it's worth considering. | ||
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
3. Should we allow some sort of interoperability between JavaScript and TypeScript configuration files? For example, should we allow a TypeScript configuration file to extend a JavaScript configuration file and vice versa? | ||
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
4. Should we allow `eslint.config.ts` to be able to use `export default` as well as `module.exports` (might be related to [TypeScript's automatic Module Detection](https://www.typescriptlang.org/tsconfig#moduleDetection))? | ||
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Help Needed | ||
|
||
<!-- | ||
This section is optional. | ||
|
||
Are you able to implement this RFC on your own? If not, what kind | ||
of help would you need from the team? | ||
--> | ||
|
||
I will be implementing this feature. I will need help from the team to review the code and provide feedback. | ||
|
||
## Frequently Asked Questions | ||
|
||
<!-- | ||
This section is optional but suggested. | ||
|
||
Try to anticipate points of clarification that might be needed by | ||
the people reviewing this RFC. Include those questions and answers | ||
in this section. | ||
--> | ||
|
||
## Related Discussions | ||
aryaemami59 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
<!-- | ||
This section is optional but suggested. | ||
|
||
If there is an issue, pull request, or other URL that provides useful | ||
context for this proposal, please include those links here. | ||
--> | ||
|
||
[This PR](https://github.com/eslint/eslint/pull/18134) is related to this RFC. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does the feature interact with the CLI option
--config
for specifying a config file?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have tested it, so far it seems to work pretty well actually, especially with v9. I'm probably going to write a bunch of tests as well to see if there are any edge cases but so far so good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to explain what the behavior is when specifying TS or non-TS config files of varying file extensions through that option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't behave any differently, same as before. You can do
eslint . --config=eslint.config.ts
oreslint . -c eslint.config.ts
and they just work. Same as with aeslint.config.js
file.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add that into the RFC?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added it to the open questions, is that fine?