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

Add example with client and server both running in the browser #386

Merged
merged 1 commit into from
Jun 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to this project will be documented in this file.

## [2.0.0] - Not yet release

* TBA

## [1.1.0] - 2022-06-08

* feat(package.json): export monaco-converter #[376](https://github.com/TypeFox/monaco-languageclient/pull/376)
Expand Down
42 changes: 30 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- [Scripts Overview](#scripts-overview)
- [**Examples**](#examples)
- [ Node.js Language Server + web client example](#nodejs-language-server-plus-web-client-example)
- [Browser-LSP](#browser-language-client-and-server)
- [Browser](#browser-example)
- [VSCode integration](#vscode-integration)
- [**History**](CHANGELOG.md)
Expand Down Expand Up @@ -63,13 +64,19 @@ cd packages/client && npm run build

## Examples

There are two different examples (one is a client-server one now separated) that demonstrate how the `monaco-languageclient` can be used. The Node.js example uses Express and WebSockets to enable communication between the language server process and the web application. The browser example shows how a language service written in JavaScript can be used in a Monaco Editor contained in a simple HTML page.
There are three examples different examples that demonstrate how the `monaco-languageclient` can be used. The Node.js example uses Express and WebSockets to enable communication between the language server process and the web application.

The Browser Language Client & Server examples does the same, but the server runs in a web worker and communication is via direct LSP message exchange.

The browser example shows how a language service written in JavaScript can be used in a Monaco
Editor contained in a simple HTML page.

All example packages now are now located under [./packages/examples](./packages/examples):

- Node.js Language Server example: [./packages/examples/node](./packages/examples/node): - Look at the [example express app](https://github.com/TypeFox/monaco-languageclient/blob/sandbox-331/packages/examples/node/src/server.ts) to learn how to open a web socket with an express app and launch a language server within the current process or as an external process.
- Web Client for Node.js Language Server: [./packages/examples/client](./packages/examples/client): Look at the [example client](https://github.com/TypeFox/monaco-languageclient/blob/sandbox-331/packages/examples/client/src/client.ts) to learn how to start Monaco language client.
- Browser example: [./packages/examples/browser](./packages/examples/browser): Look at the [browser example](https://github.com/TypeFox/monaco-languageclient/blob/sandbox-331/packages/examples/browser/src/client.ts) to learn how to use a language service written in JavaScript in a simple HTML page.
- Node.js Language Server example: [./packages/examples/node](./packages/examples/node): - Look at the [example express app](https://github.com/TypeFox/monaco-languageclient/blob/main/packages/examples/node/src/server.ts) to learn how to open a web socket with an express app and launch a language server within the current process or as an external process.
- Web Client for Node.js Language Server: [./packages/examples/client](./packages/examples/client): Look at the [example client](https://github.com/TypeFox/monaco-languageclient/blob/main/packages/examples/client/src/client.ts) to learn how to start Monaco language client.
- Browser Language Client and Server: [./packages/examples/browser-lsp](./packages/examples/browser-lsp): Look at the [client](https://github.com/TypeFox/monaco-languageclient/blob/main/packages/examples/browser-lsp/src/client.ts) and the [web worker](https://github.com/TypeFox/monaco-languageclient/blob/main/packages/examples/browser-lsp/src/serverWorker.ts) implementing the language server. They communicate via `vscode-languageserver-protocol/browser` instead of a web socket used in the first example.
- Browser example: [./packages/examples/browser](./packages/examples/browser): Look at the [browser example](https://github.com/TypeFox/monaco-languageclient/blob/main/packages/examples/browser/src/client.ts) to learn how to use a language service written in JavaScript in a simple HTML page ([here](https://github.com/TypeFox/monaco-languageclient/blob/main/packages/examples/browser-old/src/client.ts) you find the old now deprecated implementation using the [monaco converters](https://github.com/TypeFox/monaco-languageclient/blob/main/packages/client/src/monaco-converters.ts).)

### Node.js Language Server plus web client example

Expand All @@ -86,9 +93,24 @@ npm run start-example-node:ext
npm run dev
```

After launching vite development server go to http://localhost:8080/packages/examples/client/index.html
After launching vite development server go to [client example](http://localhost:8080/packages/examples/client/index.html)

**Hints for all examples:** Vite serves all client code from [localhost](http://localhost:8080). You can go to the [index.html](http://localhost:8080/index.html) and navigate to all client examples from there. You can edit the client example code directly (TypeScript) and vite ensures it automatically made available.

### Browser Language Client and Server

You can edit the client example code directly (TypeScript) and vite ensures it automatically made available.
If you have build all packages or the specific package `packages/examples/browser-lsp` before you just need to run the vite development server:

```bash
# Optional: Build all packages
npm run build
# Launch vite development server if not already done
npm run dev
```

After launching vite development an go to the [example](http://localhost:8080/packages/examples/browser-lsp/index.html)

**Hint:** If you change the worker code, you have to re-create it (use `npm run build:worker` from the within the example [directory](./packages/examples/browser-lsp)!

### Browser example

Expand All @@ -99,13 +121,9 @@ From CLI in root of the project you just need to run. If it is already running t
npm run dev
```

After launching vite development server go to http://localhost:8080/packages/examples/browser/index.html

You can also go to http://localhost:8080/packages/examples/browser-old/index.html for the old implementation using the deprecated monaco converters

You can edit the client example code directly (TypeScript) and vite ensures it automatically made available
After launching vite development an go to the [example](http://localhost:8080/packages/examples/browser/index.html)

**Hint:** Vite serves all client code from http://localhost:8080 . You can go to the index.html and from there select if you want to open **Web Client for Node.js Language Server** or **Browser Example** as well.
You can also [go to](http://localhost:8080/packages/examples/browser-old/index.html) for the old implementation using the deprecated monaco converters.

### Optional webpack build for client example

Expand Down
2 changes: 2 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ <h1>Examples</h1>
<br>
<a href="packages/examples/browser/index.html">Browser Example</a>
<br>
<a href="packages/examples/browser-lsp/index.html">Browser Language Client & Server</a>
<br>
<a href="packages/examples/browser-old/index.html">Browser Example old (using monaco-converter)</a>
</div>
</body>
Expand Down
24 changes: 24 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@
"dev": "vite --debug --force",
"start-example-node": "npm run start --workspace packages/examples/node",
"start-example-node:ext": "npm run start:ext --workspace packages/examples/node",
"build": "npm run build-client && npm run build-example-node && npm run build-example-client && npm run build-example-browser && npm run build-example-browser-old",
"build": "npm run build --workspaces",
"build-client": "npm run build --workspace packages/client",
"build-example-node": "npm run build --workspace packages/examples/node",
"build-example-client": "npm run build --workspace packages/examples/client && npm run webpack:example-client-build",
"build-example-browser-lsp": "npm run build --workspace packages/examples/browser-lsp",
"build-example-browser": "npm run build --workspace packages/examples/browser",
"build-example-browser-old": "npm run build --workspace packages/examples/browser-old",
"webpack:example-client-build": "npm run webpack:build --workspace packages/examples/client",
Expand All @@ -40,6 +41,7 @@
"packages/client",
"packages/examples/node",
"packages/examples/client",
"packages/examples/browser-lsp",
"packages/examples/browser",
"packages/examples/browser-old"
]
Expand Down
16 changes: 16 additions & 0 deletions packages/examples/browser-lsp/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>

<head>
<title>Monaco Language Client Browser Language Client & Server</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script defer type="module" src="src/client.ts"></script>
</head>

<body>
<h2>Monaco Language Client Browser Language Client & Server</h2>
<div id="container" style="width:800px;height:600px;border:1px solid grey"></div>
</body>

</html>
19 changes: 19 additions & 0 deletions packages/examples/browser-lsp/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "browser-lsp",
"private": true,
"dependencies": {
"monaco-editor": "0.33.0",
"monaco-editor-workers": "0.33.0",
"monaco-languageclient": "../../client",
"vscode-languageserver": "8.0.1",
"vscode-languageserver-protocol": "3.17.1"
},
"scripts": {
"clean": "npx shx rm -fr dist tsconfig.tsbuildinfo",
"compile": "tsc",
"watch": "tsc -w",
"copy:monacoworkers": "shx mkdir -p dist && shx cp -r ../../../node_modules/monaco-editor-workers/dist/workers/editorWorker* ./dist",
"build:worker": "vite -c vite.config.worker.ts build",
"build": "npm run clean && npm run compile && npm run build:worker && npm run copy:monacoworkers"
}
}
79 changes: 79 additions & 0 deletions packages/examples/browser-lsp/src/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) 2018-2022 TypeFox GmbH (http://www.typefox.io). All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import 'monaco-editor/esm/vs/editor/editor.all.js';

// support all editor features
import 'monaco-editor/esm/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.js';
import 'monaco-editor/esm/vs/editor/standalone/browser/inspectTokens/inspectTokens.js';
import 'monaco-editor/esm/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.js';
import 'monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess.js';
import 'monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess.js';
import 'monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess.js';
import 'monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.js';
import 'monaco-editor/esm/vs/editor/standalone/browser/quickInput/standaloneQuickInputService.js';
import 'monaco-editor/esm/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.js';
import 'monaco-editor/esm/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.js';

import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';

import { buildWorkerDefinition } from 'monaco-editor-workers';
buildWorkerDefinition('dist', new URL('', window.location.href).href, false);

import { MonacoLanguageClient, CloseAction, ErrorAction, MonacoServices, MessageTransports } from 'monaco-languageclient';
import { BrowserMessageReader, BrowserMessageWriter } from 'vscode-languageserver-protocol/browser';

// register Monaco languages
monaco.languages.register({
id: 'plaintext',
extensions: ['.txt'],
aliases: ['PLAINTEXT', 'plaintext'],
mimetypes: ['text/plain']
});

// create Monaco editor
const editorText = `
#ff0000 (red)
#00ff00 (green)
#0000ff (blue)
`;
monaco.editor.create(document.getElementById("container")!, {
model: monaco.editor.createModel(editorText, 'plaintext', monaco.Uri.parse('inmemory://model.txt')),
glyphMargin: true,
lightbulb: {
enabled: true
}
});

function createLanguageClient(transports: MessageTransports): MonacoLanguageClient {
return new MonacoLanguageClient({
name: "Sample Language Client",
clientOptions: {
// use a language id as a document selector
documentSelector: [{ language: 'plaintext' }],
// disable the default error handler
errorHandler: {
error: () => ({ action: ErrorAction.Continue }),
closed: () => ({ action: CloseAction.DoNotRestart })
}
},
// create a language client connection to the server running in the web worker
connectionProvider: {
get: () => {
return Promise.resolve(transports);
}
}
});
}

// install Monaco language client services
MonacoServices.install();

const worker = new Worker(new URL('./dist/serverWorker-es.js', window.location.href).href);
const reader = new BrowserMessageReader(worker);
const writer = new BrowserMessageWriter(worker);
const languageClient = createLanguageClient({ reader, writer });
languageClient.start();

reader.onClose(() => languageClient.stop());
Loading