[Bug] Loading bulk models is causing major delay in intellisense
Reproducible in vscode.dev or in VS Code Desktop?
- [X] Not reproducible in vscode.dev or VS Code Desktop
Reproducible in the monaco editor playground?
- [ ] Not reproducible in the monaco editor playground
Monaco Editor Playground Code
// ========== Example #1: Loading .definition models instead of .ts ======================
monaco.languages.typescript.javascriptDefaults.setEagerModelSync(false);
monaco.languages.typescript.typescriptDefaults.setEagerModelSync(false);
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
noSemanticValidation: true,
noSyntaxValidation: true,
noSuggestionDiagnostics: true
});
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
noSemanticValidation: true,
noSyntaxValidation: true,
noSuggestionDiagnostics: true
});
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES2016,
allowNonTsExtensions: true,
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
module: monaco.languages.typescript.ModuleKind.CommonJS,
noEmit: true,
typeRoots: ["node_modules/@types"]
});
// Case #1: Load 2000 .d.ts files with each having 1 function declaration
let extraLibs = []
for (let i = 0; i < 2000; i++) {
extraLibs.push(
{
content: `export declare function next${i}() : string`,
filePath: monaco.Uri.file(`/node_modules/@types/external${i}/index.d.ts`).toString(true)
}
);
}
// Case #2: Load 1 .d.ts file with 2000 function declarations
/*let def = ''
for (let i = 0; i < 2000; i++) {
def = def.concat(`export declare function next${i}() : string\n`);
}
let extraLibs = []
extraLibs.push(
{
content: def,
filePath: monaco.Uri.file(`/node_modules/@types/external1/index.d.ts`).toString(true)
}
);*/
monaco.languages.typescript.typescriptDefaults.setExtraLibs(extraLibs);
extraLibs.forEach((lib) => monaco.editor.createModel(lib.content, "typescript", monaco.Uri.parse(lib.filePath)))
var jsCode = `import * as x from "external1"
const tt : string = x.next1();`;
monaco.editor.create(document.getElementById("container"), {
model: monaco.editor.createModel(jsCode, "typescript", monaco.Uri.file("main.tsx")),
});
// ========== Example #2: Loading .ts models instead of definitions ======================
/*monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true);
monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true);
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
noSemanticValidation: true,
noSyntaxValidation: true,
noSuggestionDiagnostics: true
});
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
noSemanticValidation: true,
noSyntaxValidation: true,
noSuggestionDiagnostics: true
});
editor = monaco.editor.create(
document.getElementById('container'),
{
minimap: { enabled: true },
scrollBeyondLastLine: true,
// model: null,
language: 'typescript',
theme: 'vs-dark',
value: 'function () {}\n\n'
}
);
// simulate 2000 .ts files
for (var fileIdx = 0; fileIdx < 2000; fileIdx++) {
for (var fnIdx = 0; fnIdx < 1; fnIdx++) {
monaco.editor.createModel(`
function test_${fileIdx}_${fnIdx}() {}
function fn_${fileIdx}_${fnIdx}() {}
function foo_${fileIdx}_${fnIdx}() {}
function bar_${fileIdx}_${fnIdx}() {}
function out_${fileIdx}_${fnIdx}() {}
`,
'typescript'
);
}
}*/
Reproduction Steps
Press Ctrl + Space after x. in the playground output (in the 2nd line: const tt : string = x.next1();). Suggestions dialog shows 'Loading...' indicator for 12-15 seconds before showing the eligible candidates.
for (let i = 0; i < 2000; i++) {
extraLibs.push(
{
content: `export declare function next${i}() : string`,
filePath: monaco.Uri.file(`/node_modules/@types/external${i}/index.d.ts`).toString(true)
}
);
}
Actual (Problematic) Behavior
Adding bulk of definition or ts file models is causing the 'Loading...' indicator for 12-15 seconds for every intellisense request. Not just the initial request.
Expected Behavior
Intellisense requests should complete with in reasonable time which otherwise directly impacts the developer experience
Additional Context
I posted this as a question in Stackoverflow (https://stackoverflow.com/questions/73936684/performant-way-to-load-2000-ts-models-into-monaco-editor-for-intellisense), but the solutions suggested (loading definition files) also didn't worked.
My observation: When I have bulk of files (ex: 2000), then the intellisense is taking longer time. But when I add 200K function declarations to 1 definition file, the perf is very good.

Just to see what is chocking the perf, I ran perf audit. Not sure if it is expected, but the same methods (like, getCodeFixesAtPosition) is getting called multiple times even for the same caret position.
Can this perf issue be solved if I use standalone typescript language server? Thanks
I can reproduce. However, what do you need this for:
extraLibs.forEach((lib) => monaco.editor.createModel(lib.content, "typescript", monaco.Uri.parse(lib.filePath)))
Thanks for confirming the issue.
I'm adding all the source files as models so that I'll get IntelliSense from all of them. Is there a way to get the same without adding them as models?
Thanks.
We ran into the same issue and are using patch-package to apply the fix below after installing monaco-editor. Thank you to @KallynGowdy for the inspiration: https://github.com/casual-simulation/vscode/commit/729f996578282277f3655bcd5906e882b0a8671a
It would be great if a fix for this could be incorporated into monaco-editor(-core) to avoid the need for a post-install patch. We attempted to set up the VS Code repository for local development to submit a PR but ran into issues with npm install, specifically related to Spectre. Unfortunately, the suggested fixes didn’t resolve the issue, creating too much friction in the process. As a result, we opted for this patch instead - hopefully, it proves useful for others facing the same challenge.
patches/monaco-editor+0.52.0.patch
diff --git a/node_modules/monaco-editor/esm/vs/editor/common/services/editorSimpleWorker.js b/node_modules/monaco-editor/esm/vs/editor/common/services/editorSimpleWorker.js
index 91df4d4..a839a70 100644
--- a/node_modules/monaco-editor/esm/vs/editor/common/services/editorSimpleWorker.js
+++ b/node_modules/monaco-editor/esm/vs/editor/common/services/editorSimpleWorker.js
@@ -303,6 +303,9 @@ export class EditorSimpleWorker extends BaseEditorSimpleWorker {
host: foreignHost,
getMirrorModels: () => {
return this._getModels();
+ },
+ getMirrorModelMap: () => {
+ return this._workerTextModelSyncServer._models;
}
};
if (this._foreignModuleFactory) {
diff --git a/node_modules/monaco-editor/esm/vs/language/typescript/ts.worker.js b/node_modules/monaco-editor/esm/vs/language/typescript/ts.worker.js
index 2858333..f468096 100644
--- a/node_modules/monaco-editor/esm/vs/language/typescript/ts.worker.js
+++ b/node_modules/monaco-editor/esm/vs/language/typescript/ts.worker.js
@@ -242506,12 +242506,10 @@ var TypeScriptWorker = class _TypeScriptWorker {
return models.concat(Object.keys(this._extraLibs));
}
_getModel(fileName) {
- let models = this._ctx.getMirrorModels();
- for (let i = 0; i < models.length; i++) {
- const uri = models[i].uri;
- if (uri.toString() === fileName || uri.toString(true) === fileName) {
- return models[i];
- }
+ const mirrorModelMap = this._ctx.getMirrorModelMap();
+ const model = mirrorModelMap[fileName];
+ if (model) {
+ return model;
}
return null;
}
Example of initial work by ts.worker.js without the fix applied:
The same example with the fix applied: