perf(desktop): compress macOS DMGs with LZMA

This commit is contained in:
kingwl committed 2026-10-12 18:06:00 +08:00
1 parent 3aa8872e67
commit 01283f1fdd
12 files changed
+69 -8

No files matched your search

+1
View File
@@ -146,6 +146,7 @@ pnpm applies local patches to the following packages at install time, so shipped
- `@fortune-sheet/core@1.0.4` — [`patches/@fortune-sheet__core@1.0.4.patch`](patches/@fortune-sheet__core@1.0.4.patch)
- `@fortune-sheet/react@1.0.4` — [`patches/@fortune-sheet__react@1.0.4.patch`](patches/@fortune-sheet__react@1.0.4.patch)
- `@yao-pkg/pkg@6.21.0` — [`patches/@yao-pkg__pkg@6.21.0.patch`](patches/@yao-pkg__pkg@6.21.0.patch)
- `app-builder-lib@26.17.0` — [`patches/app-builder-lib@26.17.0.patch`](patches/app-builder-lib@26.17.0.patch)
- `exceljs@4.4.0` — [`patches/exceljs@4.4.0.patch`](patches/exceljs@4.4.0.patch)
- `node-pty@1.2.0-beta.15` — [`patches/node-pty@1.2.0-beta.15.patch`](patches/node-pty@1.2.0-beta.15.patch)
@@ -30,6 +30,7 @@ export interface DesktopElectronBuilderConfig {
readonly signIgnore: readonly string[]
}
readonly dmg: {
readonly format: 'ULMO'
readonly sign: boolean
readonly writeUpdateInfo: boolean
}
+2 -2
View File
@@ -21,8 +21,8 @@
en: d80a92c02a583b80
zh: b27f75ff29fcea1a
/desktop-packaging/configuration-and-local-builds:
en: e8b8bb1e287bff80
zh: 09b38712c8e974bc
en: e4f526604231ed43
zh: d412179ffdc402ba
/desktop-packaging/windows-actions-packaging:
en: e3f51e7130a0fe05
zh: 70fd6a40d5899871
+2
View File
@@ -93,6 +93,8 @@ pnpm run package:desktop:win:x64
The macOS arm64 command requires Apple Silicon. The macOS x64 command runs on Intel macOS or Apple Silicon with Rosetta. The Windows x64 command requires Windows x64. Linux is not a supported Desktop release target.
Both release and local unsigned macOS DMGs use LZMA compression (`dmg.format: 'ULMO'`) in [the electron-builder configuration](../scripts/electron-builder-config.mjs). A [build-time patch](../../../patches/app-builder-lib@26.17.0.patch) adds this format to the pinned builder's validation and TypeScript declarations.
Each target owns its packed package inputs, prepared runtime, package set, dsh tree, pnpm preparation state, unpacked application, update metadata, and final artifacts under `apps/desktop/.desktop-build/targets/<target>/`. The Electron archive cache remains shared under `.desktop-build/downloads` because every archive name includes its version, platform, and architecture and is verified before extraction. A target build never consumes another target's mutable preparation state.
<a id="windows-actions"></a>
+2
View File
@@ -93,6 +93,8 @@ pnpm run package:desktop:win:x64
macOS arm64 命令要求 Apple Silicon。macOS x64 命令可以在 Intel macOS 或带 Rosetta 的 Apple Silicon 上运行。Windows x64 命令要求 Windows x64。Linux 不是受支持的 Desktop 发布目标。
macOS 正式发布和本地未签名 DMG 都通过 [electron-builder 配置](../scripts/electron-builder-config.mjs)中的 `dmg.format: 'ULMO'` 使用 LZMA 压缩。[构建时补丁](../../../patches/app-builder-lib@26.17.0.patch)为固定版本 builder 的校验规则和 TypeScript 声明添加此格式。
每个目标都在 `apps/desktop/.desktop-build/targets/<target>/` 下持有自己的打包输入、已准备运行时、包集合、dsh 依赖树、pnpm 准备状态、未打包应用、更新元数据和最终产物。Electron 归档缓存继续由 `.desktop-build/downloads` 共享,因为每个归档文件名都包含版本、平台和架构,并且在解包前经过验证。目标构建绝不读取其他目标的可变准备状态。
<a id="windows-actions"></a>
@@ -166,6 +166,7 @@ export function createElectronBuilderConfig(
target: unsigned ? ['dmg'] : ['dmg', 'zip'],
},
dmg: {
format: 'ULMO',
sign: !unsigned,
writeUpdateInfo: false,
},
@@ -13,6 +13,7 @@ export const DESKTOP_RUNTIME_PATCHES: Readonly<Record<string, DesktopRuntimePatc
'@fortune-sheet/core@1.0.4': { scope: 'workspace-only', reason: 'Patched spreadsheet code is embedded in the client bundle.' },
'@fortune-sheet/react@1.0.4': { scope: 'workspace-only', reason: 'Patched spreadsheet code is embedded in the client bundle.' },
'@yao-pkg/pkg@6.21.0': { scope: 'workspace-only', reason: 'The executable packer executes on the build host.' },
'app-builder-lib@26.17.0': { scope: 'workspace-only', reason: 'DMG format validation executes on the build host.' },
'exceljs@4.4.0': { scope: 'workspace-only', reason: 'The patched parser is embedded in the client bundle and worker.' },
'node-pty@1.2.0-beta.15': { scope: 'shared', reason: 'Runtime terminals need helper resolution and Windows worker cleanup.' },
}
@@ -1,5 +1,6 @@
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'
import { readFileSync } from 'node:fs'
import { createRequire } from 'node:module'
import type { NotarizeOptions } from '@electron/notarize'
import {
resolveDesktopAppId,
@@ -12,6 +13,11 @@ import {
assertMacOSSignatureDetails,
} from '../scripts/verify-macos-signature.mjs'
const require = createRequire(import.meta.url)
const { validateConfiguration } = require('app-builder-lib/out/util/config/config.js') as {
validateConfiguration: (config: object, logger: { isEnabled: false }) => Promise<void>
}
const RELEASE_ENVIRONMENT = {
DSH_DESKTOP_APP_ID: 'com.example.desktop',
DSH_DESKTOP_MANDATORY_UPDATE_TEST_ORIGIN: 'https://policy.example.com',
@@ -75,6 +81,7 @@ describe('desktop macOS release signature', () => {
signIgnore: ['/Contents/Resources/app\\.asar\\.unpacked/dsh(?:/|$)', '/Contents/Resources/runtime/primary-runtime(?:/|$)', '\\.pak$'],
},
dmg: {
format: 'ULMO',
sign: true,
writeUpdateInfo: false,
},
@@ -87,6 +94,23 @@ describe('desktop macOS release signature', () => {
expect(typeof config.artifactBuildCompleted).toBe('function')
})
it('accepts LZMA DMGs through builder validation while rejecting unknown formats', async () => {
const { createElectronBuilderConfig } = await import('../scripts/electron-builder-config.mjs')
for (const arch of ['arm64', 'x64']) {
for (const unsigned of ['0', '1']) {
const config = createElectronBuilderConfig({
...RELEASE_ENVIRONMENT,
DSH_DESKTOP_TARGET_ARCH: arch,
DSH_DESKTOP_UNSIGNED: unsigned,
}, 'darwin', arch)
expect(config.dmg.format).toBe('ULMO')
await expect(validateConfiguration(config, { isEnabled: false })).resolves.toBeUndefined()
}
}
await expect(validateConfiguration({ dmg: { format: 'invalid' } }, { isEnabled: false }))
.rejects.toThrow('configuration.dmg.format')
})
it('seals PAK resources with their enclosing bundle while signing executable code', async () => {
const { createElectronBuilderConfig } = await import('../electron-builder.config.mjs')
const config = createElectronBuilderConfig(RELEASE_ENVIRONMENT, 'darwin', 'arm64')
@@ -43,7 +43,7 @@ it('classifies the current workspace and shares only runtime patch bytes', () =>
const before = readFileSync(join(repository, 'pnpm-lock.yaml'))
const plan = prepareRuntimePatches(project, repository)
expect(plan.patches.map(entry => entry.spec)).toEqual(['@earendil-works/pi-ai@1.0.2', 'node-pty@1.2.0-beta.15'])
expect(plan.workspaceOnly).toHaveLength(5)
expect(plan.workspaceOnly).toHaveLength(6)
const settings = yaml.load(readFileSync(join(project, 'pnpm-workspace.yaml'), 'utf8')) as { overrides: Record<string, string> }
expect(settings.overrides['@earendil-works/pi-ai']).toBeUndefined()
expect(settings.overrides['@earendil-works/pi-ai@^1.0.2']).toBe('1.0.2')
+27
View File
@@ -0,0 +1,27 @@
diff --git a/out/options/macOptions.d.ts b/out/options/macOptions.d.ts
index e93987d973399b17f3970c858abb49f5e4b193d6..445a73c81e1d7eb61dc318373d2331487934d3f5 100644
--- a/out/options/macOptions.d.ts
+++ b/out/options/macOptions.d.ts
@@ -258,7 +258,7 @@ export interface DmgOptions extends TargetSpecificOptions {
* The disk image format. `ULFO` (lzfse-compressed image (OS X 10.11+ only)).
* @default UDZO
*/
- format?: "UDRW" | "UDRO" | "UDCO" | "UDZO" | "UDBZ" | "ULFO";
+ format?: "UDRW" | "UDRO" | "UDCO" | "UDZO" | "UDBZ" | "ULFO" | "ULMO";
/**
* The filesystem for the DMG volume (e.g. `"APFS"` or `"HFS+"`)
* This will be changed to APFS in the next major release, so it is recommended to set it explicitly to HFS+ if you want to keep using HFS+ (e.g. for better compatibility with older macOS versions).
diff --git a/scheme.json b/scheme.json
index a637bab2668ef88e7382dd4aa5db62b74fdde898..ebcafac58971bdd7c69b78ceddcd401a75ffaa35 100644
--- a/scheme.json
+++ b/scheme.json
@@ -979,7 +979,8 @@
"UDRO",
"UDRW",
"UDZO",
- "ULFO"
+ "ULFO",
+ "ULMO"
],
"type": "string"
},
+6 -5
View File
@@ -15,6 +15,7 @@ patchedDependencies:
'@fortune-sheet/core@1.0.4': 8791a230763dbf853fd65d627c68c31de37209992851377855e16cf08ea70532
'@fortune-sheet/react@1.0.4': 2932e52e79afcd4ced08cfa123b5eded786c85043da32f622f3e80af6fc96c37
'@yao-pkg/pkg@6.21.0': 75891fc22b277c145cafeab83e41baf4a70f5b8fe6dc0801c6a0b922d7ee88c7
app-builder-lib@26.17.0: b70dc2a2a78ffabb80a4f14fafc7c103237f2b0a207e1f296fa1c1387ea29348
exceljs@4.4.0: c1bf8ac8f319dab382f08e3a669b715e691d46c703ac5a4163eb383fbedd1d48
node-pty@1.2.0-beta.15: 9d30053266d0f39d3debe894c675867f6782da6bcadbc94a693b3cfb9eff8ed0
@@ -722,7 +723,7 @@ importers:
version: 8.18.1
app-builder-lib:
specifier: 26.17.0
version: 26.17.0(dmg-builder@26.17.0)(electron-builder-squirrel-windows@26.17.0)(supports-color@9.4.0)
version: 26.17.0(patch_hash=b70dc2a2a78ffabb80a4f14fafc7c103237f2b0a207e1f296fa1c1387ea29348)(dmg-builder@26.17.0)(electron-builder-squirrel-windows@26.17.0)(supports-color@9.4.0)
cos-nodejs-sdk-v5:
specifier: 3.0.0
version: 3.0.0
@@ -26194,7 +26195,7 @@ snapshots:
anynum@1.0.1: {}
app-builder-lib@26.17.0(dmg-builder@26.17.0)(electron-builder-squirrel-windows@26.17.0)(supports-color@9.4.0):
app-builder-lib@26.17.0(patch_hash=b70dc2a2a78ffabb80a4f14fafc7c103237f2b0a207e1f296fa1c1387ea29348)(dmg-builder@26.17.0)(electron-builder-squirrel-windows@26.17.0)(supports-color@9.4.0):
dependencies:
'@electron/asar': 3.4.1
'@electron/fuses': 1.8.0
@@ -27057,7 +27058,7 @@ snapshots:
dmg-builder@26.17.0(electron-builder-squirrel-windows@26.17.0)(supports-color@9.4.0):
dependencies:
app-builder-lib: 26.17.0(dmg-builder@26.17.0)(electron-builder-squirrel-windows@26.17.0)(supports-color@9.4.0)
app-builder-lib: 26.17.0(patch_hash=b70dc2a2a78ffabb80a4f14fafc7c103237f2b0a207e1f296fa1c1387ea29348)(dmg-builder@26.17.0)(electron-builder-squirrel-windows@26.17.0)(supports-color@9.4.0)
builder-util: 26.16.0(supports-color@9.4.0)
fs-extra: 10.1.0
js-yaml: 4.3.2
@@ -27108,7 +27109,7 @@ snapshots:
electron-builder-squirrel-windows@26.17.0(dmg-builder@26.17.0)(supports-color@9.4.0):
dependencies:
app-builder-lib: 26.17.0(dmg-builder@26.17.0)(electron-builder-squirrel-windows@26.17.0)(supports-color@9.4.0)
app-builder-lib: 26.17.0(patch_hash=b70dc2a2a78ffabb80a4f14fafc7c103237f2b0a207e1f296fa1c1387ea29348)(dmg-builder@26.17.0)(electron-builder-squirrel-windows@26.17.0)(supports-color@9.4.0)
builder-util: 26.16.0(supports-color@9.4.0)
electron-winstaller: 5.4.0(supports-color@9.4.0)
transitivePeerDependencies:
@@ -27117,7 +27118,7 @@ snapshots:
electron-builder@26.17.0(electron-builder-squirrel-windows@26.17.0)(supports-color@9.4.0):
dependencies:
app-builder-lib: 26.17.0(dmg-builder@26.17.0)(electron-builder-squirrel-windows@26.17.0)(supports-color@9.4.0)
app-builder-lib: 26.17.0(patch_hash=b70dc2a2a78ffabb80a4f14fafc7c103237f2b0a207e1f296fa1c1387ea29348)(dmg-builder@26.17.0)(electron-builder-squirrel-windows@26.17.0)(supports-color@9.4.0)
builder-util: 26.16.0(supports-color@9.4.0)
builder-util-runtime: 9.7.0(supports-color@9.4.0)
chalk: 4.1.2
+1
View File
@@ -111,5 +111,6 @@ patchedDependencies:
'@fortune-sheet/core@1.0.4': patches/@fortune-sheet__core@1.0.4.patch
'@fortune-sheet/react@1.0.4': patches/@fortune-sheet__react@1.0.4.patch
'@yao-pkg/pkg@6.21.0': patches/@yao-pkg__pkg@6.21.0.patch
app-builder-lib@26.17.0: patches/app-builder-lib@26.17.0.patch
exceljs@4.4.0: patches/exceljs@4.4.0.patch
node-pty@1.2.0-beta.15: patches/node-pty@1.2.0-beta.15.patch