diff --git a/docs/guides/examples.md b/docs/guides/examples.md index 6b58da6d2..8efb11cdf 100644 --- a/docs/guides/examples.md +++ b/docs/guides/examples.md @@ -75,7 +75,7 @@ async function createJsonEditor() { // Create the editor app const editorApp = new EditorApp({ codeResources: { - main: { + modified: { text: jsonContent, uri: codeUri } diff --git a/docs/guides/getting-started.md b/docs/guides/getting-started.md index 4db3b673f..6f7d4861e 100644 --- a/docs/guides/getting-started.md +++ b/docs/guides/getting-started.md @@ -1,24 +1,25 @@ # Getting Started -This guide will walk you through creating your first Monaco Language Client application. We'll build a simple JSON editor with language server support. +This guide will walk you through creating your first Monaco Language Client application. We'll start by building a simple JSON editor with language server support. ## Prerequisites Before you begin, ensure you have: -- Completed the [Installation](../installation.md) steps +- Completed the [Installation](../installation.md) steps in advance - A basic understanding of TypeScript and web development - A running development server (like Vite, webpack dev server, or something similar) +- This project cloned down so you can start up a JSON language server for testing ## Your First Language Client -We'll create a simple JSON editor that connects to a language server via WebSocket. In this example, we'll use Extended Mode. +We'll create a simple JSON editor that connects to a language server via WebSocket. We'll be using Extended Mode in this example. -The steps below will outline the process at large, and then further below we'll break down the relevant sections to explain what each part does. +The steps below will outline the steps, and then further below we'll break down the relevant sections to explain what each part does. -### Step 1: HTML Setup +### HTML Setup -Create a basic HTML file: +Start by creating a basic HTML file to give a place for monaco to setup: ```html @@ -28,21 +29,76 @@ Create a basic HTML file: Monaco Language Client - JSON Example -
+
``` -### Step 2: Basic TypeScript Setup +If you already have one setup, just be sure to add the root element for the Monaco Editor to attach to. -Create your main TypeScript file (`main.ts`): +If you're following along using Vite with the React TS template, you can add this to your main component (App.tsx): +```tsx +
+``` + +### Add Required Dependencies + +We can rely on an extension package that provides JSON language client support for the Monaco VSCode API, and giving us syntax highlighting as well. You can install it via npm. + +Note the version 23, which is intended for use with monaco-languageclient v10.4.x. If your project is using a different version of monaco-languageclient, be sure to match all `@codinggame/...` extensions accordingly. See the [version compatibility table](versions-and-history.md#monaco-editor--codingamemonaco-vscode-api-compatibility-table) for which versions to use. + +```shell +npm install @codingame/monaco-vscode-json-default-extension@23 +``` + +### Updating Vite Config (if using Vite) + +Be sure to update your `vite.config.ts` to include the `importMetaUrlPlugin`, which is required for the Monaco Language Client to function properly in dev mode when loading up vsix extensions. For more details, see the [Troubleshooting Guide on Vite](./troubleshooting.md#if-you-use-vite). + +You may also need to install the plugin if you haven't already. + +```shell +npm install @codingame/esbuild-import-meta-url-plugin +``` + +Then update your `vite.config.ts` as follows: ```typescript -// Import required extensions for JSON support -import '@codingame/monaco-vscode-json-default-extension'; +import importMetaUrlPlugin from '@codingame/esbuild-import-meta-url-plugin' + +export default { + // ... other vite config options + plugins: [ + importMetaUrlPlugin, + // ... other plugins + ], + worker: { + format: 'es' + }, + optimizeDeps: { + include: [ + 'vscode-textmate', + 'vscode-oniguruma' + ], + esbuildOptions: { + plugins: [importMetaUrlPlugin] + } + } +} +``` + +### Monaco Editor & Language Client Setup -// Import Monaco Language Client components +Create your main TypeScript file (`main.ts`). If you already have a TypeScript setup, you can integrate the following code into your existing project. + +Note that we'll still need a running language server for JSON language support, the client just provides the means to connect to it. We'll cover that in the next step after this one. + +Once you have that installed, you can setup your `main.ts` file as follows to setup the editor & language client: + +```typescript + +// import Monaco Language Client components import { EditorApp, type EditorAppConfig } from 'monaco-languageclient/editorApp'; import { configureDefaultWorkerFactory } from 'monaco-languageclient/workerFactory'; import { MonacoVscodeApiWrapper, type MonacoVscodeApiConfig } from 'monaco-languageclient/vscodeApiWrapper'; @@ -53,16 +109,19 @@ import * as vscode from 'vscode'; import { LogLevel } from '@codingame/monaco-vscode-api'; import { RegisteredFileSystemProvider, RegisteredMemoryFile, registerFileSystemOverlay } from '@codingame/monaco-vscode-files-service-override'; -async function createJsonEditor() { - // Sample JSON content - const jsonContent = `{ +// import extension for JSON support +import "@codingame/monaco-vscode-json-default-extension"; + +// Sample JSON content +const jsonContent = `{ "$schema": "http://json.schemastore.org/package", "name": "my-package", "version": "1.0.0", "description": "A sample package" }`; - // Set up file system +async function createJsonEditor() { + // Set up an in-memory file system (won't persist on reload) const fileUri = vscode.Uri.file('/workspace/package.json'); const fileSystemProvider = new RegisteredFileSystemProvider(false); fileSystemProvider.registerFile(new RegisteredMemoryFile(fileUri, jsonContent)); @@ -72,21 +131,27 @@ async function createJsonEditor() { const vscodeApiConfig: MonacoVscodeApiConfig = { $type: 'extended', viewsConfig: { - $type: 'EditorService' + $type: 'EditorService', + htmlContainer: document.getElementById("monaco-editor-root")! }, logLevel: LogLevel.Debug, userConfiguration: { json: JSON.stringify({ 'workbench.colorTheme': 'Default Dark Modern', - 'editor.wordBasedSuggestions': 'off' + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.lightbulb.enabled': 'On', + 'editor.wordBasedSuggestions': 'off', + 'editor.experimental.asyncTokenization': true }) }, monacoWorkerFactory: configureDefaultWorkerFactory }; + const languageId = 'json'; + // Language client configuration const languageClientConfig: LanguageClientConfig = { - languageId: 'json', + languageId, connection: { options: { $type: 'WebSocketUrl', @@ -94,7 +159,7 @@ async function createJsonEditor() { } }, clientOptions: { - documentSelector: ['json'], + documentSelector: [languageId], workspaceFolder: { index: 0, name: 'workspace', @@ -106,32 +171,33 @@ async function createJsonEditor() { // editor app / monaco-editor configuration const editorAppConfig: EditorAppConfig = { codeResources: { - main: { - text: code, - uri: codeUri + modified: { + text: jsonContent, + uri: fileUri.path, } } }; - // Create the monaco-vscode api Wrapper + // create the monaco-vscode api Wrapper const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); await apiWrapper.start(); - // Create language client wrapper + // create language client wrapper & app const lcWrapper = new LanguageClientWrapper(languageClientConfig); - await lcWrapper.start(); - - // Create and start the editor app const editorApp = new EditorApp(editorAppConfig); - const htmlContainer = document.getElementById('monaco-editor-root')!; - await editorApp.start(htmlContainer); + + // start editor app first, then language client + await editorApp.start(document.getElementById("monaco-editor-root")!); + await lcWrapper.start(); console.log('JSON editor with language client is ready!'); } createJsonEditor().catch(console.error); ``` -### Step 3: Language Server Setup +After this you can run `npm run build` to verify things & `npm run dev` (or an equivalent for your stack) to start a development server. You should see a Monaco Editor instance load up in your browser, with code, but no language support or highlighting yet (we'll cover that next). + +### Language Server Setup For this example to work, you'll need a JSON language server running on `ws://localhost:30000/sampleServer`. @@ -143,17 +209,19 @@ npm install npm run start:example:server:json ``` -This starts a JSON language server that our client can connect to. +This starts a JSON language server that our client is expecting to connect to. -### Step 4: Run Your Example +### Run Your Example -Start your development server and open your HTML file. You should see: +Go back to your development server and reload the page. You should see the same Monaco Editor instance but with language support. -1. **Monaco Editor** loaded with the JSON content -2. **Syntax highlighting** for JSON -3. **IntelliSense** when you type (try adding new properties) -4. **Error detection** if you introduce JSON syntax errors -5. **Schema validation** based on the `$schema` property +In addition to the basic editor functionality, you should also see: + +- **Syntax highlighting** for JSON +- **IntelliSense** when you type (try adding new properties) +- **Error detection** if you introduce JSON syntax errors + +If you see the content aligned strangely to the right, make sure that `text-align` isn't set to a particular direction (ex. `right` or `center`) in your styles. ## Understanding the Code @@ -199,10 +267,13 @@ Congratulations! If everything worked as expected, then you've created your firs ## Troubleshooting -**Editor doesn't load**: Check browser console for errors. Ensure all dependencies are installed. +**Editor doesn't load**: Check browser console for errors. Ensure all dependencies are installed. Also if the language server is offline, this will block the editor & client from starting up. + +Also ensure that you have compatible versions of `monaco-languageclient` and any `@codingame/...` extensions you are using. If there's a discrepancy here your editor or language client integration likely won't work, and you may not see any errors in the console. See the [version compatibility table](versions-and-history.md#monaco-editor--codingamemonaco-vscode-api-compatibility-table) for reference. **No language features**: Verify the language server is running and the WebSocket connection is successful. **Import errors**: Make sure you have the correct package versions and bundler configuration from the [Installation guide](../installation.md). + For more help, see our [Troubleshooting Guide](./troubleshooting.md). diff --git a/docs/index.md b/docs/index.md index 7677d01f2..847596ae3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,6 @@ # Monaco Language Client Documentation -Welcome to the official documentation for the `monaco-languageclient`. The `monaco-languageclient` library provides the ability to integrate the Monaco Editor with language clients and language servers utilizing the Language Server Protocol (LSP). Using the `monaco-languageclient`, you can build purely web-based editors with full LSP support, enabling features like code completion, diagnostics, and much more. +Welcome to the official documentation for the `monaco-languageclient`. The `monaco-languageclient` library provides the ability to integrate the Monaco Editor with language clients and language servers utilizing the Language Server Protocol (LSP). Using the `monaco-languageclient`, you can build purely web-based editors with full LSP support, enabling features like code completion, diagnostics, and more. This documentation is built to help newcomers and experts to be able to quickly leverage the `monaco-languageclient` effectively. @@ -10,12 +10,12 @@ In particular, the `monaco-languageclient` is helpful when you need to: - Build custom language support for specific programming languages in a web-based environment. - Utilize WebSocket or Web Worker connections to communicate with language servers deployed elsewhere. -We have partitioned the documentation into several sections that cover everything from what the `monaco-languageclient` is, to how to get started, to advanced usage. +We've split up the documentation into sections that cover a variety of topics, starting at an introduction, and later getting into specific guides: -- [Introduction](./introduction.md): Learn what the monaco-languageclient is, its key concepts, and how it fits into the ecosystem. +- [Introduction](./introduction.md): Learn what the `monaco-languageclient` is, its key concepts, and how it works. - [Installation](./installation.md): Step-by-step instructions to get started with `monaco-languageclient`, including dependencies and setup. -- [Guides](./guides/index.md): Guides on topics like getting started and troubleshooting. - - [Getting Started](./guides/getting-started.md): Your first monaco language client integration. +- [Guides](./guides/index.md): General overview of all guides. + - [Getting Started](./guides/getting-started.md): Walking through your first monaco language client integration. - [Configuration](./guides/configuration.md): Basic configuration options. - [Examples](./guides/examples.md): Simple examples to illustrate common use cases. - [Troubleshooting](./guides/troubleshooting.md): Common issues and solutions. diff --git a/docs/installation.md b/docs/installation.md index ceea4eed8..f2963c06f 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -10,7 +10,19 @@ Before installing Monaco Language Client, ensure you have: - **npm 10.2.3 or higher** - A web bundler (Vite, Webpack, etc.) that supports ES modules -Generally, we prefer to use Volta to manage Node.js versions. You can install it from [https://volta.sh/](https://volta.sh/). +We recommend using a Node.js version manager such as [nvm](https://github.com/nvm-sh/nvm) or [mise](https://mise.jdx.dev/). + +> [!NOTE] +> Previously we have recommended using Volta to manage your Node.js versions, but as of late it is currently [unmaintained](https://github.com/volta-cli/volta), and their team recommends moving to an alternative solution, such as mise or nvm. + +You'll also need a project that you can use to install the `monaco-languageclient`. If you don't have one yet, you can get [started quickly by creating a new Vite project](https://vite.dev/guide/#scaffolding-your-first-vite-project) with React: + +```shell +# create a new Vite React project +npm create vite@latest my-monaco-project -- --template react-ts +cd my-monaco-project +npm install +``` ## Perform the installation @@ -40,7 +52,7 @@ npm install @typefox/monaco-editor-react ### npm/pnpm -If using npm or pnpm, and your dependencies already contain a refernence to `monaco-editor`, add `overrides` to your `package.json` to ensure only one compatible `monaco-editor` dependency is used in your project: +If using npm or pnpm, and your dependencies already contain a reference to `monaco-editor`, add `overrides` to your `package.json` to ensure only one compatible `monaco-editor` dependency is used in your project: ```json { @@ -50,6 +62,8 @@ If using npm or pnpm, and your dependencies already contain a refernence to `mon } ``` +Depending on the version at the time of your installation, you may need to adjust the version range slightly to match the latest compatible version of `@codingame/monaco-vscode-editor-api`. + ### Yarn In yarn you have to specify `resolutions` instead of `overrides`: @@ -128,7 +142,7 @@ Then open to see various running examples. ## Version Compatibility -Monaco Language Client versions align with specific Monaco Editor and VSCode versions. See our [version compatibility table](versions-and-history.md#monaco-editor--codingamemonaco-vscode-api-compatibility-table) for details. +Keep in mind that monaco-languageclient versions align with specific Monaco Editor and VSCode versions. See our [version compatibility table](versions-and-history.md#monaco-editor--codingamemonaco-vscode-api-compatibility-table) to determine which versions can be used together. When in doubt, double check your `package.json` dependencies to ensure compatibility. ## Common Issues @@ -146,6 +160,4 @@ If you see console warnings about version mismatches, check that all `@codingame ## What's Next? -Once you have Monaco Language Client installed, you're ready to: - -1. **Follow the [Getting Started Guide](./guides/getting-started.md)** for your first setup +Once you have Monaco Language Client installed, you can hop over to the [Getting Started Guide](./guides/getting-started.md) for your first setup. diff --git a/docs/introduction.md b/docs/introduction.md index 962649e71..2a6a2d712 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -2,7 +2,7 @@ ## What is the Monaco Language Client? -The Monaco Language Client is a TypeScript library allowing to use the Language Server Protocol (LSP) directly with the monaco-editor. This lets it utilize language servers to extend the monoaco-editor's existing language support. Web applications can then provide rich language features such as code completion, diagnostics, Go To Definition support, and more, directly in the browser. +The Monaco Language Client is a TypeScript library that allows you to use the Language Server Protocol (LSP) directly with the monaco-editor. This lets you utilize language servers to extend the monoaco-editor's existing language support. Web applications can then provide rich language features such as code completion, diagnostics, Go To Definition support, and more; directly in the browser. ## Key Concepts @@ -11,7 +11,7 @@ To give some background, the monaco-languageclient builds on two main technologi - Language Server Protocol (LSP) and `vscode-languageclient` - `monaco-editor` and `@codingame/monaco-vscode-api` -We'll briefly explain each below. +We'll explain each below. ### Language Server Protocol (LSP) and vscode-languageclient @@ -23,7 +23,9 @@ The Language Server Protocol is a standard that defines how development tools ca - **Hover information** - Documentation and type information - **Code formatting** - Automatic code formatting -The `vscode-languageclient` is the library usually supplying client side support for the language server protocol for VSCode and its extensions. `monaco-languageclient` wraps this library directly and makes it available in the browser. It is made possible by the stack described in the next sub-section. +and more, as defined by the LSP specification. Most of the features you're accustomed to in a modern IDE for a language are made possible through the LSP. + +The `vscode-languageclient` is the most frequently used library to provide client side support for the language server protocol for VSCode and its extensions. `monaco-languageclient` wraps this library and makes it available in the browser. This feature is made possible by the stack described in the next sub-section about the monaco-editor & @codingame/monaco-vscode-api. ## monaco-editor and @codingame/monaco-vscode-api @@ -33,7 +35,7 @@ This is where the `@codingame/monaco-vscode-api` comes in. It supplies a modular ### How the Monaco Language Client Works -The Monaco Language Client acts as a communication layer between the Monaco Editor and one or many language servers. This allows it to: +The Monaco Language Client acts as a communication layer between the Monaco Editor and one or more language servers. This allows it to: 1. **Receive events** from the Monaco Editor (typing, cursor movement, etc.) 2. **Translate these events** into LSP messages @@ -50,26 +52,26 @@ The Monaco Language Client supports two main architectural patterns: In this configuration it's implied that the language server is running as a server on a backend (Node.js, Python, etc.) and communicates with the editor in the browser via WebSockets. ```shell -Web Browser Server + Web Browser Server ┌─────────────────┐ ┌──────────────────┐ │ Monaco Editor │ │ Language Server │ -│ ↕ │ │ (Node.js/Python/ │ -│ Language Client │ ←WebSocket→ │ Java/etc.) │ +│ ↕ │ ←WebSocket→ │ (Node.js/Python/ │ +│ Language Client │ │ Java/etc.) │ └─────────────────┘ └──────────────────┘ ``` ### Web Worker Communication -In this configuration, the language server runs in a Web Worker within the browser itself. This is useful for language servers that can be compiled to WebAssembly or plain JavaScript. [Langium](https://langium.org/), for example, can generate language servers that run purely in Web Workers. +In this configuration, the language server runs in a Web Worker within the browser itself. This is useful for language servers that can be compiled to WebAssembly or plain JavaScript. [Langium](https://langium.org/), for example, can generate language servers that run purely in Web Workers in this fashion. ```shell -Web Browser + Web Browser ┌────────────────────────────────────────┐ -│ Main Thread Web Worker │ +│ Main Thread Web Worker │ │ ┌─────────────────┐ ┌─────────────┐ │ │ │ Monaco Editor │ │ Language │ │ -│ │ ↕ │ │ Server │ │ -│ │ Language Client │ ←→ │ (WASM/JS) │ │ +│ │ ↕ │ ←→ │ Server │ │ +│ │ Language Client │ │ (WASM/JS) │ │ │ └─────────────────┘ └─────────────┘ │ └────────────────────────────────────────┘ ``` @@ -87,9 +89,9 @@ Uses `@codingame/monaco-vscode-api` to provide VSCode-like services and function - Rich VSCode services integration - Ability to use VSCode Web extensions -This is the recommended mode for _most_ use cases. If you're not sure which mode to use, start with the extended mode. +This is best for applications that want to provide VSCode-like functionality in the browser. -**Best for**: Applications that want VSCode-like functionality in the browser. +_This is the recommended mode for most use cases._ If you're not sure which mode to use, start with the extended mode. ### Classic Mode @@ -100,13 +102,15 @@ Uses a standalone Monaco Editor with language client features added on top. This - Simpler integration - Direct Monaco Editor API access -However, it lacks advanced features and services provided by the extended mode, and in _most_ cases is not recommended unless you have a specific need for it. +This is best for applications that need language server features but want to keep things simple, and do not require any or some elements of the VSCode API. + +However, keep in mind this mode lacks advanced features and services provided by the extended mode, and in _most_ cases is _not_ recommended unless you have a specific need for it. -**Best for**: Applications that need language server features but want to keep things simple. +Generally speaking, it's a good idea to start with extended mode until you have a specific reason or justification to switch to classic mode. ## When to Use the Monaco Language Client -The Monaco Language Client is ideal when you need to: +Overall, the Monaco Language Client is ideal when you need to: - **Build web-based IDEs or editors** with language support - **Add intelligent language features** to existing Monaco Editor integrations @@ -116,4 +120,4 @@ The Monaco Language Client is ideal when you need to: ## What's Next? -Ready to get started? Check out our [Installation Guide](./installation.md) to set up the monaco-languageclient in your project, or jump to [Basic Usage](./guides/getting-started.md) to start learning how to get started with simple examples. +Ready to get started? Check out our [Installation Guide](./installation.md) to set up the `monaco-languageclient` in your project, or jump to [Basic Usage](./guides/getting-started.md) to start learning how to get started with simple examples. diff --git a/packages/examples/src/common/client/extendedClient.ts b/packages/examples/src/common/client/extendedClient.ts index a639a8ed9..fa02b8d08 100644 --- a/packages/examples/src/common/client/extendedClient.ts +++ b/packages/examples/src/common/client/extendedClient.ts @@ -12,7 +12,6 @@ import { EditorApp, type EditorAppConfig } from 'monaco-languageclient/editorApp import { LanguageClientWrapper, type LanguageClientConfig } from 'monaco-languageclient/lcwrapper'; import { MonacoVscodeApiWrapper, type MonacoVscodeApiConfig } from 'monaco-languageclient/vscodeApiWrapper'; import { configureDefaultWorkerFactory } from 'monaco-languageclient/workerFactory'; -import { LangiumMonarchContent } from '../../langium/langium-dsl/config/langium.monarch.js'; export const runExtendedClient = async (lsConfig: ExampleLsConfig, helloCode: string) => { const helloUri = vscode.Uri.file(`${lsConfig.basePath}/workspace/hello.${lsConfig.languageId}`); @@ -79,10 +78,6 @@ export const runExtendedClient = async (lsConfig: ExampleLsConfig, helloCode: st text: helloCode, uri: helloUri.path } - }, - languageDef: { - monarchLanguage: LangiumMonarchContent, - languageExtensionConfig: { id: 'langium' } } };