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

Minimal example with extension support #465

Open
julian-baumann opened this issue Jul 13, 2024 · 47 comments
Open

Minimal example with extension support #465

julian-baumann opened this issue Jul 13, 2024 · 47 comments

Comments

@julian-baumann
Copy link

julian-baumann commented Jul 13, 2024

I am trying to set up a minimal code editor with support for extensions, themes, and LSP. Despite being aware of #444, I’m still struggling to understand how to load a local VSCode extension from a vsix file and get it functioning.

I would greatly appreciate any help to get me started in the right direction :)

Here is a simplified example of what I've already come up with. I am trying to load the Swift extension and get LSP working. Especially with webpack.

import "vscode/localExtensionHost";

import { AfterViewInit, Component, ElementRef, ViewChild } from "@angular/core";
import getExtensionServiceOverride, { WorkerConfig } from "@codingame/monaco-vscode-extensions-service-override";
import getLanguagesServiceOverride from "@codingame/monaco-vscode-languages-service-override";
import getModelServiceOverride from "@codingame/monaco-vscode-model-service-override";
import getTextmateServiceOverride from "@codingame/monaco-vscode-textmate-service-override";
import getThemeServiceOverride from "@codingame/monaco-vscode-theme-service-override";
import { editor } from "monaco-editor";
import { extensions } from "vscode";
import { initialize as initializeMonacoService} from "vscode/services";

export type WorkerLoader = () => Worker;

export const workerConfig: WorkerConfig = {
    url: new URL("vscode/workers/extensionHost.worker", import.meta.url).toString(),
    options: { type: "module" }
};
const value = `func test() -> String {
    print("Hello World")
    return "Test"
}`;

const workerLoaders: Partial<Record<string, WorkerLoader>> = {
    editorWorkerService: () => new Worker(new URL("monaco-editor/esm/vs/editor/editor.worker.js", import.meta.url), { type: "module" }),
    textMateWorker: () => new Worker(new URL("@codingame/monaco-vscode-textmate-service-override/worker", import.meta.url), { type: "module" })
};

window.MonacoEnvironment = {
    getWorker: function (moduleId, label): Worker {
        const workerFactory = workerLoaders[label];
        if (workerFactory != null) {
            return workerFactory();
        }
        throw new Error(`Unimplemented worker ${label} (${moduleId})`);
    }
};

await initializeMonacoService({
    ...getModelServiceOverride(),
    ...getExtensionServiceOverride(workerConfig),
    ...getThemeServiceOverride(),
    ...getLanguagesServiceOverride(),
    ...getTextmateServiceOverride()
});

// Not sure about this one. Doesn't work either
const extension = extensions.getExtension("sswg.swift-lang");
extension?.activate();

editor.create(this.editorRef?.nativeElement, {
    value: value,
    language: "swift"
});
@CGNonofr
Copy link
Contributor

There is no web-compatible swift extension, so with the vsix loader, you may manage to get the declarative parts working (like syntax highlighting or snippets) but not the LSP part or anything requiring extension code to work.

A server will be required to run the LSP server, and there are multiple ways to connect to it from the client:

  • Create your own channel to forward LSP messages from your client to your server, and synchronize files by hands
  • Use the VSCode server, then extract the vsix file somewhere on the server, and use the registerRemoteExtension function from vscode/extensions

@julian-baumann
Copy link
Author

Thank you very much for your response. I've now got the vscode-server up and running and installed the swift vsix extension via ./bin/code-server --install-extension <path>. It is successfully installed and shows up under ./bin/code-server --list-extensions. But it doesn't quite work yet with my client... I have enabled scanRemoteExtensions, but the extension does not show up in vscode.extensions.all.

You also mentioned the registerRemoteExtension method, which takes a directory path as argument. What path should I provide here?

I've started the server with the following argumens: ./bin/code-server --port 8080 --without-connection-token --accept-server-license-terms --host 0.0.0.0, which gives me a successfull response, telling me that the extensions host is running

*
* Visual Studio Code Server
*
* By using the software, you agree to
* the Visual Studio Code Server License Terms (https://aka.ms/vscode-server-license) and
* the Microsoft Privacy Statement (https://privacy.microsoft.com/en-US/privacystatement).
*
Server bound to 0.0.0.0:8080 (IPv4)
Extension host agent listening on 8080

[22:47:21] 




[22:47:21] Extension host agent started.

Now on my client, I don't see the extension. This is my updated code:

const value = `func test() -> String {
    print("Hello World")
    return "Test"
}`;
const workerLoaders: Partial<Record<string, WorkerLoader>> = {
    editorWorkerService: () => new Worker(new URL("monaco-editor/esm/vs/editor/editor.worker.js", import.meta.url), { type: "module" }),
    textMateWorker: () => new Worker(new URL("@codingame/monaco-vscode-textmate-service-override/worker", import.meta.url), { type: "module" })
};

window.MonacoEnvironment = {
    getWorker: function (moduleId, label): Worker {
        const workerFactory = workerLoaders[label];
        if (workerFactory != null) {
            return workerFactory();
        }
        throw new Error(`Unimplemented worker ${label} (${moduleId})`);
    }
};

const fileSystemProvider = new RegisteredFileSystemProvider(false);
fileSystemProvider.registerFile(new RegisteredMemoryFile(monaco.Uri.file("/main.swift"), value));

registerFileSystemOverlay(1, fileSystemProvider);
await initializeMonacoService({
    ...getRemoteAgentServiceOverride({
        scanRemoteExtensions: true
    }),
    ...getModelServiceOverride(),
    ...getExtensionServiceOverride(),
    ...getThemeServiceOverride(),
    ...getLanguagesServiceOverride(),
    ...getTextmateServiceOverride(),
    ...getViewsServiceOverride(),
    ...getFileServiceOverride(),
    ...getSearchServiceOverride()
}, undefined, {
    remoteAuthority: "localhost:8080"
});

console.log("extensions", vscode.extensions.all);

attachPart(Parts.EDITOR_PART, this.editorRef.nativeElement!);

vscode.workspace.openTextDocument("/main.swift").then((doc) => {
    vscode.window.showTextDocument(doc);
});

But still vscode.extensions.all is empty.

Am I missing something?

@julian-baumann
Copy link
Author

I’m not certain if this is related to the issue, but I’m also encountering the following console errors:

CodeExpectedError: ENOPRO: No file system provider found for resource 'inmemory://model/'
Error: Not implemented
    at StandaloneUriLabelService.registerFormatter (standaloneServices.js:797:17)
CodeExpectedError: ENOPRO: No file system provider found for resource 'inmemory://model/'

If they're not related, I will address them later on. For now I would just like to get the extensions working.

@julian-baumann
Copy link
Author

Update: I think I got the extension working, by using registerRemoteExtension with the directory of the installed extension, usually installed in ~/.vscode-server/extensions/

const extension = await registerRemoteExtension("~/.vscode-server/extensions/sswg.swift-lang-1.10.4");

But there is no syntax highlighting or code completion enabled in the editor. Is there something I need to enable?

@CGNonofr
Copy link
Contributor

But still vscode.extensions.all is empty.

This api doesn't allow to see extension running on another extension host, so calling it from the localExtensionHost will not allow you to see the extension running in the server extension host

You can try to use the extension gallery service override to extension statuses

But there is no syntax highlighting or code completion enabled in the editor. Is there something I need to enable?

Is there anything working then?

If you provide a reproduction repo, I may be able to help

@CGNonofr
Copy link
Contributor

I’m not certain if this is related to the issue, but I’m also encountering the following console errors:

CodeExpectedError: ENOPRO: No file system provider found for resource 'inmemory://model/'

Hum no idea 🤔

Error: Not implemented
    at StandaloneUriLabelService.registerFormatter (standaloneServices.js:797:17)

fixed in #467

@julian-baumann
Copy link
Author

Thank you very much for your assistance so far. I’m gradually gaining a deeper understanding of how everything works here.

Is there anything working then?

Not really, but

const extension = await registerRemoteExtension("~/.vscode-server/extensions/sswg.swift-lang-1.10.4");

extension.isEnabled() returns true and I see this warning log in the console

 WARN [sswg.swift-lang]: View container 'explorer' does not exist and all views registered to it will be added to 'Explorer'.

So it seems like the extension is doing something.

If you provide a reproduction repo, I may be able to help

I will take care of that today and get back to you with a response, thanks

@julian-baumann
Copy link
Author

julian-baumann commented Jul 16, 2024

I’ve hacked together a brief demo which you can find here: https://github.com/julian-baumann/monaco-vscode-demo

For detailed setup instructions, please refer to the README. All the essential code is located in a single file: ./src/app/app.component.ts

It should more or less work out of the box. Let me know if you encounter any issues.

@CGNonofr
Copy link
Contributor

Ok, so,your problems:

  • you're importing @codingame/monaco-vscode-configuration-service-override but not using the getServiceOverride method, you're not supposed to import a service override without using it, and the configuration service override is pretty much required as it's the one managing the workspace folders as well
  • the swift-lang extensions registers a lot of stuff, and requires the corresponding service overrides to be registered to suppress the errors:
    • @codingame/monaco-vscode-extension-gallery-service-override
    • @codingame/monaco-vscode-explorer-service-override
    • @codingame/monaco-vscode-debug-service-override
    • @codingame/monaco-vscode-storage-service-override
    • @codingame/monaco-vscode-terminal-service-override
    • @codingame/monaco-vscode-chat-service-override
    • @codingame/monaco-vscode-scm-service-override
  • the swift-lang extension is not responsible for the syntax highlighting, but the default swift extension instead, import @codingame/monaco-vscode-swift-default-extension
  • The exported services are the one designed for the web version, and running them in electron doesn't work well. That's the reason for the @codingame/monaco-vscode-swift-default-extension to be not working: in electron, the web extension management server is unable to register any extension manager server, so there is no place for the extension to run

@julian-baumann
Copy link
Author

Thank you, I've tried importing the required overrides, but as you mentioned, it doesn't work in electron. Do you happen to know any workaround or solution on how to get it running in electron?

In the meanwhile, I've also create a new vite+React project with a the same code as in the angular application which can be found here: https://github.com/julian-baumann/monaco-vscode-demo/tree/vite
This one also runs in the browser, and we see a working syntax highlighting! But still no code suggestions/completions or errors. In the console we see the following log message:

[Extension Host] 00:21:17: SourceKit-LSP setup

So it seems like it is trying to start the LSP service. But no indication whether it started successfully or not...

Any ideas?

@julian-baumann
Copy link
Author

Update: I got LSP working!
I had to load the project via the code-server (vscode-remote://localhost:8080/...), rather than using the RegisteredFileSystemProvider.

The only thing not working right now is loading the @codingame/monaco-vscode-swift-default-extension extension via electron.

@CGNonofr
Copy link
Contributor

I'm not aware of any workaround, we need to allow using the electron services in the lib

@julian-baumann
Copy link
Author

Seems like it's working if we disable nodeIntegration and use a preload.js for all node related stuff as intended by electron.

@ivan-kzn
Copy link

@julian-baumann could you please push working changes to your repo?

@julian-baumann
Copy link
Author

julian-baumann commented Jul 18, 2024

I've just pushed a working version on main. But I will probably not continue with this project, since it was only a small demo to test everything. But the current angular project on the main branch should work fine both in the browser and in electorn. Please make sure to update the projectPath field in ./src/app/app.component.ts to a valid swift project, like to the one included in the root of the repo (has to be an absolute path).

@ivan-kzn
Copy link

ivan-kzn commented Jul 18, 2024

I understand, thanks! I just faced with same issue to make everything work together

@julian-baumann
Copy link
Author

I may not be able to assist you with any further problems, but if you encounter any issues specifically with my test project, please don’t hesitate to contact me.

@brianjenkins94
Copy link

I'm trying to do something very similar here: https://github.com/brianjenkins94/monaco-vscode-api-esbuild

but can't quite make sense of some of these console errors:

image

@brianjenkins94
Copy link

@CGNonofr was hoping you could take a look maybe? ^ 🙏

@CGNonofr
Copy link
Contributor

esbuild doesn't handle well assets urls, that's why we add to use a custom plugin in the demo, maybe it's your issue?

@brianjenkins94
Copy link

brianjenkins94 commented Jul 23, 2024

I'm handling that already: https://github.com/brianjenkins94/monaco-vscode-api-esbuild/blob/main/tsup.config.ts#L38

Here it is on GitHub Pages if you don't want to try it locally: https://brianjenkins94.github.io/monaco-vscode-api-esbuild/

@CGNonofr
Copy link
Contributor

No idea why it tries to load extensionHostWorker.js from https://brianjenkins94.github.io/monaco-vscode-api-esbuild/vscode/src/vs/workbench/api/worker/extensionHostWorker.js, there is very probably a configuration issue

I didn't really understand your recursive update of the importMetaUrlPlugin

Copy link

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Aug 24, 2024
@brianjenkins94
Copy link

brianjenkins94 commented Aug 30, 2024

Ah, looks to be related to all that fakeWorker stuff.

Is it possible to load the workers from a CDN or something?

Maybe via MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker?

Looks like that would only work for the editorWorkerService.

Maybe I just need to change the workerConfig...

@brianjenkins94
Copy link

brianjenkins94 commented Aug 30, 2024

Unfortunately, very stuck on:

simpleWorker.js: Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/microsoft/monaco-editor#faq

Latest attempt here: https://brianjenkins94.github.io/monaco-vscode-api-esbuild/

@github-actions github-actions bot removed the stale label Aug 31, 2024
@CGNonofr
Copy link
Contributor

Sorry, I'm really not familiar enough with esbuild

It's maybe a good opportunity for you to get into the code, since it's a quite complex project to use anyway, better understand it as much as possible

@brianjenkins94
Copy link

brianjenkins94 commented Sep 10, 2024

The piece I'm stuck on is why the service workers aren't working. Everything else seems okay.

@CGNonofr
Copy link
Contributor

You can have a look at the devtools, which file it's trying to load in the worker, and add breakpoints in the code where the error occurs. That's what I would be doing if I had to investigate it

@brianjenkins94
Copy link

Is there anywhere else I can ask to get more informational error messages or debug info?

Breakpoints and stepping aren't yielding anything helpful, just generic errors.

@CGNonofr
Copy link
Contributor

I don't think so

But you are the one creating the worker, you can have a look at the worker url to see if there is anything wrong

@brianjenkins94
Copy link

A new error message! How exciting!

Unimplemented worker editorWorkerService (workerMain.js)

Seems there may have been a name change and now it's called TextEditorWorker?

@CGNonofr
Copy link
Contributor

Yes, in the last version, have a look at https://github.com/CodinGame/monaco-vscode-api/releases/tag/v9.0.0

@brianjenkins94
Copy link

brianjenkins94 commented Sep 16, 2024

It looks like it's still called editorWorkerService in demo/node_modules/vscode/vscode/src/vs/editor/common/services/editorWorker.js:

import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
-const IEditorWorkerService = ( createDecorator('editorWorkerService'));
export { IEditorWorkerService };

@CGNonofr
Copy link
Contributor

Did you update VSCode and rebuild the library, because the node_modules/vscode of the demo just link to the root directory

@brianjenkins94
Copy link

Yes, I even did npm cache clean --force and confirmed that npm list vscode --depth=0 yields vscode@npm:@codingame/[email protected].

@CGNonofr
Copy link
Contributor

I'm not sure how you manage to make npm list vscode return vscode@npm:@codingame/[email protected] in the demo since it's a local dependency 🤔

@CGNonofr
Copy link
Contributor

Btw, you're mixing up the worker name with the service name. I didn't properly pay attention

@brianjenkins94
Copy link

Actually, mine looks to be throwing all the same warnings that https://monaco-vscode-api.netlify.app/ is throwing.

Mine just only knows about plain text?

@CGNonofr
Copy link
Contributor

Oh, indeed, I've desactivated the console warnings for some reason and I didn't see it, it seems broken, will have a look

@CGNonofr
Copy link
Contributor

CGNonofr commented Sep 17, 2024

Ok, the worker was renamed in the VSCode service, but not in the standalone service, and the lib still uses the standalone service

I'll release a 9.0.1 with the fix, in the meantime you can keep editorWorkerService as worker name

@CGNonofr
Copy link
Contributor

#499

@brianjenkins94
Copy link

Awesome, it's working!

Last step is to load my hello-world extension but using registerFileUrl looks to yield CSP errors:

const { registerFileUrl, getApi } = registerExtension({
	"name": "helloworld-web-sample",
	"displayName": "helloworld-web-sample",
	"description": "HelloWorld example for VS Code in the browser",
	"version": "0.0.1",
	"publisher": "vscode-samples",
	"private": true,
	"license": "MIT",
	"repository": "https://github.com/microsoft/vscode-extension-samples/helloworld-web-sample",
	"engines": {
		"vscode": "^1.84.0"
	},
	"categories": [
		"Other"
	],
	"activationEvents": [
		"onLanguage:plaintext"
	],
	"browser": "./extension.js",
	...
}, ExtensionHostKind.LocalWebWorker);

registerFileUrl('/package.json', new URL('./extensions/hello-world/package.json', import.meta.url).toString())
extensionHost.worker-3a9df9.js:73407 Refused to connect to 'extension-file://vscode-samples.helloworld-web-sample/extension.js' because it violates the following Content Security Policy directive: "connect-src 'self'

@CGNonofr
Copy link
Contributor

You seems to be never registering the extension.js file?

@caner-cetin
Copy link

caner-cetin commented Oct 17, 2024

No, issue is not that, I am also having same issue loading COBOL LSP. I dont need vscode server and I dont need workspace, workbench, all kinds of stuff because main intent is the single file editor.

import("src/editor/extensions/cobol-language-support-2.2.0.vsix"),

is successfully ran but

Content-Security-Policy: The page’s settings blocked the loading of a resource (connect-src) at data:application/javascript;base64,InVzZ… because it violates the following directive: “connect-src 'self' https: wss: http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:*” [webWorkerExtensionHostIframe.esm.html](http://localhost:5173/node_modules/@codingame/monaco-vscode-extensions-service-override/assets/webWorkerExtensionHostIframe.esm.html?vscode-coi=3&vscodeWebWorkerExtHostId=be4a2c52-e647-4ac9-86c2-b5b359e98d33)
Activating extension 'BroadcomMFD.cobol-language-support' failed: NetworkError when attempting to fetch resource..

browser does not let me load that vsix file.

https://github.com/eclipse-che4z/che-che4z-lsp-for-cobol/releases/download/2.2.0/cobol-language-support-2.2.0.vsix

try with SCRIPT.CBL, default text

IDENTIFICATION DIVISION.
PROGRAM-ID. IDSAMPLE.
ENVIRONMENT DIVISION.
PROCEDURE DIVISION.
    DISPLAY 'DENIZ ABI KORNAYA BAS'.
    STOP RUN.

edit: If I cant run LSP from browser, what is the most sane way to run this extension without setupping whole remote server?

@CGNonofr
Copy link
Contributor

I dont need vscode server and I dont need workspace, workbench, all kinds of stuff because main intent is the single file editor.

That's a bold assumption

Your issue if cause by the worker extension host being strict on CSP, and your bundler transform assets into data: urls that are not allowed. You can try forcing it to emit asset to the disk, I'll have a lookif it's possible to allow it

@caner-cetin
Copy link

caner-cetin commented Oct 17, 2024

Mhm, deleted

		<meta http-equiv="Content-Security-Policy" content="
			default-src 'none';
			child-src 'self' data: blob:;
			script-src 'self' 'unsafe-eval' 'sha256-fCnZ3iXydTZHO961jO3ioYDdWSfm8PZg/rI6zFX/SE0=' https: http://localhost:* blob:;
			connect-src 'self' https: wss: http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:*;"/>

from worker myself, and even then it is not working that well (extension is not loaded at all, commands are not there. pressing tab throws error "cobol-lsp.smart-tab" doesnt exist but there is one in package json).

i guess i am going for workspace & vs server lol

@CGNonofr
Copy link
Contributor

I've tried you extension in vscode.dev, and there are the same issues (at least the smart-tab command missing) so the extension is not so web-compatible after all

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

No branches or pull requests

5 participants