
Security News
The Changelog Podcast: Practical Steps to Stay Safe on npm
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.
@codingame/monaco-vscode-api
Advanced tools
This NPM module allows to integrate full VSCode functionality into your monaco-editor.
For more information, please checkout the project's wiki.
npm install @codingame/monaco-vscode-api
# Optionally install the extension api and the editor api
npm install vscode@npm:@codingame/monaco-vscode-extension-api
npm install monaco-editor@npm:@codingame/monaco-vscode-editor-api
@codingame/monaco-vscode-extension-api is installed as an alias to vscode to be able to run import * as vscode from 'vscode', similar to what is done inside a VSCode extension
@codingame/monaco-vscode-editor-api is installed as an alias to monaco-editor because it provides the same api as the official monaco-editor
If you are just starting with monaco-editor and monaco-vscode-api you may find helpful the Getting Started Guide in the wiki.
Most of VSCode functionality implemented as "services", e.g.
By default, Monaco uses a simplified versions of the VSCode services, called standalone services.
This package allows to
Here is an example usage that overrides Monaco default configuration with VSCode json-based settings:
// default monaco-editor imports
import * as monaco from 'monaco-editor'
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
// utilities to override Monaco services
import { initialize } from '@codingame/monaco-vscode-api'
import getConfigurationServiceOverride, {
  updateUserConfiguration
} from '@codingame/monaco-vscode-configuration-service-override'
window.MonacoEnvironment = {
  getWorker: (_moduleId, _label) => new editorWorker()
}
// overriding Monaco service with VSCode
await initialize({
  ...getConfigurationServiceOverride()
})
// json config like in vscode settings.json
updateUserConfiguration(`{
    "editor.fontSize": 30,
    "editor.lineHeight": 30,
    "editor.fontFamily": "monospace",
    "editor.fontWeight": "bold",
    "editor.letterSpacing": 0,
}`)
// creating an editor with VSCode configuration
monaco.editor.create(document.getElementById('editor')!, {
  value: 'Editor with VSCode config and large bold fonts'
})
[!NOTE]
initializecan only be called once (and it should be called BEFORE creating your first editor).
Each get<service-name>ServiceOverride contains the service and some glue to make VSCode service work with Monaco.
Some basic service overrides are coming with this package as dependencies:
@codingame/monaco-vscode-base-service-override
@codingame/monaco-vscode-host-service-override
@codingame/monaco-vscode-extensions-service-override
@codingame/monaco-vscode-files-service-override
file:// files, but also adds the support for lazy loaded extension files. It adds separate memory user files (e.g. config, keybindings), cache files and log filesfile:// files@codingame/monaco-vscode-quickaccess-service-override
@codingame/monaco-vscode-search-service-override
However, most of the services are separated into different modules, so they can be imported as required. You can find a full list of services in the corresponding wiki page.
VSCode uses a bunch of default extensions. Most of them are used to load the default languages and grammars (see https://github.com/microsoft/vscode/tree/main/extensions).
This library bundles and publishes them as separate packages, which allows to use the ones you want. To use an extension, just install the corresponding package and import it in the beginning of the file:
import '@codingame/monaco-vscode-javascript-default-extension'
import '@codingame/monaco-vscode-json-default-extension'
...
Here is an example of usage of default VSCode theme extension with theme service override:
// importing default VSCode theme extension
import '@codingame/monaco-vscode-theme-defaults-default-extension'
// default monaco-editor imports
import * as monaco from 'monaco-editor'
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
// utilities to override Monaco services
import { initialize } from '@codingame/monaco-vscode-api'
import getThemeServiceOverride from '@codingame/monaco-vscode-theme-service-override'
window.MonacoEnvironment = {
  getWorker: function (_moduleId, _label) {
    return new editorWorker()
  }
}
// overriding Monaco service with VSCode
await initialize({
  ...getThemeServiceOverride()
})
// creating an editor with VSCode theme
monaco.editor.create(document.getElementById('editor')!, {
  value: 'Editor with VSCode Theme Support'
})
See the full list of ported default extensions
VSCode extensions are bundled as vsix files. This library publishes a rollup plugin (vite-compatible) that allows to load a vsix file.
import vsixPlugin from '@codingame/monaco-vscode-rollup-vsix-plugin'
...
plugins: [
  ...,
  vsixPlugin()
]
import './extension.vsix'
This library also offers the possibility to localize vscode and the extensions in the supported languages. To do so, import one of the following packages before anything else:
@codingame/monaco-vscode-language-pack-cs@codingame/monaco-vscode-language-pack-de@codingame/monaco-vscode-language-pack-es@codingame/monaco-vscode-language-pack-fr@codingame/monaco-vscode-language-pack-it@codingame/monaco-vscode-language-pack-ja@codingame/monaco-vscode-language-pack-ko@codingame/monaco-vscode-language-pack-pl@codingame/monaco-vscode-language-pack-pt-br@codingame/monaco-vscode-language-pack-qps-ploc@codingame/monaco-vscode-language-pack-ru@codingame/monaco-vscode-language-pack-tr@codingame/monaco-vscode-language-pack-zh-hans@codingame/monaco-vscode-language-pack-zh-hant⚠️ The language pack should be imported and loaded BEFORE anything else from this library is loaded. Otherwise, some translations would be missing and an error would be displayed in the console. ⚠️
The official monaco-editor package provides a function to create models: monaco.editor.createModel.
This method creates a standalone model that cannot be found or used by any VSCode services.
The recommended way is to used the createModelReference method instead (added on top of the official monaco-editor api) which returns instead a reference to a model.
It has some pros:
To work, it needs the file to exist on the virtual filesystem. It can be achieved either by:
registerFileSystemOverlay from the files service override, which can be cleaned when not needed anymore (recommended)createModelReference function, which writes the file content to the virtual filesystem before creating the modelbefore:
import * as monaco from 'monaco-editor'
const model = monaco.editor.createModel(...)
const editor = monaco.editor.create({ model, ... })
...
model.dispose()
editor.dispose()
after:
import * as monaco from 'monaco-editor'
import { RegisteredFileSystemProvider, RegisteredMemoryFile, registerFileSystemOverlay } from '@codingame/monaco-vscode-files-service-override'
const fileUri = monaco.Uri.file(<file uri>);
const fileSystemProvider = new RegisteredFileSystemProvider(false)
fileSystemProvider.registerFile(new RegisteredMemoryFile(fileUri, <file content>))
const overlayDisposable = registerFileSystemOverlay(1, fileSystemProvider)
const modelRef = await monaco.editor.createModelReference(fileUri)
const editor = monaco.editor.create({ model: modelRef.object.textEditorModel })
...
await modelRef.object.save()
...
modelRef.dispose()
editor.dispose()
overlayDisposable.dispose()
createModelReference return a reference to a model. The value is fetched from the memory filesystem.
The reference can then be disposed, the model will only be disposed if there is no remaining references.
To be able to use the VSCode api directly from your code, you need to import vscode/localExtensionHost and wait for the services to be initialized.
You will then be able to import it as if you were in a VSCode extension:
import * as vscode from 'vscode'
import 'vscode/localExtensionHost'
const range = new vscode.Range(...)
vscode.languages.registerCompletionItemProvider(...)
You can also register a new extension from its manifest:
import { registerExtension, initialize, ExtensionHostKind } from '@codingame/monaco-vscode-api/extensions'
await initialize()
const { registerFileUrl, getApi } = registerExtension({
  name: 'my-extension',
  publisher: 'someone',
  version: '1.0.0',
  engines: {
      vscode: '*'
  },
  contributes: {
  }
}, ExtensionHostKind.LocalProcess)
registerFileUrl('/file-extension-path.json', new URL('./file-real-path.json', import.meta.url).toString())
const vscode = await getApi()
vscode.languages.registerCompletionItemProvider(...)
Try it out on https://monaco-vscode-api.netlify.app/
There is a demo that showcases the service-override features. It includes:
From CLI run:
# build monaco-vscode-api (the demo use it as a local dependency)
npm ci
npm run build
# start demo
cd demo
npm ci
npm start
# OR: for vite debug output
npm run start:debug
For the debug feature, also run:
npm run start:debugServer
⚠️ Building monaco-vscode-api is only supported on Linux or Mac. It you use Windows, have a look at WSL ⚠️
See the VSCode Server wiki page.
The library supports shadow-dom.
⚠️ VSCode itself doesn't support shadow dom, and there are multiple parts that needed to be patched in order for it to work.
There are multiple benefits of using it:
If the provided container element is a child of a shadow dom element, the styles will be injected in both the main page and the shadow root. That's it.
In order to be able to load the static css files in the shadow dom as well. Your bundler configuration needs to be adapted so that importing css files doesn't load their content in the page head, but instead just returns the file content as default (either as a string or a CSSStyleSheet). It can be achieved with most bundlers with some configurations.
Note that the bundler should still resolve referenced assets in the css files, so you can't just use the raw loader, or the assets/source webpack module type.
Add this rule in your configuration:
{
  test: /node_modules\/(@codingame\/monaco-vscode|vscode|monaco-editor).*\.css$/,
  use: [
    {
      loader: 'css-loader',
      options: {
        esModule: false,
        exportType: 'css-style-sheet', // or 'string', both are working
        url: true,
        import: true
      }
    }
  ]
}
You should also make sure that no other loader is interfering with it, by either use a oneOf or exclusing those files in the other css loaders.
Add this plugin in your configuration:
{
  name: 'load-vscode-css-as-string',
  enforce: 'pre',
  async resolveId(source, importer, options) {
    const resolved = (await this.resolve(source, importer, options))!
    if (
      resolved.id.match(
        /node_modules\/(@codingame\/monaco-vscode|vscode|monaco-editor).*\.css$/
      )
    ) {
      return {
        ...resolved,
        id: resolved.id + '?inline'
      }
    }
    return undefined
  }
}
One issue with VSCode is it's only designed to be initialized once. So the initialization options (workbench options, remote server authority...) can't be updated/reloaded. Also it's not possible to "unload" the services.
To still be able to do it, a possibility is to run all VSCode code inside an iframe instead of in the main page. But then VSCode will render in the iframe only and won't be well integrated in the page.
To better integrate it, it's also possible to run the code in the iframe, but make the code interact with the main page dom.
This library supports that mode. To enable that, you should
window.vscodeWindow to the parent window, also initialize the service with a container mounted in that windowTo "unload" the workbench, you should:
document.querySelectorAll('[data-vscode]').forEach((el) => el.remove())⚠️ window.vscodeWindow should be set BEFORE any VSCode code is loaded
Note: it can be used in combination with shadow dom
It's demonstrated in the demo, by adding ?sandbox query parameter to the demo url
If something doesn't work, make sure to check out the Troubleshooting wiki page.
This project was mainly created to make the implementation of monaco-languageclient more robust and maintainable.
monaco-languageclient uses vscode-languageclient which was built to run inside a VSCode extension. VSCode extensions communicate with the editor via an API they can import into their code.
The VSCode api exports:
The first implementations of monaco-languageclient were using a fake VSCode api implementation. The vscode-languageclient was hacked so the VSCode<->protocol object converters were mainly bypassed, so the fake VSCode api was receiving Language Server Protocol objects. Then the objects were transformed using custom transformers into Monaco objects to communicate with the monaco api.
This approach has some disadvantages:
With this library, it would be possible to plug vscode-languageclient directly on top of monaco, monaco-languageclient still helps to do so by:
FAQs
VSCode public API plugged on the monaco editor
The npm package @codingame/monaco-vscode-api receives a total of 74,054 weekly downloads. As such, @codingame/monaco-vscode-api popularity was classified as popular.
We found that @codingame/monaco-vscode-api demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.

Security News
Experts push back on new claims about AI-driven ransomware, warning that hype and sponsored research are distorting how the threat is understood.

Security News
Ruby's creator Matz assumes control of RubyGems and Bundler repositories while former maintainers agree to step back and transfer all rights to end the dispute.