How to Embed a Monaco Editor in a Browser as a Part of My First Task at TypeFox
Hi there, this is Akos. I am the new one at TypeFox, and within this post, I would like to describe you what was my first task after joining TypeFox. Namely, how to embed the Monaco Editor in the web browser and how to support a simple expression language from the browser using the Language Server Protocol (LSP).
First and foremost, what is the Monaco Editor? The Monaco Editor is a browser-based code editor that powers VS Code. It supports cool features such as syntax and semantic validation, content assist, syntax coloring, parameter hints, hover, and much more out of the box. It is well-documented and relatively easy to connect with a language server and integrate into your projects.
The first thing I needed for this task is the Xtext implementation of the language server. This server is available from the 2.11.0.beta1 milestone version of Xtext and depends on a lightweight library: ls-api. This library is a simple Java binding for the LSP and is going to be replaced by the LSP4J Eclipse project in the future. By default, the Xtext language server supports various features, such as content proposals, hover, mark occurrences, and find references, which one can use for almost any kind of DSLs without any further customizations. Besides that, there are a couple of additional features that require custom implementation; for instance the signature helper which provides parameter hints. Usually, one single language is supported by one server; however, the Xtext server is capable of supporting multiple Xtext languages at the same time. The only requirement is that the actual implementation of the language should be available from the classpath of the server as a bundled jar.
I had to prepare some generic glue code that acts as a web socket server endpoint and handles the lifecycle of the Xtext language server instance associated with the web socket session. On session-open event, it creates a new server instance and caches it and indeed on the web socket session-close event it shuts down the server and removes it from the cache. Besides that, to be able to support Guice based dependency injection in RESTful web services I used the jersey2-guice library which supports DI within the Jersey 2.x implementation of the JAX-RS/JSR-311 specification.
The last remaining part of this task was to build a web-archive file and deploy it. Since not all environments have installed Node.js on it, an individual Node.js task was added to the Gradle configuration to install Node.js with npm. Npm can install Webpack and Webpack can gather all modules and their direct and transitive dependencies reading the content of the package.json of our module. Finally, Gradle creates a war file which can be optionally deployed on a Tomcat server using the Gretty Gradle plug-in.
This example web-based Monaco Editor, which was presented at EclipseCon Europe last week, is available here. We are planning to make both the generic glue code (used for the server) and the Monaco Editor code accessible in the future. Once the code is available under the EPL 1.0 license, we'll come back to you with another blog post with all the technical details and pitfalls. If you cannot wait, feel free to drop me a mail.