Skip to content

Conversation

dorshinar
Copy link
Contributor

Hi! :)

Following up on this issue, I added the necessary exports for Graphiql to work.

However, I can't validate it because I was not able to build the project locally and link all created packages to my project.
Would you be able to help me with that?

There's also another file missing that I couldn't figure out how to include. It's /monaco-editor/esm/vs/editor/edcore.main.js that you can see here. The file is simply re-exporting some things, and I think that for the Graphiql use case export * from './editor.api.js'; would be enough, as the editor.api.js already exists.
In monaco's source code I believe it is generated by the bundler here, I'm not sure how to mimic this behavior in rollup so I would appreciate any help with that. It's also fine to include a static file with the necessary export.

Thank you very much!

@CGNonofr CGNonofr force-pushed the export-modules-for-graphiql branch from 7597898 to bd51c4d Compare September 25, 2025 12:10
@CGNonofr
Copy link
Contributor

Thanks!

However, I can't validate it because I was not able to build the project locally and link all created packages to my project.
Would you be able to help me with that?

Sure! tell me more about what's blocking you?

There's also another file missing that I couldn't figure out how to include. It's /monaco-editor/esm/vs/editor/edcore.main.js that you can see here. The file is simply re-exporting some things, and I think that for the Graphiql use case export * from './editor.api.js'; would be enough, as the editor.api.js already exists.
In monaco's source code I believe it is generated by the bundler here, I'm not sure how to mimic this behavior in rollup so I would appreciate any help with that. It's also fine to include a static file with the necessary export.

It is indeed a monaco-editor specific file, and as you said it's just re-exporting editor.api.js so it can be replaced safely

You can probably to something similar to what is done for editor.worker.js, just doing export * from './editor.api.js'; in the sources

@dorshinar
Copy link
Contributor Author

Awesome, updated the config to include the edcore.main.js file.
Regarding my errors, I ran npm install and npm run build, and I get an error:

[!] Error: Cannot find module '../util/utimes.js'
Require stack:
- /workspaces/monaco-vscode-api/node_modules/rollup-plugin-copy/node_modules/fs-extra/lib/copy-sync/copy-sync.js
- /workspaces/monaco-vscode-api/node_modules/rollup-plugin-copy/node_modules/fs-extra/lib/copy-sync/index.js
- /workspaces/monaco-vscode-api/node_modules/rollup-plugin-copy/node_modules/fs-extra/lib/index.js
- /workspaces/monaco-vscode-api/node_modules/rollup-plugin-copy/dist/index.commonjs.js

I'm using MacOS 15.7 and running in the dev-container provided in the repo.

@CGNonofr
Copy link
Contributor

CGNonofr commented Sep 25, 2025

Hum very weird error 🤔 Never seen it before

does /workspaces/monaco-vscode-api/node_modules/rollup-plugin-copy/node_modules/fs-extra/lib/util/utimes.js exist?

@dorshinar
Copy link
Contributor Author

Ok I did a complete uninstall and reinstall and now I was able to build the packages without errors.
But I still can't link them to my project.
I'm using yarn and set the resolution as follows:

"resolutions": {
    "@codingame/monaco-vscode-api": "portal:<REDACTED>/monaco-vscode-api/dist/packages/monaco-vscode-api",
    "monaco-editor": "portal:<REDACTED>/monaco-vscode-api/dist/packages/monaco-vscode-editor-api"
}

But running yarn install I get:

$  yarn
➤ YN0000: · Yarn 4.9.4
➤ YN0000: ┌ Project validation
➤ YN0057: │ @wiz/portal: Resolutions field will be ignored
➤ YN0000: └ Completed
➤ YN0000: ┌ Resolution step
➤ YN0082: │ @codingame/monaco-vscode-5452e2b7-9081-5f95-839b-4ab3544ce28f-common@npm:0.0.0-semantic-release: No candidates found
➤ YN0000: └ Completed in 1s 754ms
➤ YN0000: · Failed with errors in 1s 759ms

@CGNonofr
Copy link
Contributor

yes, it references the version 0.0.0-semantic-release of other packages...

The simplest way is probably to not try to install the package, but simply copy the content of the package in your node_modules by hands

@CGNonofr
Copy link
Contributor

CGNonofr commented Oct 8, 2025

What is the status? do you consider it ready to be merged? I'm not sure since you just merged main into it

@dorshinar
Copy link
Contributor Author

No sorry, it's not ready yet. Had to take a break and only now I'm returning to it so I made sure to work on the latest version.
I hope to finish it in the next few days

@dorshinar
Copy link
Contributor Author

Seems that monaco-editor ships with built-in languages while @codingame/monaco-vscode-editor-api does not.
Specifically, I need monaco-editor/esm/vs/basic-languages/graphql/graphql.contribution.js and monaco-editor/esm/vs/language/json/monaco.contribution.js.
Is there an easy way to copy them to the dist? I'm looking for something similar to EDITOR_API_EXPOSE_MODULES but that only works for the vscode pacakge

@CGNonofr
Copy link
Contributor

CGNonofr commented Oct 8, 2025

Seems that monaco-editor ships with built-in languages while @codingame/monaco-vscode-editor-api does not. Specifically, I need monaco-editor/esm/vs/basic-languages/graphql/graphql.contribution.js and monaco-editor/esm/vs/language/json/monaco.contribution.js. Is there an easy way to copy them to the dist? I'm looking for something similar to EDITOR_API_EXPOSE_MODULES but that only works for the vscode pacakge

The standalone languages are bundled in @codingame/monaco-vscode-standalone-languages, so it will be difficult to redirect to it.

An option is to create an empty module at that location

@dorshinar
Copy link
Contributor Author

dorshinar commented Oct 9, 2025

Ok I got it wrong, yeah it works I just need to import @codingame/monaco-vscode-standalone-json-language-features.

Now I have another issue, I see that when loading workers, the logic (for example in src/editor.api.ts) tries to load the worker with the getWorker function, and falls back to getWorkerUrl if getWorker is undefined.
However, I see that getWorker is always defined, but does not contain the workers for both GraphQL and JSON.
We use vite-plugin-monaco-editor-esm to load the monaco environment, along with the workers we need.
The call to getWorker with either graphql or json fails, and it never tries the getWorkerUrl function.

I edited the files locally and it does seem to work, but the file that loads the JSON worker (called jsonMode.js under monaco-vscode-standalone-json-language-features) is copied over directly from monaco-editor. Not sure how to proceed.

After changing it manually (which, again, is not a viable solution), I get the following errors:
CleanShot 2025-10-09 at 12 43 49@2x

@CGNonofr
Copy link
Contributor

CGNonofr commented Oct 9, 2025

However, I see that getWorker is always defined, but does not contain the workers for both GraphQL and JSON.

What do you mean? you're the one expected to provide the getWorker function

We use vite-plugin-monaco-editor-esm to load the monaco environment

Probably not a good idea

@dorshinar
Copy link
Contributor Author

IIUC, the getWorker method is supplied by monaco-languageclient. I'm a little fuzzy on the boundaries between the libraries.

Probably not a good idea

How should we do it then?

@CGNonofr
Copy link
Contributor

CGNonofr commented Oct 9, 2025

IIUC, the getWorker method is supplied by monaco-languageclient. I'm a little fuzzy on the boundaries between the libraries.

I do think monaco-languageclient allows to register your own workers, if you can't use getWorkerUrl just implement getWorker and return new Worker(new URL(<worker_url>, import.meta.url))

How should we do it then?

I don't know what it is doing exactly, nothing else is required 🤷

@kaisalmen
Copy link
Collaborator

@dorshinar
Copy link
Contributor Author

dorshinar commented Oct 9, 2025

Got it @kaisalmen, I switched to calling useWorkerFactory where I manually create the workers
Seems to load them now 👍

But I'm still seeing these errors:
CleanShot 2025-10-09 at 13 57 04@2x

The error comes from here, where the createData.languageConfig is undefined. I'm not sure where it should come from.
CleanShot 2025-10-09 at 13 57 38@2x

@kaisalmen
Copy link
Collaborator

kaisalmen commented Oct 9, 2025

@dorshinar have you considered to pre-bundle the graphql worker with rollup or esbuild? It might circumvent the problem.

@dorshinar
Copy link
Contributor Author

@kaisalmen I believe this is handled by vite automatically

Can you elaborate?

@kaisalmen
Copy link
Collaborator

Can you elaborate?

It is possible to just bundle the worker as single ESM file, then the build performing the production build will not see a need to touch/transform it. Depending on the build tooling (I have next.js / webpack in mind here) this can circumvent issues. But it may not help in your situation.

@dorshinar
Copy link
Contributor Author

Got it, so this may solve the second issue.
But the first issue seems to come from a miscommunication between the lanugage client and the language server, running in the worker.
The message does not contain the languageConfig that is apparently required.

@dorshinar
Copy link
Contributor Author

I did some more digging. I looked at how the monaco-graphql worker should work and how it works when using monaco-languageclient with the @codingame packages, and I saw a discrepancy.

I debugged a working example from the Graphiql repo, and saw that the GraphQLWorker is loaded when an event is sent with method: "$loadForeignModule", but in my not-working project, GraphQLWorker is loaded and initialized when an event is sent with method: $initialize.
The $loadForeignModule event in the working example has the necessary languageConfig, but the $initialize does not (in both examples).

Do you have any idea where the problem might be?

@CGNonofr
Copy link
Contributor

I did some more digging. I looked at how the monaco-graphql worker should work and how it works when using monaco-languageclient with the @codingame packages, and I saw a discrepancy.

I debugged a working example from the Graphiql repo, and saw that the GraphQLWorker is loaded when an event is sent with method: "$loadForeignModule", but in my not-working project, GraphQLWorker is loaded and initialized when an event is sent with method: $initialize. The $loadForeignModule event in the working example has the necessary languageConfig, but the $initialize does not (in both examples).

Do you have any idea where the problem might be?

Monaco-editor workers has changed quite a lot in the last monaco-editor version. We had a compatibility layer until monaco-editor 53 is out that is now removed, and it was about initialize and loadForeignModule. Does graphiql work with the latest official monaco-editor?

@dorshinar
Copy link
Contributor Author

I think it's not working with 0.53, and your explanation makes sense.
Their example uses monaco 0.52, and fails when I tried to upgrade to 0.54.

@CGNonofr
Copy link
Contributor

Here's the backward compatibility code that was removed in the last versions: d3fcbe9

I guess you can apply that patch in your node_modules until graphiql updates

@dorshinar
Copy link
Contributor Author

dorshinar commented Oct 15, 2025

Awesome, it works!
Now I get a functional Graphiql, but I'm still seeing errors in the console.

I believe the error originates from the wordHighlighter.js in monaco-vscode-api. Seems like the files for the query and variables (denoted by xxx-variables.json and xxx-operation.json are not being created in the in-memory file system, however they are accessed when I click on a panel to focus it.
Syntax highlighting works correctly, as well as the language server.

Uncaught (in promise) FileOperationError: Unable to read file '/r1j-variables.json' (Error: Unable to resolve nonexistent file '/r1j-variables.json')
    at FileServiceOverride.restoreReadError (fileService.js:537:18)
    at FileServiceOverride.doReadFileStream (fileService.js:521:24)
    at async BrowserTextFileService2.doRead (textFileService.js:170:28)
    at async BrowserTextFileService2.readStream (textFileService.js:152:41)
    at async _a3.resolveFromFile (textFileEditorModel.js:297:29)
    at async _a3.resolve (textFileEditorModel.js:198:9)
    at async TextFileEditorModelManager2.doResolve (textFileEditorModelManager.js:294:13)
    at async ResourceModelCollection2.doCreateReferencedObject (textModelResolverService.js:53:27)
    at async AsyncReferenceCollection.acquire (lifecycle.js:432:28)
    at async TextModelResolverService2.createModelReference (textModelResolverService.js:176:16)

EDIT:
The language server works for the query, not for the variables json. I'm still trying to find out why.

@dorshinar
Copy link
Contributor Author

Regarding my issue of a file not being created, I see that monaco-vscode-api recommends using the async createModelReference instead of the sync createModel.
I believe this is the issue - Graphiql calls those function in useEffect, and here's the getOrCreateModel implementation.

Because it's called in useEffect the function must be synchronous, otherwise they can't return the cleanup function that disposes of the resources.
Is there a way to make createModel work? Or have a synchronous version of createModelReference?

@CGNonofr
Copy link
Contributor

CGNonofr commented Oct 16, 2025

createModelReference is a function that reads the content from the disk and create the model if it doesn't exist, there's no way to make it sync

The issue with using createModel is that no ref on it will exist, so it may crash the next time createModelReference is called, which is done internally in VSCode

getOrCreateModel uses the existing model if it exists, so it will work as soon as you create the model using createModelReferences before

Also make sure to not be disposing the model reference until graphiql doesn't need it anymore or the model may be deleted

@dorshinar
Copy link
Contributor Author

dorshinar commented Oct 19, 2025

Got it. Tried that and now I'm not getting the error in the console, but the variables JSON validation is still not working.
I see that monaco.languages.json.jsonDefaults.diagnosticsOptions is updated correctly:

{
    "schemaValidation": "error",
    "validate": true,
    "allowComments": true,
    "trailingCommas": "ignore",
    "schemas": [
        {
            "uri": "file:///file%3A///r1j-variables-schema.json",
            "schema": {
                "$schema": "http://json-schema.org/draft-04/schema",
                "type": "object",
                "properties": {...},
                "required": [...],
                "additionalProperties": false,
                "definitions": {...},
                "$id": "monaco://variables-schema.json",
                "title": "GraphQL Variables"
            },
            "fileMatch": [
                "file:///r1j-variables.json"
            ]
        }
    ],
    "enableSchemaRequest": false
}

But no markers are shown.
The files match, and I also tried a static schema but it didn't show any markers.

I tried adding more imports, but to no avail. This is what I have now:

import '@codingame/monaco-vscode-standalone-languages';
import '@codingame/monaco-vscode-standalone-json-language-features';
import '@codingame/monaco-vscode-json-default-extension';
import '@codingame/monaco-vscode-json-language-features-default-extension';

import getLanguageServiceOverride from '@codingame/monaco-vscode-languages-service-override';
import getFilesServiceOverride from '@codingame/monaco-vscode-files-service-override';
import getMarkersServiceOverride from '@codingame/monaco-vscode-markers-service-override';
import getBaseServiceOverride from '@codingame/monaco-vscode-base-service-override';
import getExtensionsServiceOverride from '@codingame/monaco-vscode-extensions-service-override';
import getModelServiceOverride from '@codingame/monaco-vscode-model-service-override';

Am I missing something?

@CGNonofr
Copy link
Contributor

Got it. Tried that and now I'm not getting the error in the console, but the variables JSON validation is still not working. I see that monaco.languages.json.jsonDefaults.diagnosticsOptions is updated correctly:

{
    "schemaValidation": "error",
    "validate": true,
    "allowComments": true,
    "trailingCommas": "ignore",
    "schemas": [
        {
            "uri": "file:///file%3A///r1j-variables-schema.json",
            "schema": {
                "$schema": "http://json-schema.org/draft-04/schema",
                "type": "object",
                "properties": {...},
                "required": [...],
                "additionalProperties": false,
                "definitions": {...},
                "$id": "monaco://variables-schema.json",
                "title": "GraphQL Variables"
            },
            "fileMatch": [
                "file:///r1j-variables.json"
            ]
        }
    ],
    "enableSchemaRequest": false
}

But no markers are shown. The files match, and I also tried a static schema but it didn't show any markers.

I tried adding more imports, but to no avail. This is what I have now:

import '@codingame/monaco-vscode-standalone-languages';
import '@codingame/monaco-vscode-standalone-json-language-features';
import '@codingame/monaco-vscode-json-default-extension';
import '@codingame/monaco-vscode-json-language-features-default-extension';

import getLanguageServiceOverride from '@codingame/monaco-vscode-languages-service-override';
import getFilesServiceOverride from '@codingame/monaco-vscode-files-service-override';
import getMarkersServiceOverride from '@codingame/monaco-vscode-markers-service-override';
import getBaseServiceOverride from '@codingame/monaco-vscode-base-service-override';
import getExtensionsServiceOverride from '@codingame/monaco-vscode-extensions-service-override';
import getModelServiceOverride from '@codingame/monaco-vscode-model-service-override';

Am I missing something?

Do you have a minimal reproduction project to provide?

@dorshinar
Copy link
Contributor Author

dorshinar commented Oct 20, 2025

Sure.
Here's a demo project where this happens. To make it run I ran npm install and then copied over the compiled @codingame/* libs from this branch.
You can try this query:

query MyQuery ($limit: Int) {
  ability(limit: $limit) {
    generaton_id
  }
}

With this variables json:

{
    "limdit": 1
}

The generaton_id is a misspelling of generation_id, and we can see the error:
CleanShot 2025-10-20 at 11 02 42

But limidt is also a misspelling of limit, but no squiggly line:
CleanShot 2025-10-20 at 11 03 10

@CGNonofr
Copy link
Contributor

would you mind packing the modified libraries and installing them on your project so I don't have to rebuild them?

@dorshinar
Copy link
Contributor Author

Yeah sure, do you want me to zip the node_modules folder?

@CGNonofr
Copy link
Contributor

Yeah sure, do you want me to zip the node_modules folder?

I meant:

  • npm pack the changed packages
  • moving the tgz the the final project and install them
  • push the tgz in the repo

That's what I do when I need to use a non-published yet library

@dorshinar
Copy link
Contributor Author

dorshinar commented Oct 20, 2025

I'm not sure how to do it, the installation from gzip keeps failing because it's missing nested deps.
I even tried gzipping every packages in monaco-vscode-api but it's not working.
Errors look like this:
CleanShot 2025-10-20 at 11 51 15

@CGNonofr
Copy link
Contributor

Ok it's maybe more complicated than that 🤔

let's merge and deploy this MR, and then open another issue for that problem?

@dorshinar
Copy link
Contributor Author

Fine by me

@CGNonofr CGNonofr self-requested a review October 20, 2025 08:57
@CGNonofr CGNonofr merged commit 4166d4a into CodinGame:main Oct 20, 2025
@dorshinar
Copy link
Contributor Author

Opened a separate issue.

Copy link

🎉 This PR is included in version 22.1.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants