You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Explore enabling type acquisition for web TS Server #172887
We now have TSServer running in web environments, but it is currently limited to single file intellisense. It would be nice if we could also offer some IntelliSense for third party packages that are imported in the current file.
If a user is trying out react for example, we should be able to offer IntelliSense for React and ReactDOM:
Lots of open questions about how this should behave and how we can implement it:
Do we try looking in the user's package.json or at their tsconfig when determining which types to use?
Do we handle packages that bundle their own typings?
How far should type acquisition go? If one type package references another, do we pull that in too?
Would this work differently in JS files vs TS files? Type acquisition works differently for the two on desktop, but on web I think we'd want the behavior to be more similar
Could we use a service like unpkg for this? Or could we stand up a more specialized service that just service up a single types file for a given package?
Can the type acquisition be async like it is on desktop?
Could we use a service like unpkg for this? Or could we stand up a more specialized service that just service up a single types file for a given package?
Having NPM provide a CDN like how unpkg works would be a nice solution for this (because I have this same issue in the TS playground)
I recently re-wrote the ATA for the Playground ( microsoft/TypeScript-Website#1997 ) in what I think is a pretty good conceptual pattern:
TypeScript can probably already give you a list of dependencies it knows about from the package.json, and the source files it has read (in the playground I don't have this, so I use ts.preprocessFile to extract that)
You make an API call which gets a list of all the files in each module tarball (I used jsDelivr's) from which you can figure out the list of .d.ts files you need to download, or that you need to check DT.
If you need to check for @types/module and grab the .d.ts files for that module
Loop through all the downloaded .d.ts files and recurse grabbing their modules etc
It's not exactly like that in practice (you need the version number before you can make that API call to jsdelivr) - but that's good enough and you can read the implementation linked above for more details. The implementation of the TypeScript Playground ATA is built for third parties, so you could be a consumer of @typescript/ata when that PR lands.
An ideal state for VS Code which would keep this entirely first-party, is that the npm registry adds two APIs like:
https://registry.npmjs.org/npm/:version_or_tag/contents which returns some sort of file list
https://registry.npmjs.org/npm/:version_or_tag/file/package.json which returns a CDN'd file from the tarball (in this case the package.json)
Or vscode creates an API which proxies these APIs to jsdelivr (they're real nice folks, I can make an intro if needed) which allows for other implementations behind the scenes in time.
After discussion, we'd like to move the core auto import implementation to VS Code
Orta Therox (@orta) I looked into using preProcessFile to get all the imports but it looks like this isn't currently exposed over the TSServer protocol? Is that correct?
After thinking about this more, I am also wondering if using preProcessFile is too low level. We can debounce how often we end up calling preProcessFile to avoid calling it on every key stroke, but it feels like it would make more sense if TS could tell us what auto imports it needs and then VS Code could then go and resolve them
The problem I'm running into now though is telling TS that jquery in import 'jquery' maps to a given file the VS Code has opened against the TypeScript server
Here's how the files are currently opened after ATA has completed (I'm using the paths that TS server sees):
^/memfs/sample-folder/file.js — This is the file that the user has opened up
import*as$from'jquery'
Then we have a list of jQuery d.ts files that VS Code has opened up with the correct content:
All of these are in-memory files so TS Server cannot read them directly. I believe we also have to keep the different scheme (memfs vs ts-typings) as part of the implementation on the VS Code side
What type of API do you think we need to get typescript to understand that import 'jquery' should resolve to ^/ts-typings/node_modules/@types/jquery/JQuery.d.ts?
There's a similar tension in doing the full TypeScript compile in the ts-vscode playground - I wonder if a reasonable strategy lays in making the TypeScript web server smarter, and keeping some of the file content inside that. As it exists, there is no way to influence what is available to that TSServer:
I think somewhere there needs to be a vfs map which the tsserver prioritises for sys lookups for dirs/files and it might need to be insider the web server. That could be controlled via additional tsserver actions/events.
What type of API do you think we need to get typescript to understand that import 'jquery' should resolve to ^/ts-typings/node_modules/@types/jquery/JQuery.d.ts?
I think that might get tricky with the schema change, I think you'd need to hardcode that somehow into the TS web server code somehow (for examples it is kinda safe that all paths with @types could be treated that way)
With my current approach, on web all TS files are opened against as in-memory resources. This means that TS knows the file content but should not try to read these files from disk. Are you proposing a different approach where readFile would be needed?
For the second part, who is the best point of contact to discuss this with? If needed I think we could rewrite the paths that VS Code sends to TS Server to make the project system happy, but I'd like to explore a proper solution first
My current proposal would be a new TS Server api that let a client explicitly pass global typings files to the TypeScript Server. This could be used both to implement ATA, and also for applications like Office Scripts where you have a VS Code extension that wants to augment the global typings in JS files
Some of this discussion also gets into our discussions around virtual file system support for vscode.dev
One idea: could a client for example tell TS Server about a type root directory and then the server would simply treat any files opened under this directory as typings
From a protocol point of view, this would look something like:
Client passes a root directory for typings to TS Server: configure { typeRoots: ['^/ts-typings'] }
Client then opens files under this types root: updateOpen { path: '^/ts-typings/jquery/jquery.d.ts' }
When resolving imports, the server then looks in the types root.
Since the server only has an in-memory representation of these read files/folders, the server may have to construct its own little virtual file system representation to implement this
I'm not sure that you need to special case the vfs as only being typings specifically, for the playground ATA we emulated having files in node_modules/@types/jquery/index.d.ts which meant it was picked up by the default behavior in TypeScript
If you have a generic system to put vfs files into the web tsserver's sys then you can put files into the right place and it would automatically be respected by the rest of the tsserver
Activity
mjbvz commentedon Aug 3, 2021
Lots of open questions about how this should behave and how we can implement it:
Do we try looking in the user's
package.jsonor at theirtsconfigwhen determining which types to use?Do we handle packages that bundle their own typings?
How far should type acquisition go? If one type package references another, do we pull that in too?
Would this work differently in JS files vs TS files? Type acquisition works differently for the two on desktop, but on web I think we'd want the behavior to be more similar
Could we use a service like unpkg for this? Or could we stand up a more specialized service that just service up a single
typesfile for a given package?Can the type acquisition be async like it is on desktop?
orta commentedon Aug 4, 2021
Having NPM provide a CDN like how unpkg works would be a nice solution for this (because I have this same issue in the TS playground)
orta commentedon Aug 24, 2021
I recently re-wrote the ATA for the Playground ( microsoft/TypeScript-Website#1997 ) in what I think is a pretty good conceptual pattern:
ts.preprocessFileto extract that)@types/moduleand grab the .d.ts files for that module.d.tsfiles and recurse grabbing their modules etcIt's not exactly like that in practice (you need the version number before you can make that API call to jsdelivr) - but that's good enough and you can read the implementation linked above for more details. The implementation of the TypeScript Playground ATA is built for third parties, so you could be a consumer of
@typescript/atawhen that PR lands.An ideal state for VS Code which would keep this entirely first-party, is that the npm registry adds two APIs like:
https://registry.npmjs.org/npm/:version_or_tag/contentswhich returns some sort of file listhttps://registry.npmjs.org/npm/:version_or_tag/file/package.jsonwhich returns a CDN'd file from the tarball (in this case thepackage.json)Or vscode creates an API which proxies these APIs to jsdelivr (they're real nice folks, I can make an intro if needed) which allows for other implementations behind the scenes in time.
MartinKolarik commentedon Sep 2, 2021
We are already watching - ping me any time if needed 😄
orta commentedon Oct 13, 2021
The Playground ATA re-write is now available on npm at @typescript/ata and deploying to the web as we speak.
ATA for tsserver on web
mjbvz commentedon Nov 19, 2021
microsoft/TypeScript#46862 Adds a draft implementation of this but I definitely need some help from the TS team to get it into a shippable state
mjbvz commentedon Jan 6, 2022
After discussion, we'd like to move the core auto import implementation to VS Code
Orta Therox (@orta) I looked into using
preProcessFileto get all the imports but it looks like this isn't currently exposed over the TSServer protocol? Is that correct?After thinking about this more, I am also wondering if using
preProcessFileis too low level. We can debounce how often we end up callingpreProcessFileto avoid calling it on every key stroke, but it feels like it would make more sense if TS could tell us what auto imports it needs and then VS Code could then go and resolve themmjbvz commentedon Jan 15, 2022
Orta Therox (@orta) Andrew Casey (@amcasey) I have a basic prototype now running on the VS Code side and can use this to load global typings such as
jqueryThe problem I'm running into now though is telling TS that
jqueryinimport 'jquery'maps to a given file the VS Code has opened against the TypeScript serverHere's how the files are currently opened after ATA has completed (I'm using the paths that TS server sees):
^/memfs/sample-folder/file.js— This is the file that the user has opened upThen we have a list of jQuery d.ts files that VS Code has opened up with the correct content:
^/ts-typings/node_modules/@types/jquery/JQueryStatic.d.ts^/ts-typings/node_modules/@types/jquery/JQuery.d.ts^/ts-typings/node_modules/@types/jquery/misc.d.ts^/ts-typings/node_modules/@types/jquery/legacy.d.ts^/ts-typings/node_modules/@types/jquery/index.d.tsAll of these are in-memory files so TS Server cannot read them directly. I believe we also have to keep the different scheme (
memfsvsts-typings) as part of the implementation on the VS Code sideWhat type of API do you think we need to get typescript to understand that
import 'jquery'should resolve to^/ts-typings/node_modules/@types/jquery/JQuery.d.ts?Prototype ATA for TS web
orta commentedon Jan 19, 2022
There's a similar tension in doing the full TypeScript compile in the ts-vscode playground - I wonder if a reasonable strategy lays in making the TypeScript web server smarter, and keeping some of the file content inside that. As it exists, there is no way to influence what is available to that TSServer:
I think somewhere there needs to be a vfs map which the tsserver prioritises for
syslookups for dirs/files and it might need to be insider the web server. That could be controlled via additional tsserver actions/events.I think that might get tricky with the schema change, I think you'd need to hardcode that somehow into the TS web server code somehow (for examples it is kinda safe that all paths with
@typescould be treated that way)mjbvz commentedon Jan 19, 2022
Orta Therox (@orta) Thanks! Not sure I understand the first part though.
With my current approach, on web all TS files are opened against as in-memory resources. This means that TS knows the file content but should not try to read these files from disk. Are you proposing a different approach where
readFilewould be needed?For the second part, who is the best point of contact to discuss this with? If needed I think we could rewrite the paths that VS Code sends to TS Server to make the project system happy, but I'd like to explore a proper solution first
mjbvz commentedon Jan 21, 2022
My current proposal would be a new TS Server api that let a client explicitly pass global typings files to the TypeScript Server. This could be used both to implement ATA, and also for applications like Office Scripts where you have a VS Code extension that wants to augment the global typings in JS files
Some of this discussion also gets into our discussions around virtual file system support for vscode.dev
One idea: could a client for example tell TS Server about a type root directory and then the server would simply treat any files opened under this directory as typings
From a protocol point of view, this would look something like:
Client passes a root directory for typings to TS Server:
configure { typeRoots: ['^/ts-typings'] }Client then opens files under this types root:
updateOpen { path: '^/ts-typings/jquery/jquery.d.ts' }When resolving imports, the server then looks in the types root.
Since the server only has an in-memory representation of these read files/folders, the server may have to construct its own little virtual file system representation to implement this
orta commentedon Jan 22, 2022
(sorry, been a busy few weeks)
I'm not sure that you need to special case the vfs as only being typings specifically, for the playground ATA we emulated having files in
node_modules/@types/jquery/index.d.tswhich meant it was picked up by the default behavior in TypeScriptIf you have a generic system to put vfs files into the web tsserver's sys then you can put files into the right place and it would automatically be respected by the rest of the tsserver
10 remaining items
Enable web type acquisition by default for js/ts
Enable web type acquisition by default for js/ts (microsoft#212370)