Closed Prinzhorn closed 3 years ago
looks like it's difficult to build workers correctly
in my case a got this error too with Angular 9 and inner exception (inside worker): regeneratorRuntime is not defined. to solve this I wrapped each worker in an angular worker (https://angular.io/guide/web-worker):
what I got for example:
editor.worker.ts
:
/// <reference lib="webworker" />
import 'monaco-editor/esm/vs/editor/editor.worker.js';
json.worker.ts
:
/// <reference lib="webworker" />
import 'monaco-editor/esm/vs/language/json/json.worker.js';
after I defined getWorker callback in MonacoEnvironment:
self.MonacoEnvironment = {
getWorker: (_, label) => {
if (label === 'json') {
return new Worker('./json.worker.ts', {
type: 'module',
});
}
return new Worker('./editor.worker.ts', {
type: 'module',
});
},
};
and this works great for development and production builds, maybe it will helpful for someone
@Prinzhorn
This is a complex topic because code is reused across AMD and ESM and things work differently under the two module systems.
The main conceptual difference is that under AMD, the web worker always starts with the entry point workerMain.js
, which then imports editorSimpleWorker.js
(this is sent in an initial message), which then can optionally loads custom web worker code if the web worker is a language worker (e.g. cssWorker
require([moduleId]
). The module id to load is received as a message by the web worker. This is possible in AMD because the AMD loader contains sufficient knowledge at runtime to convert the module id to a script path and load the code using importScripts
. On the other hand, under ESM, dynamic imports don't generally work e.g. await import(variableContainingModuleId)
will throw when processed by Webpack or other bundlers. Under ESM, all the imports must be spelled out. That is why the strategy under ESM is for the embedder of the editor to define a function MonacoEnvironment.getWorkerUrl
. When the needed worker must be created, instead of creating workerMain.js
as in the AMD case, the custom worker is started (like css.worker.js
which then loads editor.worker.js
which then loads editorSimpleWorker.js
). So under ESM, the generic code is loaded by the custom web worker code, while under AMD the generic code loads the custom web worker code.
The Unexpected Usage error comes when the embedder fails to define MonacoEnvironment.getWorkerUrl
or MonacoEnvironment.getWorker
correctly in the ESM case.
Now to specifically answer your question, editor.worker.js
is also loaded directly by the core editor for the generic web worker the core runs for diffing, link computation, word suggestions, etc.
The code on the UI side which constructs web workers and talks to them does not have the knowledge if it is running under ESM or under AMD. So it behaves the same in both cases. That is why even in the ESM case, the code on the UI side sends an initial message to load editorSimpleWorker.js
which is discarded here. You can see that custom web workers also ignore the initial message e.g. here.
As I mentioned in the beginning, this is quite complex because the same code is reused under AMD and ESM, the UI side behaves the same way regardless of AMD or ESM, and there is the generic editor core web worker and there are custom web workers that the languages use using the same infrastructure.
I am open to having made a mistake in this area, but if that is the case, can you please provide reproducible steps instead of an analysis?
Thanks for looking into this.
I am open to having made a mistake in this area, but if that is the case, can you please provide reproducible steps instead of an analysis?
Like I said, the official examples trigger the error (both browser-esm-parcel
and browser-esm-webpack
). Otherwise I'd probably not have made such bold claims :sweat_smile:
Here are the detailed steps:
git clone https://github.com/Microsoft/monaco-editor-samples.git
cd monaco-editor-samples
npm install .
npm run simpleserver
So far this is copied from the official example repo. Now update the language to one that needs a custom worker:
sed -i "s/language: 'javascript'/language: 'handlebars'/g" browser-esm-parcel/src/index.js
monaco.editor.create(document.getElementById('container'), {
value: ['function x() {', '\tconsole.log("Hello world!");', '}'].join('\n'),
- language: 'javascript'
+ language: 'handlebars'
});
And now follow the official steps to build the parcel esm example
cd browser-esm-parcel
npm install .
npm run build
npm run simpleserver
Visit http://localhost:9999/
Chromium
Firefox
Like I said this works equally for browser-esm-webpack, I just happen to use parcel for my projects.
Hm, this seems to be an issue with handlebars
in particular. I tried some other languages and also some garbage like foobarbaz and nothing else triggers it.
I can reproduce. It looks like handlebars
and razor
are configured to have web workers by monaco-html
here and they are not covered in any of the samples correctly.
Edit: It looks that monaco-css
is also doing this for scss
and less
.
Looks like the monaco-editor-webpack-plugin already supported this here, so there are no more places where these languages need to be supported in ESM.
Nice, thank you
I just got "Uncaught Error: Unexpected usage" myself. I found that there are so many issues and nobody seems to care. I looked into it and the root cause seems to be too simple to be true?
null
asforeignModule
argument https://github.com/microsoft/vscode/blob/b449c95a8460443ee6bf985bb6c8db63d395e6e6/src/vs/editor/editor.worker.ts#L30foreignModule
variable inside the scope is never changed, so the second constructor argument here is alwaysnull
toothis._foreignModuleFactory
is always null as well https://github.com/microsoft/vscode/blob/b449c95a8460443ee6bf985bb6c8db63d395e6e6/src/vs/editor/common/services/editorSimpleWorker.ts#L342@alexdima any idea why you did that (ignore the first worker message)? https://github.com/microsoft/vscode/commit/66091601a52d4f495e8b90c8c56283a5b1b07bd0
The issue can also be reproduced in the official ESM examples and it has likely been present from day one of ESM support. All you need to do is use a language that uses the generic worker, e.g. put
handlebars
here https://github.com/microsoft/monaco-editor-samples/blob/c5586a25cfd069349b6242a3d140223cc3d9110c/browser-esm-parcel/src/index.js#L23