TypeFox / monaco-components

Monaco Editor and Language Client Wrapper, plus Monaco Editor React Component
MIT License
42 stars 13 forks source link

Lit Component #24

Closed ballcoach12 closed 11 months ago

ballcoach12 commented 1 year ago

My team would like to build a Lit component to wrap an editor for a language that we created using Langium. We have a Lit app almost working with a component that should be able to provide the editor for our language. However, we are running into problems with rollup when we try to build the app. It seems that the monaco-editor-wrapper does some things that rollup doesn't like.

I came across the recent announcement about the monaco-editor-wrapper Lit component being discontinued in the latest release.

image

My questions are:

  1. Is there a way to deliver the editor wrapper as a Lit component at all?
  2. Should we just try to wrap the React editor so that we can use it in a Lit app?
  3. Should my question be redirected to the Langium repo?

Thanks

kaisalmen commented 1 year ago
  1. Should my question be redirected to the Langium repo?

Hi @ballcoach12 this is exactly the correct spot to ask your questions. 👍

  1. Is there a way to deliver the editor wrapper as a Lit component at all?

We discontinued monaco-editor-comp because nobody seemed to really use it: according to download numbers it never increased popularity and we ourselves discontinued to use it. Due to the way the whole underlying stack of monaco-editor, monaco-languageclient and monaco-vscode-api is now configured, using a web component now felt counter-intuitive, but it is still possible. You won't be able to pass the configuration as property, but putting a web component shell around monaco-editor-wrapper will work.

  1. Should we just try to wrap the React editor so that we can use it in a Lit app?

I would wrap monaco-editor-wrapper and not the react-component or just consider using pure JavaScript. The aim of the wrapper is to make it work in pure HMTL/JS context. No framework is required.

I guess you are aware of these Langium examples: https://github.com/TypeFox/monaco-components/tree/main/packages/examples/src/langium Two entry points are: https://github.com/TypeFox/monaco-components/blob/main/packages/examples/wrapper_langium.html and: https://github.com/TypeFox/monaco-components/blob/main/packages/examples/react_langium.html

However, we are running into problems with rollup when we try to build the app. It seems that the monaco-editor-wrapper does some things that rollup doesn't like.

We build a bundle for verification with vite which uses rollup 3 under the hood for production bundling. Asset inclusions and commonjsOptions are likely a problem for you, see the vite config: https://github.com/TypeFox/monaco-components/blob/main/packages/examples/vite.bundle-mew.ts

This bundle is used here: https://github.com/TypeFox/monaco-components/blob/main/packages/examples/verify_wrapper.html

Hopefully this already helps you to move forward. If there are more questions. don't hesitate to ask. If our READMEs are unclear, please let us know, too. We may have forgotten some things when upting them for v2 🙂

ballcoach12 commented 1 year ago

Many thanks, @kaisalmen, for your helpful response. We are still studying how best to attack this problem, so I'm sure I'll have additional questions. We essentially want to accomplish what is described here, but using Lit instead of React.

ballcoach12 commented 1 year ago

It feels like I am really close to getting this working. I created a new Lit element project (I was working with a Lit app before) and Rollup is now out of the picture. Only WebDev server is involved. The only problem that I can see is that it cannot seem to find the vscode package. For some reason, I recall that it isn't as easy as adding vscode to the dependencies in my package.json file. So I'm not sure how to go about resolving this. The error I get is:

Error while transforming node_modules\monaco-editor-wrapper\dist\index.js: Could not resolve import "vscode".

  10 | import 'monaco-editor/esm/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.js';
  11 | import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
> 12 | import * as vscode from 'vscode';
     |            ^
  13 | import { getMonacoCss } from './generated/css.js';
  14 | import { MonacoLanguageClient, CloseAction, ErrorAction, MonacoServices } from 'monaco-languageclient';
  15 | import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc';

Note that I am using the following versions in my package.json file:

"monaco-editor": "^0.39.0",
"monaco-editor-workers": "^0.34.2",
"monaco-editor-wrapper": "^1.3.1"
kaisalmen commented 1 year ago

Is there any specific reason you are using a fairly the old version of monaco-editor-wrapper? 2.0.0 was released last week and I recommend starting from there.

No matter which version you use, you have to use monaco-vscode-api as vscode dependency. monaco-editor-wrapper depends on monaco-languageclient and it depends on monaco-vscode-api:

"vscode": "npm:@codingame/monaco-vscode-api@~1.78.8",

You have to use compatible versions, see: https://github.com/TypeFox/monaco-languageclient#using-monaco-languageclient

monaco-editor 0.39.0 is too new and not yet supported and additionally the worker support package should fit the monaco-editor version.

Idea: start to wrap one of the simple examples into a lit component. Throw out all unnecessary stuff (HTML buttons, restart handling): https://github.com/TypeFox/monaco-components/blob/main/packages/examples/src/wrapperTs.ts or https://github.com/TypeFox/monaco-components/blob/main/packages/examples/src/wrapperWs.ts

ballcoach12 commented 1 year ago

@kaisalmen , as you suggested, I am trying to wrap one of the simple examples. But the problem seems to be dependency resolution. I am not even at the point yet where I am using Lit, and I can't build a bundle due to dependency resolution.

I have created a minimal example here: https://github.com/ballcoach12/monaco-editor-ts.

We are using Parcel to build our module now instead of Rollup (maybe that's a mistake), and it fails when we attempt the build:

🚨 Build failed.

@parcel/core: Failed to resolve 'vscode/service-override/configuration' from './node_modules/monaco-editor-wrapper/dist/editorVscodeApi.js'

  G:\BITBUCKET\PROTOTYPE\monaco-editor-ts\packages\monaco-ts\node_modules\monaco-editor-wrapper\dist\editorVscodeApi.js:1:41
  > 1 | import { updateUserConfiguration } from 'vscode/service-override/configuration';
  >   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    2 | import { registerExtension } from 'vscode/extensions';
    3 | import 'vscode/default-extensions/theme-defaults';

@parcel/resolver-default: Cannot load file './service-override/configuration' from module 'vscode'

It does not seem to know how to resolve 'vscode/service-override/configuration' even though we reference "vscode": "npm:@codingame/monaco-vscode-api@~1.78.8",. My guess is that your Vite-based implementation gets around this problem by pre-bunding these modules.

ballcoach12 commented 1 year ago

Also, I noticed that the build:comp npm script is still in the main package.json file. This probably needs to be removed since the web components implementation has been removed.

kaisalmen commented 1 year ago

Hi @ballcoach12 we don't use parcel, so I can't really help there. As you know we use vite/rollup for bundling, but it also works with webpack. We have a verification example in the monaco-languageclient repo that creates a working bundle from an client, see here: https://github.com/TypeFox/monaco-languageclient/blob/main/packages/verify/webpack/webpack.config.js

https://github.com/ballcoach12/monaco-editor-ts only contains a README. Did you forgot to push updates?

Thanks for the hint regarding the package.json. I already pushed an update.

ballcoach12 commented 1 year ago

Sorry about that! The files should be in the repo now (been a long week...:)

ballcoach12 commented 1 year ago

I got a basic example working where I wrap an editor in Lit. I'll post it to the repo next week. Thanks for the input!

ballcoach12 commented 11 months ago

Picking this back up after a few months...

One of the reasons why we are using an earlier version of monaco-editor-wrapper is because that's what is generated by the generator-langium. I assume that the Langium implementation will eventually catch up to the newer version of monaco-editor-wrapper, but ~1.6.0 seems to be the version for now.

I recall seeing a comment somewhere along the way that one of the notable differences between wrapper versions is the ability to use UserConfig to set up the editor. IIRC, it was highly recommended to do that if we are trying to package our language editor inside a Lit component.

One thing that I am a bit confused on is the difference between 'classic' mode and 'VscodeApi' mode. Can you explain that to me and advise on how I should determine which one to choose?

kaisalmen commented 11 months ago

I assume that the Langium implementation will eventually catch up

@ballcoach12 there is https://github.com/eclipse-langium/langium/issues/1163 Once #45 and #47 are done and a new release is available my plan is to update the template.

classic mode basically supplies the configuration/capabilities you know from monaco-editor. vscodeApi mode allows you to use all the vscode services monaco-vscode-api exposes, e.g. textmate grammars, views support, debugger, etc.

Our documentation needs to be improved. It will come... 😅

kaisalmen commented 11 months ago

@ballcoach12 the Langium Grammar example (moved over here from monaco-languageclient a couple of weeks ago): https://github.com/TypeFox/monaco-components/blob/main/packages/examples/src/langium/wrapperLangium.ts now allows to start the editor in both modes. One uses monarch, the other one textmate.

ballcoach12 commented 11 months ago

@kaisalmen, thanks for the information. That likely explains why I was seeing multiple errors related to missing dependencies in my experimentation to get my implementation up and running. I was probably trying to run the editor in vscode mode and had not supplied the right dependencies.

At the moment, I am pursuing two approaches. The first is similar to how you guys test the mew.js bundle by inserting the TS code to configure the editor into the HTML file. I've been able to get a basic editor with Javascript support up and running this way.

The second approach is similar to the Statemachine example where the TS code is in a separate file that is referenced by a <script> tag in the HTML. I have not gotten this to work yet; the browser console shows an exception being thrown inside the Promise, stating that we cannot access createLangiumGlobalConfig before it is initialized. My guess is that this has something to do with the lifecycle of loading the page, and that's why the corresponding examples have the Start button on the page.

I plan to post an updated example to my repo later today. I'll add to the notes on this issue when that is done.

ballcoach12 commented 11 months ago

I have posted a new repository at https://github.com/ballcoach12/stab-at-lang-editor. If someone has time to take a look at it, I'd greatly appreciate it. The wrapper-js-html project works correctly, but the wrapper-js-code project does not. In the latter case, I get the following error when the editor loads in the browser:

Uncaught (in promise) Error: unsupported at FileService.unsupported2 (tools.js:2:11) at writeFile (monaco.js:128:48) at createModelReference (monaco.js:135:15) at EditorAppClassic.updateEditorModel (editorAppBase.ts:121:31) at EditorAppClassic.createEditor (editorAppBase.ts:74:20) at EditorAppClassic.createEditors (editorAppClassic.ts:73:24) at MonacoEditorLanguageClientWrapper.start (wrapper.ts:89:30) at async restartEditor (common.ts:43:5) at async startEditor (common.ts:15:5)

I don't get this error in the first case. Something tells me that it is related to module formats or else I don't have something configured correctly.

kaisalmen commented 11 months ago

Hi @ballcoach12 I will have the time to look at it tomorrow, I guess.

ballcoach12 commented 11 months ago

Thanks, @kaisalmen. I greatly appreciate it. I'll buy you a beer! :)

ballcoach12 commented 11 months ago

I have updated the example code in the repo I created. I have gotten past the error that I mentioned above, and now only have one error in the browser:

image

I suspect that either Vite is doing something in the bundling/chunking that is breaking things, or I have somehow missed a configuration option for the editor. In any case, things seem to fail when the editor tries to make the /tmp directory, from what I can see.

kaisalmen commented 11 months ago

@ballcoach12 found it. Don't use vite-plugin-node-polyfills in your vite configuration. It breaks the code with bad polyfills. Also, because you anyhow use vite, you dont't need the libs folder, just use regular package references in the code. vite does the magic.

ballcoach12 commented 11 months ago

Fixed!! I just modified my project and got it to work! Thanks so much for your help! I'll push my updates in case anyone wants to see my implementation as an example in the future.

kaisalmen commented 11 months ago

I'll push my updates in case anyone wants to see my implementation as an example in the future.

Sounds good.