This is an automated email from the ASF dual-hosted git repository.

vatsrahul1001 pushed a commit to branch v3-2-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-2-test by this push:
     new af9f681428e [v3-2-test] UI: Load Monaco workers via a same-origin Blob 
shim (#67352) (#67469)
af9f681428e is described below

commit af9f681428ea19c271fb440535d50076cb127484
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Mon May 25 19:06:40 2026 +0530

    [v3-2-test] UI: Load Monaco workers via a same-origin Blob shim (#67352) 
(#67469)
    
    In dev mode the SPA shell is served by the airflow api-server while
    Vite serves assets on a different origin. Module workers cannot be
    constructed cross-origin even when CORS allows the fetch — Chrome
    refuses with 'Script at <vite url> cannot be accessed from origin
    <api-server>'. Monaco then falls back to 'main-thread workers', whose
    `$loadForeignModule` path tries to resolve module IDs through the
    non-existent AMD `require.toUrl`, flooding the console with
    `Cannot read properties of undefined (reading 'toUrl')` errors.
    
    Swap the `?worker` constructor imports for `?url` imports and
    construct workers from a same-origin Blob shim that simply re-imports
    the resolved URL. The Blob lives on the page origin so the Worker
    constructor accepts it, and the inner cross-origin `import` is
    permitted by Vite's CORS response.
    
    Closes #67342.
    (cherry picked from commit 68629ffd9fc63978e0d39dde16cb4f3890d06af3)
    
    Co-authored-by: Pierre Jeambrun <[email protected]>
    Co-authored-by: Rahul Vats <[email protected]>
---
 .../src/components/MonacoEditor/configureMonaco.ts | 30 ++++++++++++++++------
 1 file changed, 22 insertions(+), 8 deletions(-)

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 de8b8b0ebc6..2ad53eb09a6 100644
--- a/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.ts
+++ b/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.ts
@@ -35,9 +35,15 @@ const loadMonacoModules = async () => {
     import("monaco-editor/esm/vs/base/browser/ui/codicons/codiconStyles"),
   ]).then(([api]) => api);
 
-  const workerConstructors = Promise.all([
-    import("monaco-editor/esm/vs/editor/editor.worker?worker").then((module) 
=> module.default),
-    
import("monaco-editor/esm/vs/language/json/json.worker?worker").then((module) 
=> module.default),
+  // Resolve the workers as plain URLs (not Vite `?worker` constructors). In 
dev mode
+  // the SPA shell is served by the airflow api-server while Vite serves 
assets on a
+  // different origin, and `new Worker(crossOriginUrl, { type: "module" })` is 
rejected
+  // by the browser. Wrapping the cross-origin URL in a same-origin Blob shim 
that just
+  // re-imports it 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?url").then((module) 
=> module.default),
+    
import("monaco-editor/esm/vs/language/json/json.worker.js?url").then((module) 
=> module.default),
   ]);
 
   const languageContributions = Promise.all([
@@ -45,13 +51,21 @@ const loadMonacoModules = async () => {
     import("monaco-editor/esm/vs/language/json/monaco.contribution"),
   ]);
 
-  const [monaco, [editorWorker, jsonWorker]] = await Promise.all([
+  const [monaco, [editorWorkerUrl, jsonWorkerUrl]] = await Promise.all([
     monacoApi,
-    workerConstructors,
+    workerUrls,
     languageContributions,
   ]);
 
-  return { editorWorker, jsonWorker, monaco };
+  return { editorWorkerUrl, jsonWorkerUrl, monaco };
+};
+
+const createWorkerFromUrl = (workerUrl: string): Worker => {
+  const absoluteUrl = new URL(workerUrl, import.meta.url).href;
+  const shim = `import ${JSON.stringify(absoluteUrl)};`;
+  const blobUrl = URL.createObjectURL(new Blob([shim], { type: 
"text/javascript" }));
+
+  return new Worker(blobUrl, { type: "module" });
 };
 
 export const configureMonaco = () => {
@@ -60,10 +74,10 @@ export const configureMonaco = () => {
   }
 
   configurationPromise = loadMonacoModules()
-    .then(({ editorWorker, jsonWorker, monaco }) => {
+    .then(({ editorWorkerUrl, jsonWorkerUrl, monaco }) => {
       Reflect.set(globalThis, "MonacoEnvironment", {
         getWorker: (_moduleId: string, label: string) =>
-          label === "json" ? new jsonWorker() : new editorWorker(),
+          createWorkerFromUrl(label === "json" ? jsonWorkerUrl : 
editorWorkerUrl),
       } satisfies MonacoEnvironment);
 
       loader.config({ monaco });

Reply via email to