/** * Релиз без @electron/rebuild: classic-level (N-API prebuilds) и sharp (@img бинарники). * См. package.json → build.npmRebuild = false. */ import { execFileSync } from 'node:child_process'; import fs from 'node:fs'; import path from 'node:path'; /** @typedef {'win' | 'mac' | 'linux'} ReleaseNativeProfile */ /** Папки prebuilds/classic-level из npm-пакета classic-level. */ export const CLASSIC_LEVEL_PREBUILD_KEYS = { win: ['win32-x64'], mac: ['darwin-x64+arm64'], linux: ['linux-x64', 'linux-arm64'], }; export const MAC_SHARP_IMG_PACKAGES = [ '@img/sharp-darwin-arm64', '@img/sharp-libvips-darwin-arm64', '@img/sharp-darwin-x64', '@img/sharp-libvips-darwin-x64', ]; /** AppImage x64/arm64 — glibc, не musl. */ export const LINUX_SHARP_IMG_PACKAGES = [ '@img/sharp-linux-x64', '@img/sharp-libvips-linux-x64', '@img/sharp-linux-arm64', '@img/sharp-libvips-linux-arm64', ]; export const WIN_SHARP_IMG_PACKAGES = ['@img/sharp-win32-x64']; /** * @param {string} root * @param {string[]} packageNames * @returns {string[]} entries like `@img/sharp-darwin-x64@0.34.5` */ export function sharpImgPackagesToInstall(root, packageNames) { const sharpPkgPath = path.join(root, 'node_modules', 'sharp', 'package.json'); if (!fs.existsSync(sharpPkgPath)) { throw new Error('[release-native-prep] sharp is not installed — run npm ci first'); } const sharpPkg = JSON.parse(fs.readFileSync(sharpPkgPath, 'utf8')); const versions = sharpPkg.optionalDependencies ?? {}; const missing = []; for (const name of packageNames) { const version = versions[name]; if (!version) { throw new Error(`[release-native-prep] sharp optionalDependency missing: ${name}`); } if (!fs.existsSync(path.join(root, 'node_modules', name))) { missing.push(`${name}@${version}`); } } return missing; } /** * @param {string} root * @param {string} prebuildKey */ export function assertClassicLevelPrebuild(root, prebuildKey) { const dir = path.join(root, 'node_modules', 'classic-level', 'prebuilds', prebuildKey); if (!fs.existsSync(dir)) { throw new Error( `[release-native-prep] classic-level prebuild missing: ${prebuildKey} (run npm ci)`, ); } const hasNode = fs.readdirSync(dir).some((f) => f.endsWith('.node')); if (!hasNode) { throw new Error( `[release-native-prep] classic-level prebuild dir empty: ${prebuildKey}`, ); } } /** * @param {string} root * @param {ReleaseNativeProfile} profile * @param {{ runInstall?: boolean }} [opts] */ export function ensureReleaseNativeDeps(root, profile, opts = {}) { const { runInstall = true } = opts; const classicKeys = CLASSIC_LEVEL_PREBUILD_KEYS[profile]; for (const key of classicKeys) { assertClassicLevelPrebuild(root, key); } let sharpPackages; if (profile === 'mac') sharpPackages = MAC_SHARP_IMG_PACKAGES; else if (profile === 'linux') sharpPackages = LINUX_SHARP_IMG_PACKAGES; else sharpPackages = WIN_SHARP_IMG_PACKAGES; const toInstall = sharpImgPackagesToInstall(root, sharpPackages); if (toInstall.length === 0) { console.log(`[release-native-prep] ${profile}: native prebuilds OK`); return; } console.log(`[release-native-prep] ${profile}: installing`, toInstall.join(', ')); if (!runInstall) return; execFileSync('npm', ['install', '--no-save', '--force', ...toInstall], { cwd: root, stdio: 'inherit', shell: process.platform === 'win32', }); }