From 4f18a50382bbeae3f5c50a34968be5cf3048810f Mon Sep 17 00:00:00 2001 From: younggglcy Date: Fri, 15 May 2026 17:02:10 +0800 Subject: [PATCH] feat: support electron 42 Add Electron 42 to the node/chrome build target tables and lazily download the electron binary when path.txt is missing on Electron 42+, since the upstream package no longer downloads itself via postinstall (supply-chain hardening). This mirrors the behavior of `npx electron`, so users do not need to add a manual `install-electron` postinstall script. close #904 --- README.md | 2 ++ src/electron.ts | 33 ++++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a623e7e..7e5b5ff 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ npm i electron-vite -D ``` +> **Note:** Starting with [Electron 42](https://www.electronjs.org/blog/electron-42-0), the `electron` package no longer downloads its binary via `postinstall`. You do not need to add an `install-electron` postinstall script — `electron-vite` will download the binary on demand the first time you run `dev`, `build`, or `preview`, mirroring the behavior of `npx electron`. + ### Development & Build In a project where `electron-vite` is installed, you can use `electron-vite` binary directly with `npx electron-vite` or add the npm scripts to your `package.json` file like this: diff --git a/src/electron.ts b/src/electron.ts index 5704504..2ff56b2 100644 --- a/src/electron.ts +++ b/src/electron.ts @@ -1,7 +1,9 @@ import path from 'node:path' import fs from 'node:fs' import { createRequire } from 'node:module' -import { type ChildProcess, spawn } from 'node:child_process' +import { type ChildProcess, spawn, spawnSync } from 'node:child_process' +import colors from 'picocolors' +import { createLogger } from 'vite' import { loadPackageData } from './utils' const _require = createRequire(import.meta.url) @@ -46,20 +48,39 @@ export function supportImportMetaPaths(): boolean { return parseInt(majorVer) >= 30 } +function installElectronBinary(electronModulePath: string): void { + const installScript = path.join(electronModulePath, 'install.js') + if (!fs.existsSync(installScript)) { + throw new Error(`electron install script not found at ${installScript}, please reinstall the electron package`) + } + createLogger().info(colors.green('Electron binary not found, installing...')) + const result = spawnSync(process.execPath, [installScript], { + stdio: 'inherit', + cwd: electronModulePath + }) + if (result.status !== 0) { + throw new Error('Failed to install electron binary') + } +} + export function getElectronPath(): string { let electronExecPath = process.env.ELECTRON_EXEC_PATH || '' if (!electronExecPath) { const electronModulePath = path.dirname(_require.resolve('electron')) const pathFile = path.join(electronModulePath, 'path.txt') - let executablePath - if (fs.existsSync(pathFile)) { - executablePath = fs.readFileSync(pathFile, 'utf-8') + const readPathFile = (): string | undefined => + fs.existsSync(pathFile) ? fs.readFileSync(pathFile, 'utf-8') : undefined + let executablePath = readPathFile() + if (!executablePath && parseInt(getElectronMajorVer()) >= 42) { + // Electron 42+ no longer downloads its binary via postinstall (supply-chain hardening). + installElectronBinary(electronModulePath) + executablePath = readPathFile() } if (executablePath) { electronExecPath = path.join(electronModulePath, 'dist', executablePath) process.env.ELECTRON_EXEC_PATH = electronExecPath } else { - throw new Error('Electron uninstall') + throw new Error('Electron is not installed') } } return electronExecPath @@ -69,6 +90,7 @@ export function getElectronNodeTarget(): string { const electronVer = getElectronMajorVer() const nodeVer = { + '42': '24.15', '41': '24.14', '40': '24.14', '39': '22.20', @@ -102,6 +124,7 @@ export function getElectronChromeTarget(): string { const electronVer = getElectronMajorVer() const chromeVer = { + '42': '148', '41': '146', '40': '144', '39': '142',