fix(E3): bundle Monaco workers locally

This commit is contained in:
Saravana Achu Mac 2026-05-04 18:10:18 -07:00
parent a09276a3b5
commit e8b3c9cf69
7 changed files with 86 additions and 0 deletions

3
pnpm-lock.yaml generated
View File

@ -266,6 +266,9 @@ importers:
lucide-react:
specifier: ^0.562.0
version: 0.562.0(react@19.2.4)
monaco-editor:
specifier: ^0.55.1
version: 0.55.1
react:
specifier: ^19.2.0
version: 19.2.4

View File

@ -28,6 +28,7 @@
"@dnd-kit/utilities": "^3.2.2",
"@monaco-editor/react": "^4.7.0",
"lucide-react": "^0.562.0",
"monaco-editor": "^0.55.1",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-router-dom": "^7.14.2",

View File

@ -9,6 +9,7 @@ const { createTradeProfileMock } = vi.hoisted(() => ({
}));
vi.mock('@monaco-editor/react', () => ({
loader: { config: vi.fn() },
default: ({ value, onChange }: any) => (
<textarea
aria-label="strategy code"
@ -18,6 +19,30 @@ vi.mock('@monaco-editor/react', () => ({
),
}));
vi.mock('monaco-editor', () => ({
editor: {},
}));
vi.mock('monaco-editor/esm/vs/editor/editor.worker?worker', () => ({
default: class MockEditorWorker {},
}));
vi.mock('monaco-editor/esm/vs/language/json/json.worker?worker', () => ({
default: class MockJsonWorker {},
}));
vi.mock('monaco-editor/esm/vs/language/css/css.worker?worker', () => ({
default: class MockCssWorker {},
}));
vi.mock('monaco-editor/esm/vs/language/html/html.worker?worker', () => ({
default: class MockHtmlWorker {},
}));
vi.mock('monaco-editor/esm/vs/language/typescript/ts.worker?worker', () => ({
default: class MockTsWorker {},
}));
vi.mock('../../lib/profileApi', () => ({
createTradeProfile: (...args: any[]) => createTradeProfileMock(...args),
}));

View File

@ -6,6 +6,7 @@ import { Suspense, lazy, useCallback, useEffect, useRef, useState } from 'react'
import { Play, Save, Copy, RotateCcw } from 'lucide-react';
import { getPlatformAccessToken } from '../../lib/authSession';
import { createTradeProfile } from '../../lib/profileApi';
import '../../lib/monacoLocalWorkers';
import { tradingRuntime } from '../../lib/runtime';
import { createRequestId } from '../../../../shared/request-id.js';

View File

@ -0,0 +1,36 @@
import { loader } from '@monaco-editor/react';
import * as monaco from 'monaco-editor';
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
type MonacoWorkerConstructor = new () => Worker;
const workerByLabel: Record<string, MonacoWorkerConstructor> = {
css: cssWorker,
handlebars: htmlWorker,
html: htmlWorker,
javascript: tsWorker,
json: jsonWorker,
less: cssWorker,
razor: htmlWorker,
scss: cssWorker,
typescript: tsWorker,
};
const monacoGlobal = globalThis as typeof globalThis & {
MonacoEnvironment?: {
getWorker: (_moduleId: string, label: string) => Worker;
};
};
monacoGlobal.MonacoEnvironment = {
getWorker(_moduleId: string, label: string) {
const WorkerConstructor = workerByLabel[label] ?? editorWorker;
return new WorkerConstructor();
},
};
loader.config({ monaco });

View File

@ -15,6 +15,15 @@
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"monaco-editor": [
"../node_modules/.pnpm/monaco-editor@0.55.1/node_modules/monaco-editor/esm/vs/editor/editor.api"
],
"monaco-editor/*": [
"../node_modules/.pnpm/monaco-editor@0.55.1/node_modules/monaco-editor/*"
]
},
/* Linting */
"strict": true,

View File

@ -4,6 +4,11 @@ import tailwindcss from '@tailwindcss/vite'
import path from 'node:path'
import fs from 'node:fs'
const monacoEditorPath = path.resolve(
__dirname,
'../node_modules/.pnpm/monaco-editor@0.55.1/node_modules/monaco-editor',
);
// Resolve a @bytelyst/* package: prefer web/node_modules, fall back to vendor/
function bytelystAlias(pkg: string): string {
const nmPath = path.resolve(__dirname, 'node_modules/@bytelyst', pkg);
@ -29,6 +34,12 @@ export default defineConfig({
// Vendor packages that live only in vendor/ (not in web/node_modules/)
{ find: '@bytelyst/api-client', replacement: bytelystAlias('api-client') },
{ find: '@bytelyst/errors', replacement: bytelystAlias('errors') },
// Monaco is an explicit web dependency, but this workspace often runs
// against pnpm's root store without a web/node_modules symlink when the
// private mobile registry is unavailable. Keep local worker imports
// resolvable for Vite in that partially installed state.
{ find: /^monaco-editor$/, replacement: monacoEditorPath },
{ find: /^monaco-editor\/(.+)/, replacement: `${monacoEditorPath}/$1` },
// General catch-all: every other @bytelyst/* → web/node_modules
{
find: /^@bytelyst\/(.+)/,