Skip to content

Let macOS apps with a non-ASCII APP_NAME launch - #148

Open
simonhamp wants to merge 1 commit into
mainfrom
fix/non-ascii-app-name-macos
Open

Let macOS apps with a non-ASCII APP_NAME launch#148
simonhamp wants to merge 1 commit into
mainfrom
fix/non-ascii-app-name-macos

Conversation

@simonhamp

Copy link
Copy Markdown
Member

Fixes #98.

Setting APP_NAME to something non-ASCII — the issue reports MUNĖ — builds fine but produces a macOS app that never opens a window and spawns no child processes at all.

Root cause

Not quite what the issue guessed. app-builder-lib's MacPackager.prepareAppInfo() constructs AppInfo with normalizeNfd = true, so every name electron-builder writes to disk is NFD-decomposed:

  • the .app bundle and its executable, from productFilename
  • every Electron helper app — <name> Helper (GPU).app and friends — which electronMac.js names from sanitizedProductName, with a comment noting that Electron resolves helpers via CFBundleName

But applyCommonInfo() writes CFBundleName and CFBundleDisplayName from the raw appInfo.productName, which arrives from the environment composed (NFC).

So the bundle gets MUNĖ Helper (GPU).app on disk while CFBundleName is MUNĖ. Electron can't line the two up and dies during startup, before it spawns anything. For ASCII names NFC and NFD are byte-identical, which is why this has gone unnoticed.

Worth noting the dead end, since it's the intuitive one: APFS is normalisation-insensitive, so fs.existsSync() on the NFC path does find the NFD directory. The failure isn't a filesystem lookup.

Evidence

Reproduced with a bare Electron app on the versions we pin (electron 40, electron-builder 26):

build result
productName: 'MUNE' launches, 3 helper children, window created
productName: 'MUNĖ' exits 133 (SIGTRAP / EXC_BREAKPOINT) immediately, no children, no stderr
MUNĖ with CFBundleName rewritten to NFD launches, 3 helper children, window created
MUNĖ re-signed, plist untouched (control) still 133 — it's the name, not the ad-hoc signature

The last row rules out code signing as the cause, and the third row is the fix, verified straight out of electron-builder with no post-processing.

The change

mac.extendInfo now sets CFBundleName and CFBundleDisplayName to the NFD form of the app name. extendInfo is merged over the plist after applyCommonInfo writes it, so it wins.

  • productName itself is left composed, so Windows and Linux are untouched.
  • NFD is a no-op on ASCII, so nothing changes for any existing app.
  • Guarded on truthiness: electron-builder strips null/undefined plist values, so an unset NATIVEPHP_APP_NAME would otherwise delete CFBundleName from the bundle entirely.

Five tests cover it; two of them fail with the fix backed out.

Not addressed

Only macOS was investigated. On Linux executableName isn't set, so it defaults to the product name and a non-ASCII binary would land in /opt — untested, and no breakage reported there. Windows already sets win.executableName from the slugged filename.

This is arguably an electron-builder bug — it normalises the names on disk but not the plist key that indexes them — so an upstream issue may be worth filing alongside this workaround.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YLMT7W3hSqRwX9gpZM5pXr

electron-builder NFD-normalises every name it writes to disk on macOS -
the .app bundle, the executable and each of the Electron helper apps -
but writes CFBundleName straight from the product name, which reaches it
composed (NFC). Electron finds its helper apps by appending
" Helper (GPU).app" and friends to CFBundleName, so the two forms have to
agree. For APP_NAME=MUNĖ they don't: the app traps on launch before it
can spawn a single child process. ASCII names are identical in both
forms, which is why this has gone unnoticed.

Decompose the name ourselves in mac.extendInfo, which electron-builder
merges over the Info.plist after writing it. productName is left
composed, so Windows and Linux are untouched, and NFD is a no-op on
ASCII, so nothing changes for existing apps.

Fixes #98

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YLMT7W3hSqRwX9gpZM5pXr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Non-ASCII APP_NAME stops built application from launching

1 participant