typefox / monaco-components Goto Github PK
View Code? Open in Web Editor NEWMonaco Editor and Language Client Wrapper, plus Monaco Editor React Component
License: MIT License
Monaco Editor and Language Client Wrapper, plus Monaco Editor React Component
License: MIT License
Once TypeFox/monaco-languageclient#600 is merged and the next major release of all npm packages is ready this repository will be archived. This TypeFox/monaco-languageclient#543 (comment) summarizes the reasons pretty well. Overall maintenance effort is reduced and all monaco related packages and all helpful examples are concentrated at one location.
All open issues that are still relevant will be transferred over.
Hi, is there a way to prevent the monaco editor wrapper messing with the css styling up to the body tag?
e.g. in dark mode "everything" gets dark
Hi, i am trying to get the MonacoEditorReactComp
combined with registerFileSystemOverlay
in order to have library files available for referencing in the editor.
unfortnately vite/esbuild have problems to bundle it.
any ideas/hints? thanks
✘ [ERROR] No matching export in "node_modules/monaco-editor/esm/vs/nls.js" for import "localizeWithPath"
node_modules/@codingame/monaco-vscode-files-service-override/node_modules/vscode/vscode/src/vs/platform/files/common/io.js:3:9:
3 │ import { localizeWithPath } from 'monaco-editor/esm/vs/nls.js';
https://github.com/cdietrich/my-monaco-editor-react-example/tree/cd/otherFilesExperiments
moned-full
to monaco-editor-comp
and moned-lc
to monaco-editor-lc-comp
.
This pertains to the MonacoEditorLanguageClientWrapper
when using a worker for the language server.
When starting the wrapper up, if the languageClientWrapper internally fails to start for some reason (such as when working with a misconfigured LS), it's possible to get the LC stuck in a 'starting' state. In such a case disposing of the wrapper, which has failed to start, will also fail because the language client cannot be cleaned up. Due to the order of execution for cleanup on dispose, this means the worker for the language server (if using a worker & not a WS) can be leaked during dispose.
We should ensure that the worker is always cleaned up upon dispose, even if the language client fails on being disposed itself.
When installing [email protected]
with yarn, a postinstall : monaco-treemending
script is run and it shows the command is not found.
It seems the latest commit removed postinstall : monaco-treemending
script in this repository, but the changes are not released yet.
When I traced the Peer Dependencies of [email protected]
to the monaco-treemending
script, it went like
[email protected]
👉 [email protected]
👉 @codingame/monaco-vscode-api@~1.78.6
I could see the actual monaco-treemending
js script is present only in the @codingame/monaco-vscode-api@~1.78.6
package, not in any of the other packages.
Now coming to the issue, when installing monaco-editor-wrapper
, npm
is somehow looking into the peer dependencies and executing the bin
scripts from @codingame/monaco-vscode-api@~1.78.6 , but this is not the case for yarn
. Yarn is only looking in that package and avoiding the peer dependencies(I guess).
Because of this, yarn becomes unusable with the latest monaco-languageclient packages.
yarn create vite
Choose any Framework and try the below command
yarn add [email protected]
(or)
yarn add [email protected]
Do we need postinstall : monaco-treemending
script in monaco-languageclient
package? As it is already taken care of by @codingame/monaco-vscode-api
and only that package has the js script to run...
Thanks.
Hi, any hints how to solve
[vite]: Rollup failed to resolve import "vscode/service-override/configuration" from "/Users/dietrich/git/my-monaco-editor-react-example/node_modules/monaco-editor-wrapper/dist/editorAppBase.js".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
Hi there, in my Monarch syntax highlighter, I have a rule where it uses embedded language:
initial: [
[
/^\s*%%(?={)/,
{ token: 'keyword', bracket: '@open', next: '@directive', nextEmbedded: 'javascript' },
],
// other rules
]
When I enter that state, I can type anything, except newlines. And when I removed javascript
and made it empty, it worked fine but without the language features.
I tried the code in https://microsoft.github.io/monaco-editor/monarch.html to check if the issue was in my code, but it's working fine.
Here's the minimum Monarch code:
export default {
tokenizer: {
initial: [
[
/^\s*%%(?={)/,
{ token: 'keyword', bracket: '@open', next: '@directive', nextEmbedded: 'javascript' },
],
],
directive: [
[/%%$/, { token: 'keyword', bracket: '@close', next: '@pop', nextEmbedded: '@pop' }],
],
},
};
Hello,
The UserConfig
property of the MonacoEditorReactComp
allows us to initialise the content of the editor using wrapperConfig
/ editorAppConfig
/ code property.
For example:
const userConfig: UserConfig = {
htmlElement: rootElem,
wrapperConfig: {
...
editorAppConfig: {
$type: 'classic',
languageId: 'typescript',
useDiffEditor: false,
theme: 'vs-light',
code: content,
},
},
};
<MonacoEditorReactComp
ref={editorRef}
userConfig={userConfig}
/>
I would like to push an external update to the current editor code, let's consider a button that add a new console.log('Hello')
to the editor.
My first attempt was using the useState
hook:
const [content, setContent ] = useState(initialCode);
And then call the setContent
inside of the onClickHandler
of the button, but this cause a restart of the editor getting a flickering in the UI.
Then I found that I can access the current value of the editor as follow:
const editor = editorRef.current?.getEditorWrapper().getEditor();
const currentCode= editor?.getValue();
and I tried to update the value of the editor inside of a useEffect with content
as dependency. In this case, I initialised the wrapperConfig
/ editorAppConfig
/ code property with an empty string
editor?.setValue(content);
That approach was worst fully crashing the editor.
My third attempt was to try to update it via the updateModel
of the MonacoEditorWrapper
but it raised an error so the editor was restarted again.
My code
const wrapper = editorRef.current?.getEditorWrapper();
wrapper?.updateModel({code: code});
The new error
No service init on restart
wrapper.ts:85 Starting monaco-editor (15)
editorAppClassic.ts:101 Init of MonacoConfig was completed.
editorAppBase.ts:109 Uncaught (in promise) Error: You cannot update the editor model, because the regular editor is not configured.
at EditorAppClassic.updateModel (editorAppBase.ts:109:35)
at MonacoEditorLanguageClientWrapper.updateModel (wrapper.ts:132:31)
at index.tsx:79:22
at commitHookEffectListMount (react-dom.development.js:23150:26)
at commitPassiveMountOnFiber (react-dom.development.js:24931:11)
at commitPassiveMountEffects_complete (react-dom.development.js:24891:9)
at commitPassiveMountEffects_begin (react-dom.development.js:24878:7)
at commitPassiveMountEffects (react-dom.development.js:24866:3)
at flushPassiveEffectsImpl (react-dom.development.js:27039:3)
at flushPassiveEffects (react-dom.development.js:26984:14)
When I looked at the editorAppBase.ts
Line 109 the exception is raised because the editor is null/undefined.
editorAppBase.ts
async updateModel(modelUpdate: ModelUpdate): Promise<void> {
if (!this.editor) {
return Promise.reject(new Error('You cannot update the editor model, because the regular editor is not configured.'));
}
this.updateAppConfig(modelUpdate);
await this.updateEditorModel();
}
I updated my code as follows, but although the error is gone, the editor still is restarted.
const wrapper = editorRef.current?.getEditorWrapper();
if (wrapper?.getEditor()) {
wrapper?.updateModel({code: code});
}
In the bellow gif you can see the flickering issue using my first approach. Due to the quality of the gif only on the four addition of the console.log
you can see the flickering of the strings.
Does anyone know the right way to update the code of the editor in a programatically/manual way?
Here is the code of my demo. It is basically a modification of the reactTs.ts
example available in monaco-components
repository
reactTs.ts
import React from 'react';
import ReactDOM from 'react-dom/client';
import EditorDemo from './EditorDemo.js';
const comp = <EditorDemo />
const rootElem = document.getElementById('root')!;
const root = ReactDOM.createRoot(rootElem);
root.render(comp);
EditorDemo.ts
import React, { useState } from 'react';
import { MonacoEditorReactComp } from '@typefox/monaco-editor-react';
import { UserConfig } from 'monaco-editor-wrapper';
import 'monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution.js';
import 'monaco-editor/esm/vs/language/typescript/monaco.contribution.js';
import { buildWorkerDefinition } from 'monaco-editor-workers';
buildWorkerDefinition('../../../../node_modules/monaco-editor-workers/dist/workers', import.meta.url, false);
const EditorDemo: React.FC = () => {
const logMessage = `console.log('hello')`
const [content, setContent] = useState(logMessage);
const rootElem = document.getElementById('root')!;
const userConfig: UserConfig = {
htmlElement: rootElem,
wrapperConfig: {
serviceConfig: {
enableKeybindingsService: true,
debugLogging: true
},
editorAppConfig: {
$type: 'classic',
languageId: 'typescript',
useDiffEditor: false,
theme: 'vs-dark',
code: content
}
}
};
const addConsoleMessage = () => {
setContent(`${content}\n${logMessage}`);
};
return (
<>
<button onClick={addConsoleMessage}>
Click me!
</button>
<MonacoEditorReactComp
userConfig={userConfig}
style={{
'paddingTop': '5px',
'height': '80vh'
}}
/>
</>
);
};
export default EditorDemo;
Im getting the following Error:
**
Unable to write file '\workspace\model63.PatCommands' (NoPermissions (FileSystemError): Not allowed)
FileOperationError@webpack://patc/./node_modules/monaco-editor/esm/vs/platform/files/common/files.js?:428:9
writeFile@webpack://patc/./node_modules/@codingame/monaco-vscode-files-service-override/vscode/src/vs/platform/files/common/fileService.js?:325:19
**
my package.json looks as follows:
{
"name": "patc",
"version": "0.1.0",
"private": true,
"dependencies": {
"@codingame/monaco-vscode-configuration-service-override": "~1.85.0",
"@codingame/monaco-vscode-editor-service-override": "~1.85.0",
"@codingame/monaco-vscode-keybindings-service-override": "~1.85.0",
"@typefox/monaco-editor-react": "^2.6.0",
"@types/react": "^18.2.22",
"@types/react-dom": "^18.2.7",
"blue-react": "^9.1.2",
"clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^12.0.2",
"html-loader": "^5.0.0",
"html-webpack-plugin": "^5.6.0",
"mini-css-extract-plugin": "^2.7.7",
"monaco-editor-workers": "^0.45.0",
"monaco-editor": "npm:@codingame/monaco-editor-treemended@>=1.85.0 <1.86.0",
"monaco-editor-wrapper": "~3.6.0",
"node-polyfill-webpack-plugin": "^3.0.0",
"npm-run-all": "^4.1.5",
"patorg-web-api-js": "^2.4.0",
"react": "^18.2.0",
"react-bootstrap-icons": "^1.10.3",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.0",
"react-scripts": "5.0.1",
"sass": "^1.68.0",
"sass-loader": "^14.0.0",
"vscode": "npm:@codingame/monaco-vscode-api@>=1.85.0 <1.86.0",
"vscode-languageclient": "^9.0.1",
"vscode-languageserver-protocol": "^3.17.5",
"webpack": "^5.90.0",
"webpack-cli": "^5.1.4",
"worker-loader": "^3.0.8"
},
"scripts": {
"start": "webpack serve --config webpack.config.js --mode development",
"backend-start": "node server.js",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"ts-loader": "^9.5.1"
},
"overrides": {
"monaco-editor": "$monaco-editor",
"vscode": "$vscode"
},
"resolutions": {
"monaco-editor": "npm:@codingame/monaco-editor-treemended@>=1.85.0 <1.86.0",
"vscode": "npm:@codingame/monaco-vscode-api@>=1.85.0 <1.86.0"
}
}
i have no webpack-resolutions in place. can anyone tell me how i stop editor from trying to write to my filesystem?
When the component mounts and the language server is not available, an error get thrown but not caught, which then also seems to cause the onLoad
not to fire. It would be nice if the error simply got caught and logged by the component.
The error thrown:
'''
{
"message": "languageClientWrapper (Python Language Server Example): Websocket connection failed.",
"error": "No error was provided."
}
'''
Style instructions for DiffEditor seem to be missing.
Automatic reconnection of WebSocket is currently not working. ReconnectingWebSocket
was not used here and reconnection capability and configuration should be realized differently. Is it still needed at all. Asses status.
using the react component in vscode mode i am getting this
(on 2nd mount of component)
any idea what could cause this?
is there some destroy/unregister missing?
When bundling the wrapper in a non-esm project, the following lines throw an error:
monaco-components/packages/monaco-editor-wrapper/src/index.ts
Lines 14 to 21 in 9057685
Since these workers aren't necessarily a feature of the wrapper, would it make sense to move them to a separate export that can be imported if a downstream user wants to do that? For most users, importing these workers by default does not pose any advantage.
Vite 2.8 changed the worker loading syntax removing the new for special import syntax.
All working handling code needs to be adapted to this.
Add the capability to add inline JS configurations to the web components before first npm release.
We have a case where we use multiple grammars in a language project. We have two.langium
grammar files and use imports to link them together and reference rules. In the wrapperConfig.editorAppConfig
section of UserConfig
, there is only support for a single language:
editorAppConfig: {
$type: 'classic',
languageId: 'helloworld',
theme: 'langium-theme',
code: code,
useDiffEditor: false,
editorOptions: {
'semanticHighlighting.enabled': true
},
languageExtensionConfig: { id: 'langium' },
languageDef: HelloWorldMonarchContent,
themeData: LangiumTheme,
}
In order to support my case, where we generate multiple monarch definition files, my assumption is that I would need to manually merge the two languages back together into a single monarch definitions file in order to use them as intended in the wrapper. Or is there another way to do this where I can specify multiple monarch definition files?
When constructing a URI, the text after the first //
determines the URI authority
property. In order to set the path
property another, third /
is required here:
This leads to issues when the language server that is connected to this editor tries to perform computations based on the name of the file, as its path is an empty string.
I used npm create @vite:latest
to scaffold a vanilla TS project. After adding a dependency to monaco-editor-wrapper
to my package.json
file, the monaco-treemending
script never shows up in the node_modules/.bin
folder, and the monaco-treemending
postinstall script fails. Here is my package.json
:
{
"name": "vite-project",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"postinstall": "monaco-treemending"
},
"dependencies": {
"monaco-editor-workers": "^0.43.0",
"monaco-editor-wrapper": "^3.0.1",
"monaco-languageclient": "^6.4.6",
"vscode-languageclient": "^8.1.0"
},
"devDependencies": {
"typescript": "^5.0.2",
"vite": "^4.4.5"
}
}
My assumption here is that I'll need to add the @codingame/monaco-vscode-api
in order to fix this.
Shouldn't this script come along with the monaco-editor-wrapper
node module?
For the latest version of monaco-editor-wrapper, and previous versions, passing an invalid LS url causes the application to become unresponsive. This can happen when the languageClientConfig.workerConfigOptions
of the UserConfig contains either:
new Worker('oops.js')
){
url: new URL('oops.js', window.location.href),
type: 'module',
name: 'some-name',
}
In either case, if the resulting UserConfig
that contains this unreachable url is passed into the start method of a wrapper, the application will hang indefinitely.
const wrapper = new MonacoEditorLanguageClientWrapper();
await wrapper.start(userConfig);
// no rejection or resolution happens, effectively frozen
This issue is particularly hard to debug as a result, and once found it's often unclear why the start
method isn't returning.
As a possible solution, we should make a 'best attempt' to determine that a given url (or pre-configured Worker) is valid. If not we should reject, allowing the resulting promise to finish up, and report the relevant error back to the user. The question remains at what stage within the wrapper to perform this sanity check, but if we can detect this case that would help others to resolve this issue quickly.
#7 introduced a dispose
method and this triggered the question if all resources are properly disposed and re-init when swapEditors
is called.
Hi, how to bundle monaco-editor-workers with vite? is there any example that works with import meta url?
Hello, trying out Langium and stumbled on the following problem:
While trying to use monaco-editor-wrapper
by directly importing in a TS frontend project using this command:
import { monaco, MonacoEditorLanguageClientWrapper, vscode } from "monaco-editor-wrapper/bundle";
instead of the tutorial recommended way of copying the dist files, I saw that the types referenced were missing and so I looked it up and it looks like the package is importing monaco-editor
here:
but because it's missing from the "dependencies"
in package.json
, the files point to nowhere, so all the types end up as any
. Adding the dependency and installing it manually inside the node_modules/monaco-editor-wrapper
dir, works just fine, the issue is that doesn't survive a clean npm install
.
Regardless, thank you for making Langium, it's such a nice project!
Hi there! I have a question about rendering editor parts (e.g. editor group view and side bar) other than the single tab.
I have a working React component set-up similar to monaco-vscode-api
's demo where I attach the default VSCode UI parts one by one like so:
// initiaze our vscode ui by assigning the refs to the corresponding DOM elements
// and handle their visibility.
for (const {part, element} of [
{part: Parts.TITLEBAR_PART, element: titleBarRef.current},
{part: Parts.BANNER_PART, element: bannerRef.current},
{part: Parts.SIDEBAR_PART, element: sideBarRef.current},
{
part: Parts.ACTIVITYBAR_PART,
element: activityBarRef.current
},
{
part: Parts.EDITOR_PART,
element: editorPartRef.current
}, {part: Parts.STATUSBAR_PART, element: statusBarRef.current}, {
part: Parts.AUXILIARYBAR_PART,
element: auxiliaryBarRef.current
}
]) {
attachPart(part, element!)
if (!isPartVisibile(part)) {
element!.style.display = 'none'
}
onPartVisibilityChange(part, visible => {
element!.style.display = visible ? 'block' : 'none'
})
}
I need the editors view of EditorPart which allows multiple tabs and split views and the file system sidebar to view mounted files.
I wonder if it's possible with monaco-editor-react.
I'd really like to use monaco-editor-react
UserConfig API etc but I also need the views. Please kindly advise. Thanks!
Hi, is there a way to enable semantic highlighting in 2.x
(I am using the classic variant)
Somehow i don’t find a way to properly pass
“semanticHighlighting.enabled”: true
Down to Monaco anymore
(Was working before in 1.6 cdietrich/langium-inject-files-webworker@138d71e)
Hi, do you have a hint how to have the component twice on a page.
am currently getting
Uncaught (in promise) Error: Services are already initialized
at checkServicesNotInitialized (lifecycle.js:68:15)
at initialize2 (services.js:84:5)
at importAllServices (monaco-vscode-api-services.ts:101:11)
at initServices (monaco-vscode-api-services.ts:29:15)
at LanguageClientWrapper.init (languageClientWrapper.ts:93:15)
at MonacoEditorLanguageClientWrapper.init (wrapper.ts:62:42)
Hi, where has monaco-editor-workers
been moved to?
There seems not to export an interface to modify the initialize request's capabilities params?
I want to disable workspace.didChangeWatchedFiles capability, because there are no corresponding files to watch.
Hi, has someone experimented bundling (am using create-react-app) without vscode to reduce bundle size?
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.
My questions are:
Thanks
DiffEditor should be available before first npm release.
Hi once again:) Huge sorry for tickets spamming, I'm just curious, do you have any plans for monaco-editor-react 2.0.0 release? I'm playing around language server support for JVM languages (kotlin example), and just discovered that the latest version of your libs in NPM is 1.1.1 (according to this page: https://www.npmjs.com/package/@typefox/monaco-editor-react), but examples in this repository are already using 2.0.0, so it's a bit complex to follow
Considerations on having more that one document in workspace in react/wrapper usecase
We have the following usecase:
Right now we do the following
This works fine until we want to exchange the to be edited file along with its other files in react.
If the component is not remounted, then the componentDidUpdate call wont reinit monaco as before and after we just have a worker
thus we cannot plugin a new worker
we currently circumvent this problem by passing a key to the component to force remount
i am thinking about what could be done to make this nicer or more generic
instead of using workspaceMgr and builtin files we could use lsp didOpen calls to open multiple files. if the protocol works fine they all should end up in the same ws and visibile to each other (did not test that yet), but this also would require a hook in the component or a prop to pass multiple resources
we at least could make the current approach more robust by adding a prop to force remount on componentDidUpdate
do you have more ideas or hints? Thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.