sublimelsp / LSP-volar

Vue support for Sublime's LSP plugin

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Use the typescript server from the current project

predragnikolic opened this issue · comments

Currently LSP-volar has a hard-coded the path to the tsserver:

"typescript": {
// For now users maybe need to change the serverPath manually to point to a `tsserver.js` file.
"serverPath": "${folder}/node_modules/typescript/lib/tsserver.js",
},

LSP-volar assumes that the node_modules will be at the root of the opened folder, which is not always the case.

Proposal,
find the tsserver path, even when the node_modules is not at the root of the project,
and if it cannot find one fallback to a bundled tsserver path. (which requires typescript as a new dependency in the package.json file)

I don't really see why the volar server itself should not do it. It's pretty common for servers to do it (vetur, typescript-language-server, ...). Maybe just try creating an issue for it in volar's repo?

I know. I did a PR to volar that should add just that: (but the PR got closed)

vuejs/language-tools#401

The biggest concern was security. The maintainer shifted the security responsibility to the client... But after a while of thinking I still thing that this logic should be on server.

To be more precise. The server would have the logic to find the tsserver, but if the security is a concern the server should not be started by the client in the first place.

It is kind of a pain to find the tsserver path with python.

I don't think you should priority use workspace typescript module. If the workspace has no install node_modules yet, or user have no add typescript to project dependencies (This is very common, especially for js projects.), language server can't working at all.

If Sublime has built-in typescript module you should use it first, otherwise you need to add typescript as @volar/server peer dependency in https://github.com/sublimelsp/LSP-volar/blob/master/server/package.json#L5, and config typescript.serverPath as typescript/lib/tsserverlibrary.js.

It's pretty common for servers to do it (vetur, typescript-language-server, ...).

They do not mean it is correct to do so. Yes this is convenient for the language client, but it also urge language client to give up security considerations.

But before considers security, I suggest to consider whether it can work in js projects.
This is a example: https://github.com/vitejs/vite/tree/main/packages/create-vite/template-vue


Edit: I see that you plan to fall back to bundle's typescript when can't find typescript in workspace. If priority use bundle's typescript, and support user config specific typescript path if user want to use workspace typescript, you don't need to implement typescript path finding.

Thanks for dropping by and stating your opinion. :)
I don't exactly agree with all your points though so let's discuss.

I don't think you should priority use workspace typescript module. If the workspace has no install node_modules yet, or user have no add typescript to project dependencies (This is very common, especially for js projects.), language server can't working at all.

That isn't a valid argument against this request because there normally is a fallback to a typescript version bundled with the extension, editor or a global one. So that's not an issue.

Security considerations aside for now, the ideal case IMO is that the workspace typescript is used (when available) since otherwise there can be various incompatibilities between what the project expects and what the Volar expects (typescript introduces breaking changes all the time, even in minor releases). This is especially important for projects that rely on typescript for compilation, not so much on pure JS projects that just rely on typescript for code intelligence of course.

If Sublime has built-in typescript module you should use it first, otherwise you need to add typescript as @volar/server peer dependency in https://github.com/sublimelsp/LSP-volar/blob/master/server/package.json#L5, and config typescript.serverPath as typescript/lib/tsserverlibrary.js.

Sublime uses Python for its extension API, not TS/JS like VSCode. So it has no business in having typescript anywhere already. That said, your suggestion to add typescript as a peer dependency (or in fact just a normal dependency in that case) is how we normally do it with those LSP-* packages and we have no problem with that. The issue is that the Volar itself won't fall back to it automatically. We would have to create some wrapper JS script (or have that logic in Python) that does that which IMO shouldn't be necessary.

They do not mean it is correct to do so. Yes this is convenient for the language client, but it also urge language client to give up security considerations.

That's another topic but there is really no security in the node ecosystem and we should not pretend otherwise. Just doing npm i alone can do all kinds of bad things on your system. Having a language server be targeted as an attack vector when there are much easier ways to screw someone up, seems of little relevance.

What VSCode's "workspace trust" solution is IMO, is just a way for MS to say "it's not our fault" when something bad happens. It doesn't really provide any meaningful protection since the user who would fall for a security issue like that will likely not be able to properly judge and audit the suspicious project to prevent himself from getting in trouble.

And also it should be editor's choice IMO whether such mitigations should be provided and how.

Edit: I see that you plan to fall back to bundle's typescript when can't find typescript in workspace. If priority use bundle's typescript, and support user config specific typescript path if user want to use workspace typescript, you don't need to implement typescript path finding.

IMO that's not an ideal flow.
As I've said above, the priority should be:

  1. workspace
  2. bundled

I don't use sublime, so I don't know, but I'm sure there are ways to deal with this, such as referring to the angualr (LSP-angular) plugin. https://github.com/sublimelsp/LSP-angular/blob/master/server/package.json#L6

https://github.com/sublimelsp/LSP-angular/blob/master/plugin.py#L13-L16
https://github.com/sublimelsp/LSP-angular/blob/master/LSP-angular.sublime-settings

As said above, there is no problem with this plugin (package) including typescript as a dependency in the same way. The problem is with Volar not having a logic for picking the most relevant typescript versions.

Security considerations aside for now, the ideal case IMO is that the workspace typescript is used (when available) since otherwise there can be various incompatibilities between what the project expects and what the Volar expects (typescript introduces breaking changes all the time, even in minor releases). This is especially important for projects that rely on typescript for compilation, not so much on pure JS projects that just rely on typescript for code intelligence of course.

In my opinion, this is the reason why bundle's typescript should be used first. :S

What VSCode's "workspace trust" solution is IMO, is just a way for MS to say "it's not our fault" when something bad happens. It doesn't really provide any meaningful protection since the user who would fall for a security issue like that will likely not be able to properly judge and audit the suspicious project to prevent himself from getting in trouble.

Just because it can't protect doesn't mean it doesn't need to be done. I agree that its greater role is to prevent a lawyer's letter from being sent to you when the company suffers a loss. But for users who always set the trust scheme correctly, this feature is useful.

And also it should be editor's choice IMO whether such mitigations should be provided and how.

If implemented typescript finding in language server, editor's can't. They can only disable entire language server if not trust.

IMO that's not an ideal flow.
As I've said above, the priority should be:

  1. workspace
  2. bundled

This implies the main problem, we have different UX designs for IDE support, so the implementation is different. This is why I put the logic in the language client. You expect that the logic implemented in the language server actually leaks IDE-specific logic to the LSP, and this is a bug for other IDE plugins because it does not conform UX design of other IDE plugins.

Anyway, I have no intention of deciding on your UX design, I just explain the reason why this logic is not implemented in language server.

Security considerations aside for now, the ideal case IMO is that the workspace typescript is used (when available) since otherwise there can be various incompatibilities between what the project expects and what the Volar expects (typescript introduces breaking changes all the time, even in minor releases). This is especially important for projects that rely on typescript for compilation, not so much on pure JS projects that just rely on typescript for code intelligence of course.

In my opinion, this is the reason why bundle's typescript should be used first. :S

No because that can end up with a situation where Volar reports an error while the project itself builds just fine. Or the other way around - project building fails while Volar doesn't report the issue.

We could have a cake and eat it too if Volar would provide an option to "useWorkspaceDependencies". Which is something that Vetur actually provides (disabled by default).

Even if implemented in language server, it may not be suitable for you. In our implementation, only the typescript in the workspace will be searched. If the workspace does not exist, the search will fail. But what you need seems to be if you can't find it in the workspace, first try to fall back to the global typescript module. I may also can't agree with this design.

I think you can use a one-line node script to solve your needs:

// resolve_module.js
process.stdout.write(require.resolve(process.argv[3], { paths: [process.argv[2]] }));
import subprocess
proc = subprocess.Popen(['node', 'resolve_module.js', 'WORKSPACE_DIR', 'typescript/lib/tsserverlibrary.js'], stdout=subprocess.PIPE)
ts_path = proc.stdout.read()
print(ts_path)

Thank you for your thoughts @rchl, @johnsoncodehk and @yaegassy.

Although I mostly have the same point of view as Rafal(@rchl),
I can also see that different people have different expectations to what should be the client responsibility and the servers responsibility. (and it is all debatable)

For now I made a PR to implemented the finding of the ts server on the client. :)