From f6080ad1c6b19b15b5ff57cc37d825df22f8167f Mon Sep 17 00:00:00 2001 From: ErlichLiu Date: Wed, 15 Jul 2026 18:02:32 +0800 Subject: [PATCH] prepare windows arm64 release packaging --- .github/workflows/release.yml | 42 ++++++++++ apps/electron/electron-builder.yml | 3 +- apps/electron/scripts/dist.ts | 99 ++++++++++++++++++++++-- apps/electron/scripts/download-bun.ts | 4 +- apps/electron/src/main/lib/bun-finder.ts | 1 + packages/shared/package.json | 2 +- packages/shared/src/types/runtime.ts | 1 + 7 files changed, 142 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 51663f4ab..2f0fcc5c9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,6 +10,10 @@ # - APPLE_APP_SPECIFIC_PASSWORD: App-Specific 密码(公证用) # - APPLE_TEAM_ID: Apple Developer Team ID # GITHUB_TOKEN 由 GitHub Actions 自动提供,无需手动配置 +# +# Windows ARM64 发布默认关闭,等有 Windows ARM 真机或可用 runner 后再启用: +# - ENABLE_WINDOWS_ARM64_RELEASE=true +# - WINDOWS_ARM64_RUNNER=windows-11-arm(或自托管 runner label) name: Release @@ -315,3 +319,41 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: npx electron-builder --win --x64 --publish always working-directory: apps/electron + + build-windows-arm64: + name: build (Windows ARM64, win, arm64, --arm64) + if: vars.ENABLE_WINDOWS_ARM64_RELEASE == 'true' + runs-on: ${{ vars.WINDOWS_ARM64_RUNNER || 'windows-11-arm' }} + + steps: + - name: 检出代码 + uses: actions/checkout@v4 + + - name: 安装 Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: 安装 Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: 确认 Windows ARM64 runner + shell: pwsh + run: | + node -e "const actual = process.platform + '-' + process.arch; if (actual !== 'win32-arm64') { console.error('Expected win32-arm64, got ' + actual); process.exit(1) }" + + - name: 安装依赖 + run: bun install --frozen-lockfile + + # 构建应用。Windows ARM64 runner 会产出原生 proma.exe CLI,避免交叉编译污染安装包。 + - name: 构建 Electron 应用 + run: bun run electron:build + working-directory: . + + - name: 打包并发布 (Windows ARM64) + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: npx electron-builder --win --arm64 --publish always + working-directory: apps/electron diff --git a/apps/electron/electron-builder.yml b/apps/electron/electron-builder.yml index e65ba4b96..7f407c8b4 100644 --- a/apps/electron/electron-builder.yml +++ b/apps/electron/electron-builder.yml @@ -127,8 +127,9 @@ win: - target: nsis arch: - x64 + - arm64 -# NSIS 安装程序配置 +# NSIS 安装程序配置(x64 + arm64 均使用安装器;正式 arm64 包需在 Windows ARM runner 上构建) nsis: oneClick: false allowToChangeInstallationDirectory: true diff --git a/apps/electron/scripts/dist.ts b/apps/electron/scripts/dist.ts index 584fbc6a0..82ee61baa 100644 --- a/apps/electron/scripts/dist.ts +++ b/apps/electron/scripts/dist.ts @@ -5,19 +5,24 @@ * 功能: * - 分步执行打包流程,每步带计时和状态指示 * - 支持只构建当前架构(--current-arch)加速开发测试 + * - 支持指定目标架构(--arm64 / --x64)覆盖当前架构 * - 支持详细输出模式(--verbose)查看 electron-builder 完整日志 * - 支持跳过代码签名(--no-sign) * - 支持只构建 DMG 或 ZIP(--dmg / --zip) + * - 支持跳过 CLI 编译(--skip-cli),用于实验性交叉打包 * * 使用: * bun run scripts/dist.ts # 完整打包(双架构 + DMG + ZIP) * bun run scripts/dist.ts --current-arch # 只构建当前架构(快速) * bun run scripts/dist.ts --current-arch --verbose # 当前架构 + 详细日志 * bun run scripts/dist.ts --current-arch --dmg # 当前架构 + 只构建 DMG + * bun run scripts/dist.ts --arm64 # 只构建 ARM64 + * bun run scripts/dist.ts --win --arm64 --skip-cli # 实验性交叉打包 Windows ARM64(不含 CLI) * bun run scripts/dist.ts --no-sign # 跳过代码签名 */ import { spawnSync } from 'child_process' +import { existsSync, mkdirSync, rmSync } from 'fs' import { join } from 'path' // ============================================ @@ -37,6 +42,13 @@ interface DistOptions { noSign: boolean targetFormat: 'all' | 'dmg' | 'zip' | 'dir' platform: 'mac' | 'win' | 'linux' + targetArch: 'arm64' | 'x64' | null + skipCli: boolean +} + +interface TargetTriple { + platform: 'mac' | 'win' | 'linux' + arch: 'arm64' | 'x64' | 'multi' } // ============================================ @@ -128,16 +140,80 @@ function runStep( return { name, duration, success: result.status === 0, skipped: false } } +function getHostPlatform(): DistOptions['platform'] { + if (process.platform === 'darwin') return 'mac' + if (process.platform === 'win32') return 'win' + return 'linux' +} + +function getHostArch(): 'arm64' | 'x64' { + if (process.arch !== 'arm64' && process.arch !== 'x64') { + throw new Error(`不支持的主机架构: ${process.arch}`) + } + return process.arch +} + +function getTargetTriple(opts: DistOptions): TargetTriple { + return { + platform: opts.platform, + arch: opts.targetArch ?? (opts.currentArch ? getHostArch() : 'multi'), + } +} + +function shouldBuildCli(opts: DistOptions, target: TargetTriple): boolean { + if (opts.skipCli) return false + if (target.arch === 'multi') return target.platform === getHostPlatform() + return target.platform === getHostPlatform() && target.arch === getHostArch() +} + +function assertCliBuildIsSafe(opts: DistOptions, target: TargetTriple): void { + if (opts.skipCli) return + + const host = `${getHostPlatform()}-${getHostArch()}` + const targetName = `${target.platform}-${target.arch}` + const samePlatform = target.platform === getHostPlatform() + const sameArch = target.arch === 'multi' || target.arch === getHostArch() + if (!samePlatform || !sameArch) { + console.error( + `${color.red}[dist] 无法在 ${host} 主机上为 ${targetName} 编译 proma CLI。${color.reset}` + ) + console.error( + `${color.yellow}[dist] 正式发布请使用目标平台/架构 runner;实验性交叉打包请显式加 --skip-cli。${color.reset}` + ) + process.exit(1) + } +} + +function clearCliResources(): void { + const cliDir = join(import.meta.dir, '..', 'resources', 'bin') + if (existsSync(cliDir)) { + rmSync(cliDir, { recursive: true, force: true }) + } + mkdirSync(cliDir, { recursive: true }) +} + // ============================================ // 主流程 // ============================================ function parseArgs(): DistOptions { const args = process.argv.slice(2) + const hasTargetArch = args.includes('--arm64') || args.includes('--x64') + + if (args.includes('--arm64') && args.includes('--x64')) { + console.error(`${color.red}[dist] --arm64 和 --x64 不能同时使用${color.reset}`) + process.exit(1) + } + if (hasTargetArch && args.includes('--current-arch')) { + console.warn(`${color.yellow}[dist] 同时使用目标架构和 --current-arch,已忽略 --current-arch${color.reset}`) + } + return { - currentArch: args.includes('--current-arch'), + currentArch: args.includes('--current-arch') && !hasTargetArch, verbose: args.includes('--verbose'), noSign: args.includes('--no-sign'), + skipCli: args.includes('--skip-cli'), + targetArch: args.includes('--arm64') ? 'arm64' : args.includes('--x64') ? 'x64' : null, targetFormat: args.includes('--dmg') ? 'dmg' : args.includes('--zip') @@ -155,15 +231,18 @@ function parseArgs(): DistOptions { function main(): void { const opts = parseArgs() - const arch = process.arch // arm64 或 x64 + const target = getTargetTriple(opts) + assertCliBuildIsSafe(opts, target) const results: StepResult[] = [] // 打印配置信息 console.log(`\n${color.bgBlue}${color.bold} Proma 打包工具 ${color.reset}\n`) console.log(` ${color.bold}平台${color.reset}: ${opts.platform}`) - console.log(` ${color.bold}架构${color.reset}: ${opts.currentArch ? arch + ' (仅当前)' : 'arm64 + x64'}`) + console.log(` ${color.bold}架构${color.reset}: ${target.arch === 'multi' ? 'arm64 + x64' : target.arch}`) + console.log(` ${color.bold}主机${color.reset}: ${getHostPlatform()}-${getHostArch()}`) console.log(` ${color.bold}格式${color.reset}: ${opts.targetFormat}`) console.log(` ${color.bold}签名${color.reset}: ${opts.noSign ? '跳过' : '启用'}`) + console.log(` ${color.bold}CLI${color.reset}: ${shouldBuildCli(opts, target) ? '编译' : '跳过'}`) console.log(` ${color.bold}详细日志${color.reset}: ${opts.verbose ? '开启' : '关闭'}`) printSeparator() @@ -200,8 +279,14 @@ function main(): void { // ── 步骤 4: 编译 proma CLI 二进制 ── step++ printStepStart(step, totalSteps, '编译 proma CLI (bun --compile)') + if (!shouldBuildCli(opts, target)) { + clearCliResources() + } results.push( - runStep('编译 proma CLI', 'bun', ['run', 'build:cli'], { verbose: opts.verbose }) + runStep('编译 proma CLI', 'bun', ['run', 'build:cli'], { + verbose: opts.verbose, + skip: !shouldBuildCli(opts, target), + }) ) printStepResult(results[results.length - 1]) if (!results[results.length - 1].success) return printSummary(results) @@ -220,9 +305,9 @@ function main(): void { const builderArgs = ['electron-builder', `--${opts.platform}`] - // 只构建当前架构 - if (opts.currentArch) { - builderArgs.push(`--${arch}`) + // 指定目标架构 + if (target.arch !== 'multi') { + builderArgs.push(`--${target.arch}`) } // 指定输出格式 diff --git a/apps/electron/scripts/download-bun.ts b/apps/electron/scripts/download-bun.ts index 751ce21c1..7898882dd 100644 --- a/apps/electron/scripts/download-bun.ts +++ b/apps/electron/scripts/download-bun.ts @@ -4,7 +4,7 @@ * * 功能: * - 从 GitHub releases 下载指定版本的 Bun 二进制文件 - * - 支持所有目标平台(darwin-arm64, darwin-x64, linux-arm64, linux-x64, win32-x64) + * - 支持所有目标平台(darwin-arm64, darwin-x64, linux-arm64, linux-x64, win32-arm64, win32-x64) * - SHA256 校验验证 * - 解压到 vendor/bun/{platform-arch}/ 目录 * @@ -30,6 +30,7 @@ const PLATFORM_ARCH_MAP: Record = { 'darwin-x64': 'darwin-x64', 'linux-arm64': 'linux-aarch64', 'linux-x64': 'linux-x64', + 'win32-arm64': 'windows-aarch64', 'win32-x64': 'windows-x64', } @@ -39,6 +40,7 @@ const TARGET_PLATFORMS: PlatformArch[] = [ 'darwin-x64', 'linux-arm64', 'linux-x64', + 'win32-arm64', 'win32-x64', ] diff --git a/apps/electron/src/main/lib/bun-finder.ts b/apps/electron/src/main/lib/bun-finder.ts index 19b49f9b6..929de46dd 100644 --- a/apps/electron/src/main/lib/bun-finder.ts +++ b/apps/electron/src/main/lib/bun-finder.ts @@ -35,6 +35,7 @@ export function getCurrentPlatformArch(): PlatformArch { 'darwin-x64', 'linux-arm64', 'linux-x64', + 'win32-arm64', 'win32-x64', ] diff --git a/packages/shared/package.json b/packages/shared/package.json index 74129f42d..a6d4f18ca 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@proma/shared", - "version": "0.1.41", + "version": "0.1.42", "license": "AGPL-3.0-only", "description": "Shared types, configs and utilities for proma", "type": "module", diff --git a/packages/shared/src/types/runtime.ts b/packages/shared/src/types/runtime.ts index 593b00226..a11c32801 100644 --- a/packages/shared/src/types/runtime.ts +++ b/packages/shared/src/types/runtime.ts @@ -22,6 +22,7 @@ export type PlatformArch = | 'darwin-x64' | 'linux-arm64' | 'linux-x64' + | 'win32-arm64' | 'win32-x64' /**