monaco-react icon indicating copy to clipboard operation
monaco-react copied to clipboard

Describe how to use monaco Web Worker with the <Editor>

Open ppoulard opened this issue 4 years ago • 12 comments

Is your feature request related to a problem? Please describe.

In the console, I get those warnings :

backend.js:6 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 backend.js:6 You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker

Describe the solution you'd like

Since the UI is subject to freeze, I would rather create the expected monaco web worker

Describe alternatives you've considered

None

Additional context

I don't know how to use such worker ; it seems that monaco use it for language processing stuff. And I do have a language languages.IMonarchLanguage and conf languages.LanguageConfiguration.

Please could you add a snippet code in the doc ?

Thanks

ppoulard avatar Apr 02 '20 09:04 ppoulard

Hello @ppoulard. By default, monaco tries to create webworkers to organize language processing (and not only) in other threads, rather than in the main thread to avoid blocking main (UI) thread. So, usually, when it starts to implement this behavior (it tries to create webworkers) and faces some problems during webworkers creation, it shows the error you've mentioned. To say short, probably, it couldn't manage to create webworkers in your environment; it can be related to your browser, version of the browser, maybe you manually/accidentally have disabled it. So, that's why, to understand your problem, first of all, provide me please, the parameters of your environment. It would be great if you could manage to create a reproducible code snippet.

suren-atoyan avatar Apr 04 '20 13:04 suren-atoyan

Hello,

Here is the way I initialize it (observer() comes from MobX) :

import Editor, { monaco as Monaco } from '@monaco-editor/react';
import { editor, languages } from 'monaco-editor';

export const LaTeXEditor: FC = observer(() => {
    const [ed, setEditor] = useState<editor.IStandaloneCodeEditor>();
    return <Editor language='latex'
                   value={ store.latexContent }
                   editorDidMount={ (_, ed) => {
                       setEditor(ed);
                       ed.onDidChangeModelContent(ev => {
                           handleContentChanges(ed.getValue());
                       });
                   }}
    />
}
const latexLanguageConf: languages.LanguageConfiguration = {
    // ...
}
const latexLanguage = {
    // ...
}
(async () => {
    const monaco = await Monaco.init();
    monaco.languages.register({ id: 'latex' });
    monaco.languages.setMonarchTokensProvider('latex', latexLanguage);
    monaco.languages.setLanguageConfiguration('latex', latexLanguageConf);
})();

Do you see anything weird in that sequence ? Thanks for your help

ppoulard avatar Apr 06 '20 08:04 ppoulard

@ppoulard

I don't see anything weird from first glance but at the same time, I can't reproduce it. I would ask you to create a snippet in codesandbox, that I will be able to see the error.

suren-atoyan avatar Apr 06 '20 16:04 suren-atoyan

@ppoulard

I don't see anything weird from first glance but at the same time, I can't reproduce it. I would ask you to create a snippet in codesandbox, that I will be able to see the error.

you can minimize your code for sandbox, remove mobix, use local state instead of store.

suren-atoyan avatar Apr 06 '20 16:04 suren-atoyan

Hello @ppoulard. Do you still have the issue? Is it relevant?

suren-atoyan avatar Jun 16 '20 11:06 suren-atoyan

Hi @suren-atoyan , I've just upgraded to v3.3.1 and the issue still exist. I'm almost sure it is due to language registration (as shown in the code above). Unfortunately I didn't have the time to make a codesanbox sample, although it is still in my todo list !

ppoulard avatar Jun 16 '20 12:06 ppoulard

@ppoulard, no worries, I just wanted to check the status. And thank you for quick response.

suren-atoyan avatar Jun 16 '20 12:06 suren-atoyan

Hey there, any solutions yet? integrated this package in a CRA app and get the same issue.

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

I'm not sure how to setup these web workers with the monaco-react package and I can not find a documentation. My worker Url setup:

 (window as any).MonacoEnvironment = {
        getWorkerUrl(moduleId: string, label: string) {
            if (label === "yaml") {
                return "./yaml.worker.bundle.js";
            }
            return "./editor.worker.bundle.js";
        },
    };

The issue is he looks for the bundle, but cannot find them, as it doesn't get copied. But I don't know how to copy these files without a webpack config.

I would appreciate any point into the right direction! Thanks!

sabine19 avatar Jan 28 '21 11:01 sabine19

This is still an issue for me. Some of my users are observing a strong latency in the editor. I'm still looking for a recipe that let me bundle (with Rollup | Webpack) the language def apart, and load it in monaco worker.

ppoulard avatar Jan 28 '21 13:01 ppoulard

I tested a lot with my CRA app to get the workers running. My findings have been that there are 2 solutions:

The first solution is to eject CRA app. (Then you have full control over your settings, but this isn't the sense of create-react-app or monaco-react). So I tried again...

My second solution uses react-app-rewired to get the possibility to override webpack settings. You have to place a config-overrides.js file in the root of the project. Then for easier configuration I install the monaco-editor-webpack-plugin.

/* config-overrides.js */
const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");

module.exports = function override(config, env) {
  config.plugins.push(
    new MonacoWebpackPlugin({
      languages: ["yaml"],
    })
  );
  return config;
};

My findings have been, that caution should be taken, which versions of the packages are installed as some of them have dependencies to specific monaco-editor versions. So my package.json looks like:

{
  "name": "monaco-editor-rewired",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@monaco-editor/react": "^4.0.9",
    "@testing-library/jest-dom": "^5.11.9",
    "@testing-library/react": "^11.2.3",
    "@testing-library/user-event": "^12.6.2",
    "@types/jest": "^26.0.20",
    "@types/node": "^12.19.15",
    "@types/react": "^16.14.2",
    "@types/react-dom": "^16.9.10",
    "monaco-editor": "^0.21.2",
    "monaco-editor-webpack-plugin": "^2.1.0",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.1",
    "typescript": "^4.1.3",
    "web-vitals": "^0.2.4"
  },
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "devDependencies": {
    "react-app-rewired": "^2.1.8"
  }
}

If that doesn't work for you, you can update the config-overrides.js and add following line:

filename: "[name].worker.js", (default)

Therefore the worker file gets explicitly copied. Important ist that the file name, that you return in the getWorkerUrl is the same.

Hope this helps someone out there ;)

Update: newest version now fit together: "@monaco-editor/react": "^4.0.9", "monaco-editor": "^0.22.3", "monaco-editor-webpack-plugin": "^3.0.0", "react-app-rewired": "^2.1.8",

sabine19 avatar Jan 30 '21 12:01 sabine19

Finally, I used craco to bundle the worker ; here is the code, somewhere in my app (before using the editor) :

// @ts-ignore
global.MonacoEnvironment = {
    getWorkerUrl(_: string, __: string) {
        // see monaco.webpack.config.js
        return '/static/editor.worker.bundle.js';
    },
};

the actual webpack config monaco.webpack.config.js :

const webpack = require('webpack');
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const mode  = process.env.NODE_ENV === 'production' ? 'production' : 'development';
console.log('Webpacking editor.worker for', mode);
module.exports = {
    mode,
    devtool: 'source-map',
    entry: {
        'editor.worker': 'monaco-editor/esm/vs/editor/editor.worker.js',
    },
    output: {
        globalObject: 'self',
        path: path.resolve(__dirname, 'public/static'),
        publicPath: '/build/',
        filename: '[name].bundle.js',
        chunkFilename: '[id].[hash].chunk.js',
    },
    node: {
        fs: 'empty',
        child_process: 'empty',
        net: 'empty',
        crypto: 'empty',
    },
    optimization: {
        noEmitOnErrors: true,
        minimize: process.env.NODE_ENV === 'production',
        minimizer: [
            new TerserPlugin({
                exclude: /eslint_bundle/,
                parallel: true,
            }),
        ],
    },
    plugins: [
        new webpack.IgnorePlugin(
          /^((fs)|(path)|(os)|(crypto)|(source-map-support))$/,
          /vs(\/|\\)language(\/|\\)typescript(\/|\\)lib/,
        ),
    ],
    resolve: {
        extensions: ['.tsx', '.ts', '.js'],
        alias: {
            vscode: 'monaco-languageclient/lib/vscode-compatibility',
        },
    },
};

the craco conf file craco.config.js:

module.exports = {
    webpack: {
        alias: {
            vscode: 'monaco-languageclient/lib/vscode-compatibility'
        }
    }
};

and some scripts added to package.json :

  "scripts": {
    "build:monaco-worker": "webpack --config monaco.webpack.config.js",
    "prebuild": "npm run lint && npm run build:monaco-worker",
  }

and of course CRA scripts are replaced by craco

ppoulard avatar Jul 20 '21 13:07 ppoulard

https://www.npmjs.com/package/@craco/craco

ppoulard avatar Jul 20 '21 13:07 ppoulard

I am closing this due to inactivity, feel free to re-open it

suren-atoyan avatar Jan 19 '24 17:01 suren-atoyan