DMG Builder Utilities
dmg-builder is a low-level utility package focused on programmatically creating macOS Disk Image (.dmg) files. It serves as a core component within the electron-builder ecosystem, providing the underlying functionality for packaging Electron applications into DMGs. The package is currently at version 26.8.1 and adheres to the release cadence of electron-builder, receiving frequent updates, typically patch or minor versions, aligning with electron-builder's rapid development cycle. Its primary differentiator is its deep integration and optimization for Electron app packaging, offering robust and configurable options for macOS distribution, often surpassing generic DMG creation tools.
Common errors
-
Error: Command failed: hdiutil attach...
cause This error typically indicates that the macOS `hdiutil` command, which is essential for disk image manipulation, failed. Common reasons include incorrect paths to input files (like the application bundle), insufficient permissions, or issues with the target output directory.fixDouble-check all paths provided to `createDmg` (e.g., `appPath`, `destination`, `background`, `icon`). Ensure your application bundle is correctly structured and exists. Verify write permissions for the output directory. -
ReferenceError: require is not defined
cause This package, particularly in its modern versions (aligning with `electron-builder`'s evolution), is primarily designed for ESM (ECMAScript Modules) environments. Attempting to use `require()` for imports in an ESM context will result in this error.fixConvert your import statements from CommonJS `require()` to ESM `import`. For example, change `const { createDmg } = require('dmg-builder');` to `import { createDmg } from 'dmg-builder';`. Ensure your `package.json` specifies `"type": "module"` or use `.mjs` file extensions. -
TypeError: Cannot read properties of undefined (reading 'platform')
cause The `createDmg` function, as an internal utility of `electron-builder`, expects a `packager` argument (or at least an object simulating its structure) that contains platform and architecture information. When used standalone or mocked incorrectly, this context may be missing.fixWhen using `createDmg` directly, ensure you pass a valid `packager` object that includes `platform` and `arch` properties, potentially by mocking it as shown in the quickstart. For full functionality, consider leveraging `electron-builder`'s complete build process instead of directly calling `dmg-builder` utilities.
Warnings
- gotcha DMG creation utilities, including `dmg-builder`, are highly dependent on macOS-specific tools (like `hdiutil` and Finder's AppleScript capabilities). This means that DMG files can generally only be built on macOS operating systems. Attempting to build on Windows or Linux will result in errors due to missing system binaries and APIs.
- breaking Recent `electron-builder` (and thus `dmg-builder` indirectly) releases have included security updates for the `tar` dependency (to v7.5.8 and v7.5.10). While not a direct API change in `dmg-builder`, it's crucial to keep dependencies updated to mitigate potential supply chain vulnerabilities.
- gotcha A fix was implemented in `electron-builder@26.8.1` to 'always use package key when reading from dependency list instead of package `name`'. If you were relying on 'name' for certain configurations in a context where 'package key' is now enforced, this could lead to unexpected behavior or misconfigurations.
- gotcha While `dmg-builder` provides low-level utilities, comprehensive customization of DMG appearance (backgrounds, icon positions, license agreements) often requires setting extensive options through the `DmgOptions` interface. Overlooking these options can result in a generic or non-compliant DMG.
Install
-
npm install dmg-builder -
yarn add dmg-builder -
pnpm add dmg-builder
Imports
- createDmg
const { createDmg } = require('dmg-builder')import { createDmg } from 'dmg-builder' - DmgOptions
import type { DmgOptions } from 'dmg-builder'import { DmgOptions } from 'dmg-builder' - Target
import { Target } from 'dmg-builder'import { Target } from 'app-builder-lib'
Quickstart
import { createDmg, DmgOptions } from 'dmg-builder';
import { Arch, Platform } from 'builder-util';
import path from 'node:path';
import { promises as fs } from 'node:fs';
async function buildMyDmg() {
// Assume 'my-app' directory contains your compiled macOS Electron app bundle
const appDir = path.resolve(process.cwd(), 'dist/mac/my-app.app');
const outputDir = path.resolve(process.cwd(), 'release');
const appName = 'My App';
const appFileName = `${appName}.app`;
const dmgFileName = `${appName}.dmg`;
await fs.mkdir(outputDir, { recursive: true });
const dmgOptions: DmgOptions = {
// Relative path to the app bundle inside the DMG
app: path.join('.', appFileName),
// Path to the app bundle on the local filesystem
appPath: appDir,
// Output path for the generated DMG
destination: path.join(outputDir, dmgFileName),
// Volume name for the mounted DMG
volume: appName,
// Background image for the DMG window (optional)
background: path.resolve(__dirname, 'assets/background.png'),
// Icon for the DMG volume (optional)
icon: path.resolve(__dirname, 'assets/icon.icns'),
// Window size (optional, default 540x380)
window: { x: 100, y: 100, width: 600, height: 400 },
// Define icon positions (optional)
iconTextSize: 12,
iconSize: 96,
// This is a minimal set, electron-builder adds many more options
contents: [
{ x: 130, y: 220, type: 'file', path: appDir, name: appFileName },
{ x: 400, y: 220, type: 'link', path: '/Applications' }
],
// Add a license file if available
// license: path.resolve(__dirname, 'LICENSE.txt'),
// Explicitly set DMG filesystem size if auto-calculation is insufficient
// size: '1g'
};
console.log(`Building DMG for ${appName}...`);
try {
// createDmg expects a MacPackager instance for full context in electron-builder
// For standalone usage, a mock packager might be necessary or use electron-builder's full build process.
// This example simulates direct use, which is typically handled by electron-builder itself.
// In a real electron-builder setup, 'createDmg' would be called internally by the MacPackager.
// This code might require mocking the 'packager' argument or running within an electron-builder context.
// A simplified call, assuming 'createDmg' can run with just options and an identity (often optional).
// This is a placeholder for the actual complexity of standalone dmg-builder usage.
const dmgPath = await createDmg(dmgOptions, {
platform: Platform.MAC,
arch: Arch.x64,
projectDir: process.cwd(),
appOutDir: outputDir,
packager: {} as any // Mocking packager as it's typically an internal dependency from electron-builder
});
console.log(`DMG successfully created at: ${dmgPath}`);
} catch (error) {
console.error('Failed to create DMG:', error);
process.exit(1);
}
}
buildMyDmg();