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

feat: add LanguageServerRunConfig and groovy example #591

Merged
merged 10 commits into from
Jan 20, 2024

Conversation

ls-infra
Copy link
Contributor

@ls-infra ls-infra commented Jan 16, 2024

Enhancement

  1. parameterising the run config to support different language server run cmd, so that it will be more configurable to the end users. (runLanguageServer( ))
  2. parameterising the language id to support different language monaco client editor. (runLanguageClient( ))

Use case

some language servers dose not use node cli to run the process https://github.com/TypeFox/monaco-languageclient/blob/main/packages/examples/src/common/server-commons.ts#L24
for example , a groovy language server is likely to be run by java cli cmd.
(see the packages/examples/src/groovy for more details)

Usage

import { runLanguageServer } from 'monaco-languageclient-examples/node';

image

(it may be better if we can make a new package called packages/language-server-runner and move those common code into it. Then the packages/examples will call packages/language-server-runner. And we publish the packages/language-server-runner as a reusable package instead of the packages/examples . )

thank you very much,

A

@kaisalmen
Copy link
Collaborator

@adrian2024lsp thank you very much for your contribution. Generalizing the server running is a nice enhancement. I will test this and review the code likely tomorrow. We could also expose the language-server-runner as sub-export from the examples package. This achieves the goal without requiring much additional work.

@ls-infra
Copy link
Contributor Author

i just fixed the CI build https://github.com/adrian2024lsp/monaco-languageclient/actions/runs/7546931119

typically , a package named like "xxx-examples" as a dependencies in others' package.json is not common.
"xxx-examples" can be viewed as an app , it is rare to include an app as a dependencies.

for example, you would not publish the https://github.com/TypeFox/monaco-languageclient-ng-example as a package to be included in others' dependencies .

instead, we should extract the common reusable into a lib package and publish it to be reused.

in a typically mono repo like https://nx.dev/, app depends on lib. Normally, we run an app , while we publish an lib to be included as dependencies to be reusable by other, not the other way around.

imo,
import { runLanguageServer } from 'language-server-runner';
is more intuitive than
import { runLanguageServer } from 'monaco-languageclient-examples';

with that said, if it is too hassle to rename the package name, maybe just leave it for now and just do it as sub-export as you said .

thanks,

Copy link
Collaborator

@kaisalmen kaisalmen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some minor change requests.
Overall, I really like what you contributed. Thank you.

packages/examples/src/common/client-commons.ts Outdated Show resolved Hide resolved
packages/examples/src/common/client-commons.ts Outdated Show resolved Hide resolved
packages/examples/src/common/client-commons.ts Outdated Show resolved Hide resolved
packages/examples/src/common/language-client-runner.ts Outdated Show resolved Hide resolved
packages/examples/src/common/model.ts Outdated Show resolved Hide resolved
packages/examples/src/common/model.ts Outdated Show resolved Hide resolved
@kaisalmen
Copy link
Collaborator

typically , a package named like "xxx-examples" as a dependencies in others' package.json is not common. "xxx-examples" can be viewed as an app , it is rare to include an app as a dependencies.

for example, you would not publish the https://github.com/TypeFox/monaco-languageclient-ng-example as a package to be included in others' dependencies .

instead, we should extract the common reusable into a lib package and publish it to be reused.

I agree. So far, the shared code was only used in other examples in https://github.com/TypeFox/monaco-languageclient-ng-example and https://github.com/TypeFox/monaco-components

It may make sense to move these things into the client lib itself (as sub-exports). Could a good move as I am thinking about reducing overall maintenance effort.

WDYT?

@kaisalmen
Copy link
Collaborator

kaisalmen commented Jan 17, 2024

Whatever I suggested above is after is this PR is in. Otherwise it will get to big. I am planning to update to a new @codingame/monaco-vscode-api version this week and release a new version of the lib afterwards.

@ls-infra
Copy link
Contributor Author

@kaisalmen , thanks for the comments. i just pushed a few commits. Please review.

in terms of reducing overall maintenance effort, I reckon nx is the way to go in long term.

currently i find it is hard to modify something across multiple packages. For example, if I need to make some change in both packages/examples and packages/vscode-ws-jsonrpc, looks like we need to publish a new version for the packages/vscode-ws-jsonrpc first before the change can be used by the packages/examples.

Nx can help us solve this kind of issue regardless small or big project. Because we have project structure conceptually like this :


apps/angular-example
apps/vue-example
apps/react-example
apps/node-example
...

libs/angular-runner
libs/vue-runner
libs/react-runner
libs/monaco-languageclient
libs/node-runner
libs/vscode-ws-jsonrpc
libs/monaco-vscode-api
...

(assuming only libs are publishable )

if we manage to make it to a nx monorepo, we do not need to manage lots of new package versions releases for changes to be available in other packages.

besides, it is easier to manage the dependency chain as well, for example we have dependency chain like this :
apps/angular-example -> libs/angular-runner -> libs/monaco-languageclient
apps/node-example -> libs/node-runner -> libs/vscode-ws-jsonrpc

when we make changes across different level of the chain, then we trigger the CI build, we immediately find out which code are incompatible. thus it helps us to achieve a fail fast CI .

For example , those two interfaces (MessageConnection vs IConnection) are incompatible but hard to tell because they are in different repos and the version of the packages dependency are aslo different.

https://github.com/CodinGame/languageserver-mutualized/blob/main/example/src/json-server-launcher.ts#L20
https://github.com/TypeFox/monaco-languageclient/blob/main/packages/examples/src/common/server-commons.ts#L23
(as i am still struggling to find out how to use the latest code from those two repos to make the mutualized way working . any help will be greatly appreciated )

with that said , we can adapt it gradually, progressively, incrementally in an non-invasive
way https://nx.dev/recipes/adopting-nx/adding-to-monorepo instead of intensive code changes.

thanks,

@kaisalmen
Copy link
Collaborator

currently i find it is hard to modify something across multiple packages. For example, if I need to make some change in both packages/examples and packages/vscode-ws-jsonrpc, looks like we need to publish a new version for the packages/vscode-ws-jsonrpc first before the change can be used by the packages/examples.

No, just let npm run watch in a terminal. Updates in the libs are handled by the TypeScript composite / references configuration. There is no need to publish inside the npm workspace. Local dependencies are properly resolved by npm itself.

(as i am still struggling to find out how to use the latest code from those two repos to make the mutualized way working . any help will be greatly appreciated )

Sorry, I need to investigate. vscode-ws-jsonrpc did not really evolve the last years. It is basically in maintenance mode.

One important thing Please, do not merge main branch into a feature branch. Always rebase a feature or bugfix branch to the latest main if you require changes from main (we should document this in the Contributing!). I did this for you here: https://github.com/TypeFox/monaco-languageclient/tree/feature/languageServerRunConfig
You can reset your branch to this. The content is identical.

Sorry, I made those copyright changes yesterday.

Copy link
Collaborator

@kaisalmen kaisalmen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the model sub-folder as the separation is artificial. I am anyway thinking about moving the code out of the example to the client anyway. Let's keep it together.

Otherwise this is ready to be merged. Thanks.

packages/examples/src/model/client.ts Outdated Show resolved Hide resolved
packages/examples/src/model/server.ts Outdated Show resolved Hide resolved
packages/examples/src/model/shared.ts Outdated Show resolved Hide resolved
@ls-infra
Copy link
Contributor Author

@kaisalmen , ok , just one more thing to confirm before i make change to the /model.
if we do not put the interface into a its own file . it will end up a circular dependency:

language-server-runner.ts
import { upgradeWsServer } from './server-commons.js';

server-commons.ts
import { LanguageServerRunConfig } from './language-server-runner.js';

if we put the interface into a separate files, then we can avoid the implementation files depending on each other thus avoid potential circular dependency in the repo. Another benefit is that we can publish those interface into its own package like vsc for other future reuse purposes. WDYT?

in terms of the npm workspace,
when we do npm install for vscode-ws-jsonrpc , can we just install things in repo/packages/vscode-ws-jsonrpc/package.json and repo/packages/package.json? So that the things in repo/packages/examples/package.json will not pollute the vscode-ws-jsonrpc ?

btw, where is the Github repo for https://www.npmjs.com/package/@codingame/monaco-editor-treemended ?

thanks,

@ls-infra ls-infra force-pushed the feature/languageServerRunConfig branch from 8a97dcd to 8e7ee39 Compare January 19, 2024 01:23
@kaisalmen
Copy link
Collaborator

kaisalmen commented Jan 19, 2024

if we do not put the interface into a its own file . it will end up a circular dependency:

Thanks, I overlook that in the review. See my suggestion in the respective review comments.

when we do npm install for vscode-ws-jsonrpc

In a npm workspace you perform npm install only at the root of the repo. It is not required on each single workspace/sub-packages level. Each workspace package.json defines its dependencies. The root level packages allows for example to commonly define devDependencies.

btw, where is the Github repo for https://www.npmjs.com/package/@codingame/monaco-editor-treemended

https://github.com/CodinGame/monaco-vscode-api it releases 100+ npm packages. 🙂

@ls-infra
Copy link
Contributor Author

@kaisalmen
I just pushed the changes,
thx,

Copy link
Collaborator

@kaisalmen kaisalmen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for your contribution! 🎉 We will make up our minds on how to restructure the common code. Once a proposal/PR is ready, I will ask you for your opinion/review.

CONTRIBUTING.md Show resolved Hide resolved
@kaisalmen kaisalmen merged commit 4996609 into TypeFox:main Jan 20, 2024
1 check passed
@ls-infra
Copy link
Contributor Author

@kaisalmen , great to see we want to restructure the common code.

#543 (comment)
looks like it will involve refactoring the common code across two Github Org as well ?
I assume the ultimate goal is to organise the code across TypeFox and CodinGame repos a bit more so that the dependency chain is more clear and improve the code reusability.

you mentioned "Even with a shared org there will be interdependent npm packages."
i think whenever we encounter a circular dependency , we can alway break the circular code by moving one side into the lower level repo or module. The circular dependency(interdependent packages) can be eventually avoided regardless across different repo or across different org.

for example,
initially we have
https://github.com/ls-infra/node-lsp-runner -> https://github.com/ls-infra/monaco-vscode-api

https://github.com/ls-infra/react-lsp-runner -> https://github.com/ls-infra/monaco-vscode-api

then later we notice some code depends on each other:
https://github.com/ls-infra/node-lsp-runner <- -> https://github.com/ls-infra/react-lsp-runner .
then we can break the circular dependency by introducing a new repo :
https://github.com/ls-infra/node-lsp-runner -> https://github.com/ls-infra/common-lsp-runner -> https://github.com/ls-infra/monaco-vscode-api

https://github.com/ls-infra/react-lsp-runner -> https://github.com/ls-infra/common-lsp-runner -> https://github.com/ls-infra/monaco-vscode-api

or directly sink the code into https://github.com/ls-infra/monaco-vscode-api depending on the context.

(assuming https://github.com/ls-infra/monaco-vscode-api is our lowest level.
its upstream dependencies are the https://github.com/microsoft/monaco-editor and https://github.com/microsoft/vscode. )

and all the repos in TypeFox and CodinGame will depend on the repos in https://github.com/ls-infra. And whenever they have an interdependent npm packages, we can sink that to the lower level of the dependencies chain.

with that said, if we can achieve similar goal without needing to introduce a new org, that is great as well.
(if needed , maybe come up with a proper name like LanguageServerInfrastructure )

Moreover, we can leverage the npm workspace as monorepo and introduce the /apps and /libs conceptually structure, it will reduce the amount of repos we need to maintain separately .

maybe in your RFC PR , you can layout what will be the dependency chain for the overall project folder structure in a file like architecture.md. Then we contribute it and it can be used as future reference.

thx,

@kaisalmen
Copy link
Collaborator

@ls-infra I don't see the need to fundamentally restructure any repository and I am pretty certain that @CGNonofr does not see that need either. I don't see any circular dependency problem with the packages.

This is a closed PR. Please create a new issues or discussion and explain the your problem. From what you wrote above it is still unclear what the actual problem is.

@ls-infra
Copy link
Contributor Author

@kaisalmen ok, that is fine , it is not necessary a problem or issue , just some thoughts on trying to avoid potentially circular dependency in the long term. And i just sometimes find it a bit hard to follow when i need to debug something to trace down the dependency chain due to we split the packages across different orgs and different repos. (and sometimes packages name does not match the repo name).

since you mentioned you will open a proposal/PR , so maybe let us discuss the restructure the common code things in your RFC PR when it is ready .

thanks,

@kaisalmen
Copy link
Collaborator

And i just sometimes find it a bit hard to follow when i need to debug something to trace down the dependency chain due to we split the packages across different orgs and different repos.

@ls-infra Fair point. Here a proper diagram / more useful documentation could be helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants