diff --git a/packages/electron-app/electron.vite.config.ts b/packages/electron-app/electron.vite.config.ts index 1161176a..105b2d3f 100644 --- a/packages/electron-app/electron.vite.config.ts +++ b/packages/electron-app/electron.vite.config.ts @@ -1,6 +1,7 @@ import { defineConfig, externalizeDepsPlugin } from "electron-vite" import solid from "vite-plugin-solid" import { resolve } from "path" +import fs from "fs" const uiRoot = resolve(__dirname, "../ui") const uiSrc = resolve(uiRoot, "src") @@ -8,6 +9,92 @@ const uiRendererRoot = resolve(uiRoot, "src/renderer") const uiRendererEntry = resolve(uiRendererRoot, "index.html") const uiRendererLoadingEntry = resolve(uiRendererRoot, "loading.html") +function copyMonacoPublicAssets(opts: { warn: (message: string) => void }) { + const publicDir = resolve(uiRendererRoot, "public") + const destRoot = resolve(publicDir, "monaco/vs") + + const candidates = [ + // Workspace root hoisted deps. + resolve(__dirname, "../../node_modules/monaco-editor/min/vs"), + // UI package local deps. + resolve(uiRoot, "node_modules/monaco-editor/min/vs"), + ] + const sourceRoot = candidates.find((p) => fs.existsSync(resolve(p, "loader.js"))) + if (!sourceRoot) { + opts.warn("Monaco source directory not found; skipping copy") + return + } + + const copyRecursive = (src: string, dest: string) => { + const stat = fs.statSync(src) + if (stat.isDirectory()) { + fs.mkdirSync(dest, { recursive: true }) + for (const entry of fs.readdirSync(src)) { + copyRecursive(resolve(src, entry), resolve(dest, entry)) + } + return + } + fs.copyFileSync(src, dest) + } + + // Keep the working tree clean; these assets are generated. + try { + fs.rmSync(destRoot, { recursive: true, force: true }) + } catch { + // ignore + } + fs.mkdirSync(destRoot, { recursive: true }) + + // Copy core Monaco runtime. + for (const dir of ["base", "editor", "platform"] as const) { + const src = resolve(sourceRoot, dir) + if (fs.existsSync(src)) { + copyRecursive(src, resolve(destRoot, dir)) + } + } + + // loader.js is required. + copyRecursive(resolve(sourceRoot, "loader.js"), resolve(destRoot, "loader.js")) + + // Copy baseline rich language packages + workers. + for (const lang of ["typescript", "html", "json", "css"] as const) { + const src = resolve(sourceRoot, "language", lang) + if (fs.existsSync(src)) { + copyRecursive(src, resolve(destRoot, "language", lang)) + } + } + + // Copy baseline basic tokenizers. + for (const lang of ["python", "markdown", "cpp", "kotlin"] as const) { + const src = resolve(sourceRoot, "basic-languages", lang) + if (fs.existsSync(src)) { + copyRecursive(src, resolve(destRoot, "basic-languages", lang)) + } + } + + // Copy monaco.contribution.js entrypoints (needed by some loads). + const monacoContribution = resolve(sourceRoot, "basic-languages", "monaco.contribution.js") + if (fs.existsSync(monacoContribution)) { + copyRecursive(monacoContribution, resolve(destRoot, "basic-languages", "monaco.contribution.js")) + } + const underscoreContribution = resolve(sourceRoot, "basic-languages", "_.contribution.js") + if (fs.existsSync(underscoreContribution)) { + copyRecursive(underscoreContribution, resolve(destRoot, "basic-languages", "_.contribution.js")) + } +} + +function prepareMonacoPublicAssets() { + return { + name: "prepare-monaco-public-assets", + configureServer(server: any) { + copyMonacoPublicAssets({ warn: (msg) => server.config.logger.warn(msg) }) + }, + buildStart(this: any) { + copyMonacoPublicAssets({ warn: (msg) => this.warn(msg) }) + }, + } +} + export default defineConfig({ main: { plugins: [externalizeDepsPlugin()], @@ -40,7 +127,7 @@ export default defineConfig({ }, renderer: { root: uiRendererRoot, - plugins: [solid()], + plugins: [solid(), prepareMonacoPublicAssets()], css: { postcss: resolve(uiRoot, "postcss.config.js"), },