Félix Malfait f4d5500fc4 fix(front): run a single Monaco instance across the app (#23855)
## Problem

Three Sentry issues, all `Missing requestHandler or method: <method>`,
first seen in v2.27.0:

| Method | Page | Events |
|---|---|---|
| `findDocumentColors` | `/settings/mcp-apis` | 170 |
| `resetSchema` | `/settings/mcp-apis` | 22 |
| `getCodeFixesAtPosition` | `/object/workflow/…` | 4 |

The first two are Monaco **JSON worker** methods, the third a
**TypeScript worker** method. All of them bottom out in
`monaco-editor/esm/vs/editor/common/services/editorSimpleWorker.js` at
`$fmr` — the foreign-module dispatcher — with `_foreignModule` still
`null`.

## Root cause

Two Monaco copies end up on the page at **different versions**:

1. **ESM `monaco-editor@0.52.2`**, bundled by Vite — what GraphiQL 5
uses.
2. **AMD `monaco-editor@0.55.1` from jsDelivr** — `@monaco-editor/react`
→ `@monaco-editor/loader@1.7.0`, whose default CDN path is hardcoded to
`monaco-editor@0.55.1/min/vs`. Nothing calls `loader.config({ monaco
})`, so it goes to the CDN.

`setupGraphiqlMonacoWorkers.ts` assigns
**`globalThis.MonacoEnvironment`**, a single global both instances read,
as a module side effect of the lazily-routed `GraphQLPlayground`. So
once the playground has been opened, the 0.55.1 CDN instance stops using
its own AMD workers and starts getting Vite-bundled 0.52.2 ones.

The two versions don't share a worker protocol: 0.52 routes
language-service calls through `$loadForeignModule` + `$fmr`, which
0.55's client never sends. `_foreignModule` stays `null`, and every call
rejects.

On `/settings/mcp-apis` the consumer is `SettingsMcpSetup.tsx` —
`<CodeEditor language="json">` for the MCP config. Monaco fires
`resetSchema` on `onWillDisposeModel` / `onDidChangeModelLanguage` and
`findDocumentColors` continuously, which is why one bug produces 170
events and 22.

There is a second, independent bug in the same file: the `switch` only
maps `json` and `graphql`, so `typescript` / `javascript` / `css` /
`html` fall through to the bare `EditorWorker`, which carries no
language service at all. That's the workflow-page
`getCodeFixesAtPosition`, and it would break even with matching
versions.

Impact is worse than the log noise suggests: after visiting the
playground, JSON validation/colors in the MCP config editor and TS
intellisense/quick-fixes in the workflow code editor silently stop
working for the rest of the session.

## Changes

- **`twenty-ui/src/input/CodeEditor/CodeEditor.tsx`** — configure
`@monaco-editor/react` with the bundled Monaco (`loader.config({ monaco
})`) instead of letting it fetch its own from jsDelivr. The import stays
dynamic so Monaco is still only downloaded when an editor actually
renders; the component shows its existing `Loader` until the loader is
configured.
- **`twenty-front/src/modules/app/utils/setupMonacoEnvironment.ts`**
(new, replaces
`settings/mcp-and-apis/utils/setupGraphiqlMonacoWorkers.ts`) — app-level
worker factory mapping every label Monaco can ask for: `json`,
`css`/`scss`/`less`, `html`/`handlebars`/`razor`,
`typescript`/`javascript`, `graphql`, and the generic editor worker as
the fallback.
- **`twenty-front/src/index.tsx`** and **`.storybook/preview.tsx`** —
set it up once for the app and for stories, rather than as a side effect
of one lazy route.

Dropping the CDN also means the code editors work in self-hosted and
air-gapped deployments, which today silently fall back to a broken
editor when jsDelivr is unreachable.

## Verification

- `nx build twenty-front` passes; `css.worker`, `html.worker` and
`ts.worker` chunks are now emitted alongside the existing
`editor`/`json`/`graphql` ones.
- Monaco stays lazy — `edcore.main` is not statically imported by the
entry chunk and is absent from `index.html`'s modulepreloads. Measured
against a baseline build of `main`, the entry chunk goes from 2,598,088
B to 2,599,040 B (**+952 B**).
- `oxlint` and `oxfmt --check` clean on all touched files; `tsc
--noEmit` clean for `twenty-ui` and reports nothing new for the touched
`twenty-front` files.

Not verified in a browser — worth a manual pass on the playground → MCP
tab → workflow code editor sequence that reproduced the original errors.

Fixes TWENTY-FRONT-8YV
Fixes TWENTY-FRONT-8YW
Fixes TWENTY-FRONT-ADE

---
_Generated by [Claude
Code](https://claude.ai/code/session_01RgPXkmUHANwD7ooUMqNYr9)_

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/23855?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-08-06 14:26:54 +02:00
2026-06-11 11:02:28 +02:00

Twenty logo

The #1 Open-Source CRM

Website · Documentation · Roadmap · Discord · Figma

Twenty banner


Why Twenty

Twenty gives technical teams the building blocks for a custom CRM that meets complex business needs and quickly adapts as the business evolves. Twenty is the CRM you build, ship, and version like the rest of your stack.

Learn more about why we built Twenty


Installation

Cloud

The fastest way to get started. Sign up at twenty.com and spin up a workspace in under a minute, with no infrastructure to manage and always up to date.

Build an app

Scaffold a new app with the Twenty CLI:

npx create-twenty-app my-app

Define objects, fields, and views as code:

import { defineObject, FieldType } from 'twenty-sdk/define';

export default defineObject({
  nameSingular: 'deal',
  namePlural: 'deals',
  labelSingular: 'Deal',
  labelPlural: 'Deals',
  fields: [
    { name: 'name', label: 'Name', type: FieldType.TEXT },
    { name: 'amount', label: 'Amount', type: FieldType.CURRENCY },
    { name: 'closeDate', label: 'Close Date', type: FieldType.DATE_TIME },
  ],
});

Then ship it to your workspace:

npx twenty app:publish --private

See the app development guide for objects, views, agents, and logic functions.

Self-hosting

Run Twenty on your own infrastructure with Docker Compose, or contribute locally via the local setup guide.



Everything you need

Twenty gives you the building blocks of a modern CRM (objects, views, workflows, and agents) and lets you extend them as code. Here's a tour of what's in the box.

Want to go deeper? Read the User Guide for product walkthroughs, or the Documentation for developer reference.

Create your apps

Learn more about apps in doc

Stay on top with version control

Learn more about version control in doc

All the tools you need to build anything

Learn more about primitives in doc

Customize your layouts

Learn more about layouts in doc

AI agents and chats

Learn more about AI in doc

Plus all the tools of a good CRM

Learn more about CRM features in doc


Stack

Thanks

Greptile      Sentry      Crowdin

Thanks to these amazing services that we use and recommend for code review (Greptile), catching bugs (Sentry) and translating (Crowdin).

Join the Community

Star the repo · Discord · Feature requests · Releases · X · LinkedIn · Crowdin · Contribute

S
Description
The open alternative to Salesforce, designed for AI.
Readme AGPL-3.0 1.4 GiB
Languages
TypeScript 79.6%
MDX 17.3%
JavaScript 2.7%
Python 0.2%
SCSS 0.1%