electron.vite.config.ts
Rama main · réplica de lectura del repositorio original.
import { execSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react-swc';
import { defineConfig } from 'electron-vite';
import { dependencyInventoryPlugin } from './scripts/electron-dependency-inventory.mjs';
import webPkg from './web/package.json' with { type: 'json' };
const __dirname = dirname(fileURLToPath(import.meta.url));
const ELECTRON_ESM_CJS_SHIM = `
// -- CommonJS Shims --
import __cjs_mod__ from 'node:module';
var __filename = import.meta.filename;
var __dirname = import.meta.dirname;
var require = __cjs_mod__.createRequire(import.meta.url);
`;
function tryGitSha(): string {
try {
return execSync('git rev-parse HEAD', { cwd: __dirname, encoding: 'utf8' }).trim();
} catch {
return 'unknown';
}
}
/** Packaged Electron loads the embedded gateway URL; renderer build is dev/preview-only. */
const skipRenderer = process.env['ELECTRON_VITE_SKIP_RENDERER'] === '1';
export default defineConfig({
main: {
plugins: [dependencyInventoryPlugin(__dirname), {
name: 'xopc:explicit-esm-shim',
configResolved(config) {
// The banner supplies the shim without scanning bundled strings as imports.
config.plugins = config.plugins.filter(plugin => plugin.name !== 'vite:esm-shim');
},
}],
build: {
// Packaged asar only ships minimal node_modules for the gateway subprocess (see
// scripts/electron-runtime-externals.mjs). Main-process deps (zod, pino, dotenv, …) must
// be bundled — electron-vite defaults to externalizeDeps=true which leaves bare imports.
externalizeDeps: false,
// Keep post-minification; electron-builder also compresses the packaged artifact.
minify: 'esbuild',
rollupOptions: {
// IMPORTANT: In the Electron main process, `electron` is a runtime-provided module.
// If Rollup resolves it to the npm package `electron`, the bundle will include
// `node_modules/electron/index.js`, which throws at runtime inside packaged apps.
// Do not mark `thread-stream` external: pnpm may not hoist it, so `require('thread-stream')`
// from `out/main/chunks/*` fails. Bundled `thread-stream` + `thread-stream-bundle-shim.ts`
// fixes pino transport worker path (see electron/thread-stream-bundle-shim.ts).
// `@vscode/ripgrep` resolves a platform optionalDep at import time; packaged apps use extraResources `bin/rg`.
// `node-pty` must resolve from its real package directory so it can load native binaries and spawn-helper.
external: ['electron', '@vscode/ripgrep', 'node-pty', '@trycua/cua-driver'],
input: {
index: resolve(__dirname, 'electron/index.ts'),
// Keep main's import.meta.dirname at out/main for preload and native helper paths.
main: resolve(__dirname, 'electron/main.ts'),
compatibility: resolve(__dirname, 'electron/gateway-compatibility.ts'),
},
// electron-vite 6 beta locates the last ESM import with a regex that can overrun into
// bundled source. Providing the shim explicitly bypasses that unsafe insertion path.
output: { banner: ELECTRON_ESM_CJS_SHIM },
},
},
resolve: {
alias: {
'@xopcai/xopc': resolve(__dirname, 'src'),
},
},
},
preload: {
plugins: [dependencyInventoryPlugin(__dirname), { name: 'computer-preview-document', async generateBundle() {
this.emitFile({ type: 'asset', fileName: 'computer-preview.html', source: readFileSync(resolve(__dirname, 'electron/computer/preview-worker.html'), 'utf8') });
} }],
build: {
minify: 'esbuild',
rollupOptions: {
// Same as main: keep `electron` as runtime-provided, not the npm package.
external: ['electron'],
input: {
index: resolve(__dirname, 'electron/preload.ts'),
'computer-preview': resolve(__dirname, 'electron/computer/preview-worker.ts'),
},
// Root package.json is `"type": "module"`, so electron-vite would default preload to ESM
// (`index.mjs`). Electron does not execute that preload as an ES module. Force CJS (`index.cjs`).
output: {
format: 'cjs',
},
},
},
},
...(skipRenderer
? {}
: {
renderer: {
root: resolve(__dirname, 'web'),
base: './',
define: {
__XOPC_WEB_VERSION__: JSON.stringify(webPkg.version),
__XOPC_WEB_COMMIT__: JSON.stringify(process.env['VITE_XOPC_WEB_COMMIT'] ?? tryGitSha()),
__XOPC_WEB_BUILD_TIME__: JSON.stringify(
process.env['VITE_XOPC_WEB_BUILD_TIME'] ?? new Date().toISOString(),
),
},
plugins: [react(), tailwindcss()],
resolve: {
alias: {
'@': resolve(__dirname, 'web/src'),
},
},
build: {
rollupOptions: {
input: resolve(__dirname, 'web/index.html'),
},
outDir: resolve(__dirname, 'out/renderer'),
emptyOutDir: true,
},
server: {
port: 5173,
// Same-origin API calls use `window.location.origin` (this dev server). Mirror `web/vite.config.ts`
// so `/api/*` reaches the xopc gateway — required for Electron dev (renderer loads from :5173).
proxy: {
'/api': {
target: 'http://localhost:18790',
changeOrigin: true,
ws: true,
},
'/health': {
target: 'http://localhost:18790',
changeOrigin: true,
},
'/status': {
target: 'http://localhost:18790',
changeOrigin: true,
},
'/favicon.ico': {
target: 'http://localhost:18790',
changeOrigin: true,
},
},
},
},
}),
});