-
-
Notifications
You must be signed in to change notification settings - Fork 8.4k
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(v2): Provide @theme
module alias type definitions for theme-classic
#3123
Conversation
Deploy preview for docusaurus-2 ready! Built with commit d2c19c7 |
@theme
module alias type definitions for theme-classic@theme
module alias type definitions for theme-classic
@theme
module alias type definitions for theme-classic@theme
module alias type definitions for theme-classic
🤪 sorry for the review delay, I have a hard time understanding what's going on in this PR, and still have some other PRs to review first |
I'm converting it to draft right now since I found that it will break TypeScript swizzling. I might need more time to think about the best approach. |
Closing since approach in #3267 should be the way to go. |
Motivation
Now we finally migrated the theme-classic code to TypeScript, we are finally in a good position to generate high-quality type definitions directly from source.
With this PR, we can finally get good IDE integrations:
Implementation
I have to admit that the current implementation is quite hacky due to lack of native support from TS. Therefore, I mostly consider this PR as a proof of concept implementation.
TypeScript already has some support for generating a bundled single d.ts file for all modules. However, its result is not directly usable.
For example, this is a snippet of what you get:
Several problems:
@theme/
to match Docusaurus' webpack type alias./index
at the end.import './styles.css'
. They cannot be understood by TypeScript/Fortunately, this is quite easy to detect and I solved that with a hack by doing string substitution:
The second issue is where we put the generated type definition file. Ideally, we want to use the generated file intheme-classic
as well. Therefore, we should reference it insidepackages/docusaurus-theme-classic/src/types.d.ts
. However, this creates a cyclic dependency:tsc
needs this generated file to compile stuff, and to generate this file we needtsc
to compile a project that includes it.My hacky way to break this cyclic dependency is to initial create an empty file, lettsc
generate the type definition elsewhere, do some string substitution and then rewrite the file in the correct place. It's safe to start with an empty d.ts, since the catch-all definitiondeclare module '@theme/*';
ensures that we have anany
module to start with.I would like some ts expert feedback on how to make it less hacky, but that's the best way to generate the type definition that I can think of.The second problem is how we can use the generated type definition on theme-classic itself. Unfortunately, we can't without introduce nasty hack or cyclic dependencies between source and types. The crossed-out text above describes a hacky way to do it which I abandoned now.
Fortunately, I found a much more principled way. We can configure
paths
intsconfig.json
to make TS translate imports that starts with@theme-classic/
tosrc/theme
. Note that the prefix has to be@theme-classic/
instead of@theme
, because otherwise the type of local module will be shadowed by the catch-alldeclare module '@theme/*';
in@docusaurus/module-type-aliases
. Since we in effect changed the import, we need to do something at the transpilation stage to undo the source level change. My solution is to write an inline babel plugin inbabel.config.js
that transforms@theme-classic/*
import back into@theme/*
import.As a proof-of-concept, I changed the
@theme
imports ofBlogPostPage
to@theme-classic
import. You can see the compiled output to check that it has been correctly transformed back into@theme
import.Have you read the Contributing Guidelines on pull requests?
Yes
Test Plan
CI passes.