From 421c0c9b023705ceb56343bc4a7dea06a822400b Mon Sep 17 00:00:00 2001 From: szzhoujiarui <311234381+szzhoujiarui@users.noreply.github.com> Date: Sun, 2 Aug 2026 04:22:33 +0000 Subject: [PATCH] UI: Support Monaco Editor 0.56 Monaco 0.56 enforces its package exports, so private deep imports prevent the UI from linting and building after the dependency upgrade. --- airflow-core/src/airflow/ui/package.json | 2 +- airflow-core/src/airflow/ui/pnpm-lock.yaml | 28 +++++++-------- .../MonacoEditor/configureMonaco.ts | 34 ++++++++----------- .../MonacoEditor/pythonFStrings.test.ts | 4 +-- airflow-core/src/airflow/ui/src/vite-env.d.ts | 9 ++--- 5 files changed, 34 insertions(+), 43 deletions(-) diff --git a/airflow-core/src/airflow/ui/package.json b/airflow-core/src/airflow/ui/package.json index f50df11191ee4..31649d51b5cb6 100644 --- a/airflow-core/src/airflow/ui/package.json +++ b/airflow-core/src/airflow/ui/package.json @@ -52,7 +52,7 @@ "i18next-http-backend": "^4.0.1", "katex": "^0.17.0", "mermaid": "^11.16.0", - "monaco-editor": "^0.55.1", + "monaco-editor": "^0.56.0", "next-themes": "^0.4.6", "react": "^19.2.8", "react-chartjs-2": "^5.3.1", diff --git a/airflow-core/src/airflow/ui/pnpm-lock.yaml b/airflow-core/src/airflow/ui/pnpm-lock.yaml index 7d9c3cf60a724..9da642f6e431f 100644 --- a/airflow-core/src/airflow/ui/pnpm-lock.yaml +++ b/airflow-core/src/airflow/ui/pnpm-lock.yaml @@ -55,7 +55,7 @@ importers: version: 1.2.3 '@monaco-editor/react': specifier: ^4.7.0 - version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 4.7.0(monaco-editor@0.56.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/react-query': specifier: ^5.101.4 version: 5.101.4(react@19.2.8) @@ -120,8 +120,8 @@ importers: specifier: ^11.16.0 version: 11.16.0 monaco-editor: - specifier: ^0.55.1 - version: 0.55.1 + specifier: ^0.56.0 + version: 0.56.0 next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -2307,12 +2307,12 @@ packages: dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} - dompurify@3.2.7: - resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} - dompurify@3.4.11: resolution: {integrity: sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==} + dompurify@3.4.8: + resolution: {integrity: sha512-yb1cEmaOum7wFvOCSQxyfgVlv5D47Rc30iZWoMpbDIWTnJ6grDDQyu2KFJzB2k7u0pMuJcQ1zphH//fFnw2tjQ==} + dotenv@16.6.1: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} @@ -3453,8 +3453,8 @@ packages: mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} - monaco-editor@0.55.1: - resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} + monaco-editor@0.56.0: + resolution: {integrity: sha512-sXboRm3BeBeLm938eaiyLMe0OxzfXIlZvbv4ir/jVgQy1zDhWjgmny0WoN45fuDKhCCQsYMbBJrv/A6jd8aCUg==} ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -5085,10 +5085,10 @@ snapshots: dependencies: state-local: 1.0.7 - '@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@monaco-editor/react@4.7.0(monaco-editor@0.56.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@monaco-editor/loader': 1.5.0 - monaco-editor: 0.55.1 + monaco-editor: 0.56.0 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) @@ -7052,11 +7052,11 @@ snapshots: '@babel/runtime': 7.29.7 csstype: 3.2.3 - dompurify@3.2.7: + dompurify@3.4.11: optionalDependencies: '@types/trusted-types': 2.0.7 - dompurify@3.4.11: + dompurify@3.4.8: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -8573,9 +8573,9 @@ snapshots: pkg-types: 1.3.1 ufo: 1.6.1 - monaco-editor@0.55.1: + monaco-editor@0.56.0: dependencies: - dompurify: 3.2.7 + dompurify: 3.4.8 marked: 14.0.0 ms@2.1.3: {} diff --git a/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.ts b/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.ts index 97ac79a8b36dd..1e00cb7274f9e 100644 --- a/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.ts +++ b/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.ts @@ -27,18 +27,13 @@ type MonacoEnvironment = { let configurationPromise: Promise | undefined; const loadMonacoModules = async () => { - // `editor.api` is API-only — the contribs/styles below must be side-effect imported - // to register their actions and render their glyphs. The CDN bundle pulled these in - // transitively; the local ESM build does not. + // The editor entry point is API-only; register the selected features and codicon styles + // explicitly to keep the local bundle small. const monacoApi = Promise.all([ - import("monaco-editor/esm/vs/editor/editor.api.js"), - import("monaco-editor/esm/vs/editor/contrib/folding/browser/folding.js"), - import("monaco-editor/esm/vs/editor/contrib/find/browser/findController.js"), - // monaco-editor 0.53 removed the `codiconStyles` side-effect module; import the two codicon - // stylesheets it used to pull in directly so folding/find glyphs still render. Both files - // ship in 0.52 and 0.55, so this resolves against the current pin and any newer bump. - import("monaco-editor/esm/vs/base/browser/ui/codicons/codicon/codicon.css"), - import("monaco-editor/esm/vs/base/browser/ui/codicons/codicon/codicon-modifiers.css"), + import("monaco-editor/editor"), + import("monaco-editor/features/folding/register"), + import("monaco-editor/features/find/register"), + import("monaco-editor/features/codicon/register"), ]).then(([api]) => api); // Resolve the bundled worker URLs (`?worker&url` runs the worker through Vite's worker @@ -52,17 +47,18 @@ const loadMonacoModules = async () => { // sidesteps the restriction (CORS still permits the inner import). In production the // worker is same-origin and the shim is harmless. const workerUrls = Promise.all([ - import("monaco-editor/esm/vs/editor/editor.worker.js?worker&url").then((module) => module.default), - import("monaco-editor/esm/vs/language/json/json.worker.js?worker&url").then((module) => module.default), + import("monaco-editor/editor/editor.worker.js?worker&url").then((module) => module.default), + import("monaco-editor/languages/features/json/json.worker.js?worker&url").then( + (module) => module.default, + ), ]); - // The JSON contribution registers its language as a side effect. Python is registered - // manually below from its grammar module instead of importing `python.contribution`, + // The JSON feature registers its language as a side effect. Python is registered + // manually below from its grammar module instead of importing its register module, // whose lazy tokens provider would overwrite our patched grammar on first use. - // The grammar module is a private monaco internal (verified against monaco-editor - // 0.52.2); the runtime guard below fails loudly if its export shape changes. - const jsonContribution = import("monaco-editor/esm/vs/language/json/monaco.contribution.js"); - const pythonGrammar = import("monaco-editor/esm/vs/basic-languages/python/python.js"); + // The runtime guard below fails loudly if the grammar export shape changes. + const jsonContribution = import("monaco-editor/languages/features/json/register"); + const pythonGrammar = import("monaco-editor/languages/definitions/python/python"); const [monaco, [editorWorkerUrl, jsonWorkerUrl], { conf: pythonConf, language: pythonLanguage }] = await Promise.all([monacoApi, workerUrls, pythonGrammar, jsonContribution]); diff --git a/airflow-core/src/airflow/ui/src/components/MonacoEditor/pythonFStrings.test.ts b/airflow-core/src/airflow/ui/src/components/MonacoEditor/pythonFStrings.test.ts index 1e69373e0282e..89cfb35d95954 100644 --- a/airflow-core/src/airflow/ui/src/components/MonacoEditor/pythonFStrings.test.ts +++ b/airflow-core/src/airflow/ui/src/components/MonacoEditor/pythonFStrings.test.ts @@ -127,8 +127,8 @@ describe("patchPythonFStrings (tokenized)", () => { let singleLineTokens: Array<{ offset: number; type: string }> = []; beforeAll(async () => { - const monaco = await import("monaco-editor/esm/vs/editor/editor.api.js"); - const { conf, language } = await import("monaco-editor/esm/vs/basic-languages/python/python.js"); + const monaco = await import("monaco-editor/editor"); + const { conf, language } = await import("monaco-editor/languages/definitions/python/python"); monaco.languages.register({ id: "python" }); monaco.languages.setLanguageConfiguration("python", conf); diff --git a/airflow-core/src/airflow/ui/src/vite-env.d.ts b/airflow-core/src/airflow/ui/src/vite-env.d.ts index e520ef77aa626..0efa1e9c8b0c0 100644 --- a/airflow-core/src/airflow/ui/src/vite-env.d.ts +++ b/airflow-core/src/airflow/ui/src/vite-env.d.ts @@ -25,14 +25,9 @@ interface ImportMeta { readonly env: ImportMetaEnv; } -// monaco-editor ships .d.ts only for `editor.api`; contribution side-effect imports have -// no typings of their own. -declare module "monaco-editor/esm/vs/editor/contrib/folding/browser/folding"; -declare module "monaco-editor/esm/vs/base/browser/ui/codicons/codiconStyles"; - -// The Python basic-language module exports its Monarch grammar (`conf` / `language`) +// The Python language definition exports its Monarch grammar (`conf` / `language`) // but ships no `.d.ts` of its own. -declare module "monaco-editor/esm/vs/basic-languages/python/python.js" { +declare module "monaco-editor/languages/definitions/python/python" { // `import(...)` type syntax is required here: a top-level `import type` would turn this // ambient declaration file into a module and break the `ImportMeta` augmentation above. /* eslint-disable @typescript-eslint/consistent-type-imports */