From f52ca059a1bb21841cef79d52d3ddae66f0256ef Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Tue, 4 Aug 2026 22:49:50 +0100 Subject: [PATCH] Enhance CEF bundling support and update build scripts - Introduced `bundleCEF` configuration to control CEF bundling in the build process. - Updated `Jenkinsfile` to support separate builds for CEF and native applications on Windows and macOS. - Modified `build-macos.mjs` and `finalize-desktop-artifacts.mjs` to incorporate CEF bundling logic and adjust artifact naming accordingly. - Enhanced logging to indicate CEF bundling status during builds, improving transparency in the build process. --- Jenkinsfile | 34 +++++++++++++++----------- electrobun.config.ts | 11 +++++++-- scripts/build-macos.mjs | 8 +++--- scripts/finalize-desktop-artifacts.mjs | 32 ++++++++++++------------ scripts/release-artifact-utils.mjs | 15 ++++++++++-- scripts/run-electrobun-build.mjs | 5 ++-- 6 files changed, 65 insertions(+), 40 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 3dc8b56..5fd1dd0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -105,26 +105,27 @@ def prepareMacBuildWorkspace() { } } -def buildOnLabel(label, buildCommand) { +def buildOnLabel(label, buildCommand, bundleCef = false) { + def cefLabel = bundleCef ? 'cef' : 'native' return { node(label) { try { - stage("Checkout (${label})") { + stage("Checkout (${label}/${cefLabel})") { checkout scm } withBun { - stage("Check Bun (${label})") { + stage("Check Bun (${label}/${cefLabel})") { checkBun() } if (label.startsWith('macos')) { - stage("Prepare macOS workspace (${label})") { + stage("Prepare macOS workspace (${label}/${cefLabel})") { prepareMacBuildWorkspace() } } - stage("Install Dependencies (${label})") { + stage("Install Dependencies (${label}/${cefLabel})") { if (isUnix()) { sh 'bun install --frozen-lockfile' } else { @@ -132,16 +133,18 @@ def buildOnLabel(label, buildCommand) { } } - stage("Write Build Metadata (${label})") { + stage("Write Build Metadata (${label}/${cefLabel})") { writeBuildMetadata() } - stage("Build (${label})") { - runBuild(buildCommand) + stage("Build (${label}/${cefLabel})") { + withEnv(["ELECTROBUN_BUNDLE_CEF=${bundleCef ? 'true' : 'false'}"]) { + runBuild(buildCommand) + } } } - stage("Archive Artifacts (${label})") { + stage("Archive Artifacts (${label}/${cefLabel})") { archiveArtifacts artifacts: 'app_dist/farmcontrol-*', fingerprint: true } } finally { @@ -151,8 +154,8 @@ def buildOnLabel(label, buildCommand) { } } -def buildMacOnLabel(label, targetArch) { - return buildOnLabel(label, "ELECTROBUN_TARGET_ARCH=${targetArch} bun run build:app:mac") +def buildMacOnLabel(label, targetArch, bundleCef = false) { + return buildOnLabel(label, "ELECTROBUN_TARGET_ARCH=${targetArch} bun run build:app:mac", bundleCef) } def setBuildNameFromPackageVersion() { @@ -177,9 +180,12 @@ try { setBuildNameFromPackageVersion() parallel( - 'Windows Build': buildOnLabel('windows', 'bun run build:app'), - 'MacOS x64 Build': buildMacOnLabel('macos', 'x64'), - 'MacOS arm64 Build': buildMacOnLabel('macos', 'arm64'), + 'Windows Build': buildOnLabel('windows', 'bun run build:app', false), + 'Windows CEF Build': buildOnLabel('windows', 'bun run build:app', true), + 'MacOS x64 Build': buildMacOnLabel('macos', 'x64', false), + 'MacOS x64 CEF Build': buildMacOnLabel('macos', 'x64', true), + 'MacOS arm64 Build': buildMacOnLabel('macos', 'arm64', false), + 'MacOS arm64 CEF Build': buildMacOnLabel('macos', 'arm64', true), 'Ubuntu Deploy': { deploy() } ) diff --git a/electrobun.config.ts b/electrobun.config.ts index 410515d..6ab2c6c 100644 --- a/electrobun.config.ts +++ b/electrobun.config.ts @@ -5,6 +5,10 @@ const packageJson = JSON.parse(readFileSync("./package.json", "utf8")); const buildEnv = process.env.ELECTROBUN_BUILD_ENV || "dev"; const isStable = buildEnv === "stable"; const canCodesign = Boolean(process.env.ELECTROBUN_DEVELOPER_ID); +const bundleCEF = ["1", "true", "yes"].includes( + String(process.env.ELECTROBUN_BUNDLE_CEF || "").toLowerCase(), +); +const defaultRenderer = bundleCEF ? "cef" : "native"; const targetOs = process.env.ELECTROBUN_OS || (process.platform === "darwin" @@ -47,7 +51,8 @@ export default { watch: ["scripts", "src"], watchIgnore: ["dist/**", "build/**", "app_dist/**"], mac: { - bundleCEF: false, + bundleCEF, + defaultRenderer, icons: "assets/icon.iconset", createDmg: false, codesign: isStable && canCodesign, @@ -55,10 +60,12 @@ export default { }, linux: { bundleCEF: false, + defaultRenderer: "native", icon: "assets/icon.png", }, win: { - bundleCEF: false, + bundleCEF, + defaultRenderer, icon: "assets/icon.iconset/icon_256x256.png", }, }, diff --git a/scripts/build-macos.mjs b/scripts/build-macos.mjs index e3c77e2..bacf15a 100644 --- a/scripts/build-macos.mjs +++ b/scripts/build-macos.mjs @@ -1,13 +1,14 @@ import { spawnSync } from "node:child_process"; import { fileURLToPath } from "node:url"; import path from "node:path"; -import { getReleaseArch } from "./release-artifact-utils.mjs"; +import { getReleaseArch, isBundleCefEnabled } from "./release-artifact-utils.mjs"; const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const hostArch = getReleaseArch(process.arch); const targetArchs = process.env.ELECTROBUN_TARGET_ARCH ? [getReleaseArch(process.env.ELECTROBUN_TARGET_ARCH)] : ["arm64", "x64"]; +const bundleCef = isBundleCefEnabled(); function canRunUnderArch(archFlag) { const result = spawnSync("arch", [archFlag, "true"], { @@ -72,6 +73,7 @@ const orderedTargets = [...targetArchs].sort((a, b) => { }); console.log(`Host architecture: ${hostArch}`); +console.log(`CEF bundling: ${bundleCef ? "enabled" : "disabled"}`); console.log(`Build order: ${orderedTargets.join(", ")}`); let builtCount = 0; @@ -85,9 +87,9 @@ for (const targetArch of orderedTargets) { continue; } - console.log(`\n=== Building macOS ${targetArch} (host ${hostArch}) ===`); + console.log(`\n=== Building macOS ${targetArch} (host ${hostArch}, cef=${bundleCef}) ===`); console.log( - `ELECTROBUN_BUILD_ENV=stable ELECTROBUN_OS=macos ELECTROBUN_ARCH=${targetArch}\n`, + `ELECTROBUN_BUILD_ENV=stable ELECTROBUN_OS=macos ELECTROBUN_ARCH=${targetArch} ELECTROBUN_BUNDLE_CEF=${bundleCef}\n`, ); run(invocation.command, invocation.args, { env: invocation.env }); diff --git a/scripts/finalize-desktop-artifacts.mjs b/scripts/finalize-desktop-artifacts.mjs index d33ee6c..769c85e 100644 --- a/scripts/finalize-desktop-artifacts.mjs +++ b/scripts/finalize-desktop-artifacts.mjs @@ -13,7 +13,8 @@ import { fileURLToPath } from 'node:url' import { getReleaseArch, getReleaseArtifactName, - getReleaseVersion + getReleaseVersion, + isBundleCefEnabled } from './release-artifact-utils.mjs' import { cleanExpandedWindowsApp, @@ -40,12 +41,17 @@ const targetOs = const buildArch = getReleaseArch(process.env.ELECTROBUN_ARCH || process.arch) const version = process.env.ELECTROBUN_APP_VERSION || getReleaseVersion(packageJson) +const bundleCef = isBundleCefEnabled() const artifactDir = process.env.ELECTROBUN_ARTIFACT_DIR || path.join(rootDir, 'app_dist') const identifier = process.env.ELECTROBUN_APP_IDENTIFIER || 'com.tombutcher.farmcontrol' const artifactPrefix = `farmcontrol-${version}-` +function artifactName(arch, ext) { + return getReleaseArtifactName(version, arch, ext, { cef: bundleCef }) +} + function getBuildRoot() { const electrobunBuildDir = process.env.ELECTROBUN_BUILD_DIR if (!electrobunBuildDir) { @@ -159,10 +165,7 @@ function publishArtifact(sourcePath, arch, ext) { } mkdirSync(artifactDir, { recursive: true }) - const destination = path.join( - artifactDir, - getReleaseArtifactName(version, arch, ext) - ) + const destination = path.join(artifactDir, artifactName(arch, ext)) cpSync(sourcePath, destination) console.log(`Published ${destination}`) return destination @@ -408,10 +411,7 @@ async function buildMacDmg(appBundlePath, arch) { ) } - const dmgPath = path.join( - artifactDir, - getReleaseArtifactName(version, arch, 'dmg') - ) + const dmgPath = path.join(artifactDir, artifactName(arch, 'dmg')) mkdirSync(artifactDir, { recursive: true }) @@ -463,10 +463,7 @@ function cleanMacBuildDir(arch) { } function buildMacPkg(appBundlePath, arch) { - const pkgPath = path.join( - artifactDir, - getReleaseArtifactName(version, arch, 'pkg') - ) + const pkgPath = path.join(artifactDir, artifactName(arch, 'pkg')) const result = spawnSync( 'pkgbuild', @@ -512,10 +509,7 @@ function cleanWinBuildDir(arch) { function buildWindowsNsis(appDir, arch) { const scriptPath = path.join(rootDir, 'scripts/build-windows-nsis.ps1') - const exePath = path.join( - artifactDir, - getReleaseArtifactName(version, arch, 'exe') - ) + const exePath = path.join(artifactDir, artifactName(arch, 'exe')) const buildInfoPath = path.join(rootDir, 'src/buildInfo.json') const buildInfo = existsSync(buildInfoPath) ? JSON.parse(readFileSync(buildInfoPath, 'utf8')) @@ -579,6 +573,10 @@ if (buildEnv === 'dev') { } async function main() { + console.log( + `finalize-desktop-artifacts: os=${targetOs} arch=${buildArch} cef=${bundleCef} version=${version}` + ) + if (targetOs === 'macos') { const appBundle = findMacAppBundle(buildArch) diff --git a/scripts/release-artifact-utils.mjs b/scripts/release-artifact-utils.mjs index 1efaadb..83912ed 100644 --- a/scripts/release-artifact-utils.mjs +++ b/scripts/release-artifact-utils.mjs @@ -12,6 +12,17 @@ export function getReleaseArch(platformArch = process.arch) { return platformArch; } -export function getReleaseArtifactName(version, arch, ext) { - return `farmcontrol-${version}-${arch}.${ext}`; +export function isBundleCefEnabled( + value = process.env.ELECTROBUN_BUNDLE_CEF, +) { + return ["1", "true", "yes"].includes(String(value || "").toLowerCase()); +} + +export function getReleaseArtifactName(version, arch, ext, options = {}) { + const cef = + typeof options === "boolean" + ? options + : Boolean(options.cef ?? isBundleCefEnabled()); + const cefSuffix = cef ? "-cef" : ""; + return `farmcontrol-${version}-${arch}${cefSuffix}.${ext}`; } diff --git a/scripts/run-electrobun-build.mjs b/scripts/run-electrobun-build.mjs index 7ad3f77..53737d0 100644 --- a/scripts/run-electrobun-build.mjs +++ b/scripts/run-electrobun-build.mjs @@ -1,7 +1,7 @@ import { spawnSync } from "node:child_process"; import path from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; -import { getReleaseArch } from "./release-artifact-utils.mjs"; +import { getReleaseArch, isBundleCefEnabled } from "./release-artifact-utils.mjs"; const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const electrobunCli = path.join( @@ -15,6 +15,7 @@ const targetArch = getReleaseArch( process.env.ELECTROBUN_FORCE_ARCH || process.arch, ); +const bundleCef = isBundleCefEnabled(); const patchResult = spawnSync("bun", [path.join(rootDir, "scripts/patch-electrobun-src.mjs")], { cwd: rootDir, @@ -82,7 +83,7 @@ const env = { }; console.log( - `run-electrobun-build: env=${buildEnv} os=macos arch=${targetArch} (host ${getReleaseArch(process.arch)})`, + `run-electrobun-build: env=${buildEnv} os=macos arch=${targetArch} cef=${bundleCef} (host ${getReleaseArch(process.arch)})`, ); const result = spawnSync(