diff --git a/apps/desktop/.gitignore b/apps/desktop/.gitignore index 43ffb2d1436..4e5d8ab2674 100644 --- a/apps/desktop/.gitignore +++ b/apps/desktop/.gitignore @@ -9,6 +9,7 @@ # production /build /dist +/.native-modules # misc .DS_Store diff --git a/apps/desktop/electron-builder.ts b/apps/desktop/electron-builder.ts index 033ccef42c4..d37e722218b 100644 --- a/apps/desktop/electron-builder.ts +++ b/apps/desktop/electron-builder.ts @@ -38,8 +38,14 @@ const config: Configuration = { to: "resources", filter: ["**/*"], }, - // Only include node-pty (native module that can't be bundled) - "node_modules/node-pty/**/*", + // Native module that can't be bundled by Vite. + // The copy:native-modules script replaces symlinks with real files + // before building (required for Bun 1.3+ isolated installs). + { + from: "node_modules/node-pty", + to: "node_modules/node-pty", + filter: ["**/*"], + }, "!**/.DS_Store", ], diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 356161d0812..b9924261735 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -18,8 +18,10 @@ "predev": "bun run clean:dev", "dev": "cross-env NODE_ENV=development electron-vite dev --watch", "compile:app": "electron-vite build", - "prebuild": "bun run clean:dev && bun run compile:app", + "copy:native-modules": "bun run scripts/copy-native-modules.ts", + "prebuild": "bun run clean:dev && bun run compile:app && bun run copy:native-modules", "build": "electron-builder", + "prepackage": "bun run copy:native-modules", "package": "electron-builder --config electron-builder.ts", "install:deps": "electron-builder install-app-deps", "make:release": "tsx ./src/lib/electron-app/release/modules/release.ts", diff --git a/apps/desktop/scripts/copy-native-modules.ts b/apps/desktop/scripts/copy-native-modules.ts new file mode 100644 index 00000000000..531e6fc3d7b --- /dev/null +++ b/apps/desktop/scripts/copy-native-modules.ts @@ -0,0 +1,57 @@ +/** + * Prepare native modules for electron-builder. + * + * With Bun 1.3+ isolated installs, node_modules contains symlinks to packages + * stored in node_modules/.bun/. electron-builder cannot follow these symlinks + * when creating asar archives. + * + * This script: + * 1. Detects if native modules are symlinks + * 2. Replaces symlinks with actual file copies + * 3. electron-builder can then properly package and unpack them + * + * This is safe because bun install will recreate the symlinks on next install. + */ + +import { cpSync, existsSync, lstatSync, realpathSync, rmSync } from "node:fs"; +import { dirname, join } from "node:path"; + +const NATIVE_MODULES = ["node-pty"] as const; + +function prepareNativeModules() { + console.log("Preparing native modules for electron-builder..."); + + const nodeModulesDir = join(dirname(import.meta.dirname), "node_modules"); + + for (const moduleName of NATIVE_MODULES) { + const modulePath = join(nodeModulesDir, moduleName); + + if (!existsSync(modulePath)) { + console.error(` [ERROR] ${moduleName} not found at ${modulePath}`); + process.exit(1); + } + + const stats = lstatSync(modulePath); + + if (stats.isSymbolicLink()) { + // Resolve symlink to get real path + const realPath = realpathSync(modulePath); + console.log(` ${moduleName}: symlink -> replacing with real files`); + console.log(` Real path: ${realPath}`); + + // Remove the symlink + rmSync(modulePath); + + // Copy the actual files + cpSync(realPath, modulePath, { recursive: true }); + + console.log(` Copied to: ${modulePath}`); + } else { + console.log(` ${moduleName}: already real directory (not a symlink)`); + } + } + + console.log("Done!"); +} + +prepareNativeModules();