Git Product home page Git Product logo

monaco-loader's Introduction

@monaco-editor/loader ยท monthly downloads gitHub license npm version PRs welcome

The utility to easy setup monaco-editor into your browser

Synopsis

Configure and download monaco sources via its loader script, without needing to use webpack's (or any other module bundler's) configuration files

Motivation

It's been a while we are working with monaco editor. It's a great library and provides a powerful editor out of the box. Anyway, there were couple of problems related to the setup process. The main problem is the need to do some additional webpack configuration; that's not bad, but some quite useful tools, like CRA, aren't happy with that fact. The library @monaco-editor/react was being created to solve that problem - monaco editor wrapper for easy/one-line integration with React applications without needing to use webpack's (or any other module bundler's) configuration files. In that library, there was a utility that cares about the initialization process of monaco and overcomes the additional use of webpack configuration. That utility grows over time and now it's a separate library. Now, you can easily setup monaco into your browser, create your own editors, wrappers for React/Vue/Angular of whatever you want.

How it works

Monaco editor provides a script called loader, which itself provides tooling to download monaco sources. The library, under the hood, handles the configuration and loading part and gives us an easy-to-use API to interact with it

Documentation

Contents

Installation

npm install @monaco-editor/loader

or

yarn add @monaco-editor/loader

NOTE: For TypeScript type definitions, this package uses the monaco-editor package as a peer dependency. So, if you need types and don't already have the monaco-editor package installed, you will need to do so.

Introduction

The library exports types and the utility called loader, the last one has two methods

Usage

import loader from '@monaco-editor/loader';

loader.init().then(monaco => {
  monaco.editor.create(/* editor container, e.g. document.body */, {
    value: '// some comment',
    language: 'javascript',
  });
});

codesandbox

.config

By using the .config method we can configure the monaco loader. By default all sources come from CDN, you can change that behavior and load them from wherever you want

import loader from '@monaco-editor/loader';

// you can change the source of the monaco files
loader.config({ paths: { vs: '...' } });

// you can configure the locales
loader.config({ 'vs/nls': { availableLanguages: { '*': 'de' } } });

// or
loader.config({
  paths: {
    vs: '...',
  },
  'vs/nls' : {
    availableLanguages: {
      '*': 'de',
    },
  },
});

loader.init().then(monaco => { /* ... */ });

codesandbox

Configure the loader to load the monaco as an npm package

import loader from '@monaco-editor/loader';
import * as monaco from 'monaco-editor';

loader.config({ monaco });

loader.init().then(monacoInstance => { /* ... */ });

codesandbox

.init

The .init method handles the initialization process. It returns the monaco instance, wrapped with cancelable promise

import loader from '@monaco-editor/loader';

loader.init().then(monaco => {
  console.log('Here is the monaco instance', monaco);
});

codesandbox

import loader from '@monaco-editor/loader';

const cancelable = loader.init();

cancelable.then(monaco => {
  console.log('You will not see it, as it is canceled');
});

cancelable.cancel();

codesandbox

Notes

For electron users

In general it works fine with electron, but there are several cases that developers usually face to and sometimes it can be confusing. Here they are:

  1. Download process fails or if you use @monaco-editor/react You see loading screen stuck Usually, it's because your environment doesn't allow you to load external sources. By default, it loads monaco sources from CDN. You can see the default configuration. But sure you can change that behavior; the library is fully configurable. Read about it here. So, if you want to download it from your local files, you can do it like this:
import loader from '@monaco-editor/loader';

loader.config({ paths: { vs: '../path-to-monaco' } });

or, if you want to use it as an npm package, you can do it like this:

import loader from '@monaco-editor/loader';
import * as monaco from 'monaco-editor';

loader.config({ monaco });

loader.init().then(monacoInstance => { /* ... */ });
  1. Based on your electron environment it can be required to have an absolute URL The utility function taken from here can help you to achieve that. Let's imagine you have monaco-editor package installed and you want to load monaco from the node_modules rather than from CDN: in that case, you can write something like this:
function ensureFirstBackSlash(str) {
    return str.length > 0 && str.charAt(0) !== '/'
        ? '/' + str
        : str;
}

function uriFromPath(_path) {
    const pathName = path.resolve(_path).replace(/\\/g, '/');
    return encodeURI('file://' + ensureFirstBackSlash(pathName));
}

loader.config({
  paths: {
    vs: uriFromPath(
      path.join(__dirname, '../node_modules/monaco-editor/min/vs')
    )
  }
});

or, just use it as an npm package.

There were several issues about this topic that can be helpful too - 1 2 3 4

And if you use electron with monaco and have faced an issue different than the above-discribed ones, please let us know to make this section more helpful.

For Next.js users

The part of the source that should be pre-parsed is optimized for server-side rendering, so, in usual cases, it will work fine, but if you want to have access, for example, to monacoInstance you should be aware that it wants to access the document object, and it requires browser environment. Basically you just need to avoid running that part out of browser environment, there are several ways to do that. One of them is described here.

And if you use monaco with Next.js and have faced an issue different than the above-described one, please let us know to make this section more helpful.

License

MIT

monaco-loader's People

Contributors

andarist avatar celian-garcia avatar jgoux avatar martonlanga avatar rw-access avatar suren-atoyan avatar syumai avatar voidranjer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

monaco-loader's Issues

[Requirement] Expectation to add an asynchronous method getMonaco to improve initial screen loading efficiency.

Background

The usage of the monaco-editor package in the project is relatively low, but its package files are quite large, affecting the efficiency of the initial screen loading.
If using the minified version of the monaco-editor, it will cause the window to mount the define method, impacting the loading of other UMD files in the project.

Approach

It is expected to add a getMonaco method in @monaco-editor/loader to asynchronously obtain monaco.

Code

 // ไฝฟ็”จloader
loader.config({
  getMonaco: () => import/* webpackChunkName: 'monaco-editor' */('monaco-editor'),
});
// ่ทฏๅพ„ src/loader/index.js

/**
 * handles the initialization of the monaco-editor
 * @return {Promise} - returns an instance of monaco (with a cancelable promise)
 */
function init() {
  const state = getState(({ monaco, isInitialized, resolve, getMonaco }) => ({ monaco, isInitialized, resolve, getMonaco }));

    if (!state.isInitialized) {
      setState({ isInitialized: true });

      if (state.monaco) {
        state.resolve(state.monaco);
        return makeCancelable(wrapperPromise);
      }
      // add getMonaco code
      if (typeof state.getMonaco === 'function') {
        const monaco = state.getMonaco().then(monaco => { 
          state.resolve(monaco);
          return monaco;
        })
        return makeCancelable(monaco);
      }

      if (window.monaco && window.monaco.editor) {
        storeMonacoInstance(window.monaco);
        state.resolve(window.monaco);
        return makeCancelable(wrapperPromise);
      }

      compose(
        injectScripts,
        getMonacoLoaderScript,
      )(configureLoader);
    }

    return makeCancelable(wrapperPromise);
}

Monaco editor not working in Egypt Region [CDN issue]

I have built a web application using the Monaco Editor. One of my clients from the Egypt region encountered an issue when trying to use the Monaco Editor Playground in my application. After debugging, I discovered the root cause of the issue. The problem is that the Monaco Editor relies on the jsdelivr CDN provider to retrieve necessary resources. However, my client is currently unable to access it.

Can you suggest a solution or an alternative approach to tackle this problem?

Instead of fetching the resources from the CDN, we can consider loading them from the "node_modules" directory after installing the Monaco Editor package.

API Failed Information:

Request: https://cdn.jsdelivr.net/npm/[email protected]/min/vs/loader.js
Response: Failed to load response data. No data found for the resource with the given identifier

Revert icon not work in some cases on monaco-diff-editor using 0.36.1 cdn version

Change to .30 not published on npm

Looks like the change to update .28 => .30 hasn't been published in npm yet:

This is what's building pulled in by the loader using the latest @monaco/react
$ grep "@0.28.1" **/*.js

static/chunks/pages/[user]/v/[notebook].js:eval("__webpack_require__.r(__webpack_exports__);\nvar config = {\n  paths: {\n    vs: 'https://cdn.jsdelivr.net/npm/[email protected]/min/vs'\n  }\n};\n\n/* harmony default export */ 

Current version.

    "@monaco-editor/loader": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.2.0.tgz",
      "integrity": "sha512-cJVCG/T/KxXgzYnjKqyAgsKDbH9mGLjcXxN6AmwumBwa2rVFkwvGcUj1RJtD0ko4XqLqJxwqsN/Z/KURB5f1OQ==",
      "requires": {
        "state-local": "^1.0.6"
      }
    }
    

Why isInitialized is added back in 1.3.1

Hi,
Wanted to understand the meaning of isInitialized flag in loader/index.js. As per my understanding you wanted it to not to initialized monaco again if already it was initialized.
But I guess that was get handled perfectly with check if(monaco) itself.
The reason why I am saying this. I have a use case if some how monaco-editor js didn't get loaded by this loader (could be any reason eg: js not present there) then I am calling loader.init() method again.
But because of isInitialized flag's value is already true. It never goes to load monaco-edtior js again. Which is a bug here.
After upgrading to 1.3.0 it was working perfectly fine. But this flag added back in 1.3.1.

If loader.init() failes then isInitialized should be marked as false.

loader.config will make browser tab CRASH

image
Hi, I use loader to choose a monaco editor version like below, but it will lead to browser tab crash.

this is operation procedure:
bug

when editor appear (component did mount) and switch to another inner tab, it will crash....
image

but if I don't use load config, It will not happen.

Unrecognised require call

While using in my Ember application it seems that the loader in monaco-editor overrides the require function and I get the "Unrecognised require call" error after any module uses the require function

How to keep multiple different monaco-editor instance in one project?

Our project depends on another dependency which uses an old version monaco, but our project uses a newer one.
Both our project and the dependency use monaco-loader to load monaco.
But I don't know why once we import the dependency, the monaco-loader loads the older one instead the newer one.
So, is there any method to make the monaco instance only takes effect in the specific area or namespace?

Document origins for loaded resources for Content Security Policies

This package works great, but I needed to add a CSP to my webpage that runs the editor, and in the CSP I need to list the resources the editor loads as exceptions to the CSP. My CSP contains some additional exceptions, but I think these are the ones needed for the editor to be able to load its resources:

// Start by forbidding most stuff by default...

default-src 'none';
form-action 'none';
connect-src 'none';

// ...
// And then allow the following resources to be loaded by the editor (you probably need to allow your own JS and CSS code here too):

img-src data:;
script-src https://cdn.jsdelivr.net blob:;
style-src-elem https://cdn.jsdelivr.net;
font-src https://cdn.jsdelivr.net;

I don't know if I've managed to allow all resources the editor will ever attempt to load. For one, data: for img-src I noticed was needed first when the editor tried to load it, which was when I triggered the autocomplete box to open, so there might be more that needs to be allowed I haven't discovered yet. Anyway, would be nice to have this documented somewhere.

(it's also the first time I'm using a CSP, so there might be a better way of achieving the same result)

loader.config({monaco}) still stuck on 'loading...'

Describe the bug
Following the instructions on the README for loading monaco-editor as an npm module (not using CDN) in Vite, it does not work. https://github.com/suren-atoyan/monaco-react#use-monaco-editor-as-an-npm-package

It used to work! I am not sure when this stopped working - sometime in the last few weeks. I was using 4.4.1 locally before, and had recently updated to React 18. I created a fresh sandbox repro.

To Reproduce

  1. Run the example: https://stackblitz.com/edit/vitejs-vite-tf4tif?file=src/App.tsx
  2. Observe that the editor never gets past loading
  3. If you comment out line 36 (loader.config({monaco})) it works fine

Expected behavior
It should load and show "HELLO" in the monaco editor

Screenshots
Broken:
image

Comment out 9-40 (loader code) works fine:
image

Update monaco peer dependency

I tried running npm install and got the following error message. It's probably because I'm using the new npm v7.

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! Found: [email protected]
npm ERR! node_modules/monaco-editor
npm ERR!   monaco-editor@"^0.22.3" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer monaco-editor@"^0.21.2" from @monaco-editor/[email protected]
npm ERR! node_modules/@monaco-editor/loader
npm ERR!   @monaco-editor/loader@"^1.0.0" from the root project

Content-security-policy refuse to load cdn files.

Hey, i have came across this bug when developing a chrome extension (mV3). I have a devtools page in which i wanted to use monaco - i have tried many configuartions without any success - i believe it is because of how the loader script is added to the body (appending)

Refused to load the script 'https://cdn.jsdelivr.net/npm/[email protected]/min/vs/asdasdasd/loader.js' because it violates the following Content Security Policy directive: "script-src 'self' 'wasm-unsafe-eval' 'inline-speculation-rules' http://localhost:* http://127.0.0.1:*". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

function injectScripts(script) {

Not really sure if that is the case or not (chrome runtimes are weird).
Keep it up!

Matyas

Add support for loading TypeScript Sandbox/additional scripts

The TypeScript Sandbox is based on Monaco and is loaded very similarly, but with some extra scripts:

require.config({
  paths: {
    vs: 'https://typescript.azureedge.net/cdn/4.0.5/monaco/min/vs',
    // vs: 'https://unpkg.com/@typescript-deploys/[email protected]/min/vs',
    sandbox: 'https://www.typescriptlang.org/js/sandbox',
  },
  // This is something you need for monaco to work
  ignoreDuplicateModules: ['vs/editor/editor.main'],
})

// Grab a copy of monaco, TypeScript and the sandbox
require(['vs/editor/editor.main', 'vs/language/typescript/tsWorker', 'sandbox/index'], (
  main,
  _tsWorker,
  sandboxFactory
) => {

If this library could add support for loading additional scripts and getting a handle on the result, that would be super useful.

I don't think I'll be able to do it right away (so please feel free to beat me!) but I may be able to take a look at this at some point if you'd be open to a PR.

getModelMarkers() or onDidChangeMarkers() are not exist

I am trying to get makers to have some aside validation but somehow it does not exist on the editor object.
However, it exists in the editor API, any solution or explanation would be useful
Using @monaco-editor/loader v 1.4.0

Thanks

Couldn't find preset "@babel/preset-env"

When I add "@monaco-editor/loader": "1.2.0" to my package.json and try to run the application (via grunt auto-build), I receive the following error:
Error: Couldn't find preset "@babel/preset-env" relative to directory "<project>/node_modules/@monaco-editor/loader" while parsing file: <project>/node_modules/@monaco-editor/loader/lib/cjs/index.js

I have "babel-preset-env": "^1.6.1" in my dependencies. Any idea what I am missing?

Monaco Instance Undefined When Trying to Change Options

I am using monaco-editor in my Vue web application. The editor loads and runs completely fine. However, I need to change the autocomplete sources for the editor. When doing so, the following code throws :

Uncaught (in promise) TypeError: Cannot read property 'setCompilerOptions' of undefined

And the editors fails to load.

Am I misusing the monaco instance?

import loader from '@monaco-editor/loader';

export default {
  mounted() {
    const wrapper = document.getElementById("editor")
    loader.init().then(monaco => {

      monaco.languages.typescriptDefaults.setCompilerOptions(
          {
            noLib: true,
            allowNonTsExtensions: true,
            target: monaco.languages.typescript.ScriptTarget.ES2015
          }
      );

      monaco.editor.create(wrapper, {
        value: 'const name = "Peter"',
        language: 'typescript',
      });
    });
  },
}

The editor works fine with the following code:

import loader from '@monaco-editor/loader';

export default {
  mounted() {
    const wrapper = document.getElementById("editor")
    loader.init().then(monaco => {
      monaco.editor.create(wrapper, {
        value: 'const name = "Peter"',
        language: 'typescript',
      });
    });
  },
}

Initializing monaco as an npm package with Next.js

Describe the bug

I'd like to initialize monaco from an npm package so I can write unit tests. Seems like this is a common problem since monaco is by default initialized remotely.

Unfortunately, it seems that inside a Next.js app I'm either implementing this incorrectly or it doesn't work:

import Editor from '@monaco-editor/react';

import loader from '@monaco-editor/loader';
import { useEffect } from 'react';
import * as monaco from 'monaco-editor';

loader.config({ monaco })

const Code = () => {
  
  useEffect(() => {
    loader.init().then((monaco) => {
      console.log("Here is the monaco instance", monaco);
    });
  })

  return (
    <Editor
      height="90vh"
      defaultLanguage="javascript"
      defaultValue="// let's write some broken code ๐Ÿ˜ˆ"
    />
  )
};

export default Code;

I'm also importing this component with SSR turned off:

const Code = dynamic(() => import('../components/Code'), {
  ssr: false,
})

To Reproduce

Run this example: https://stackblitz.com/edit/nextjs-xye7xg?file=components/Code.tsx

Will see an console error :

error - ./node_modules/monaco-editor/esm/vs/base/browser/ui/actionbar/actionbar.css
Global CSS cannot be imported from within node_modules.

Expected behavior

  1. Should be able to load monaco from node_modules within a Next.js app
  2. When loading from npm packages, should be able to run the following test: https://stackblitz.com/edit/nextjs-xye7xg?file=components/Code.test.tsx

addEventListener is not a function - when running from Vite (built)

Uncaught TypeError: el.addEventListener is not a function
at addEventListener (index.js:4469:6)
at platform.ts:162:11
at platform.ts:184:46
at s._invokeFactory (loader.js:1189:41)
at s.complete (loader.js:1199:36)
at s._onModuleComplete (loader.js:1825:20)
at s._resolve (loader.js:1785:22)
at s.defineModule (loader.js:1428:18)
at g (loader.js:1875:27)
at numbers.ts:26:1

Points to this:
function addEventListener(el, event, handler, options) {
el.addEventListener(event, handler, options);
}

unable to import loader after upgrading to 1.2.0

Getting following compiler error

error TS9006: Declaration emit for this file requires using private name 'CancelablePromise' from module '"node_modules/@monaco-editor/loader/lib/types"'. An explicit type annotation may unblock declaration emit.

when importing as:

import loader from "@monaco-editor/loader";

using following configs

  "devDependencies": {
    "@types/node": "^12.0.0",
    "typescript": "^4.1.3",
    "rimraf": "^3.0.2"
  }
{
  "compilerOptions": {
    "target": "es6",
    "allowJs": true,
    "module": "esnext",
    "moduleResolution": "node",
    "sourceMap": true,
    "declarationMap": true,
    "emitDeclarationOnly": true,
    "inlineSources": false,
    "declaration": true,
    "stripInternal": true,
    "lib": [
    "es2016",
    "dom"
    ],
    "outDir": "lib",
    "strict": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "rootDir": "src",
    "baseUrl": ".",
    "skipLibCheck": true,
    "noImplicitAny": false
  },
  "include": [
    "src"
  ]
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.