Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

electron-macos-print

A macOS native print module for Electron, using NSPrintPanel to display the system print dialog for PDF files.

Installation

Install directly from GitHub via SSH:

npm install git+ssh://git@github.com:xxxxxccc/electron-macos-print.git
# or
pnpm add git+ssh://git@github.com:xxxxxccc/electron-macos-print.git

Or add to package.json manually:

{
  "dependencies": {
    "electron-macos-print": "git+ssh://git@github.com:xxxxxccc/electron-macos-print.git"
  }
}

Note: This is a native addon that compiles from source during installation. Requires Xcode Command Line Tools on macOS.

Build from source

git clone git@github.com:xxxxxccc/electron-macos-print.git
cd electron-macos-print
pnpm install
pnpm build

Usage

Important: This module only works on macOS. When used in a cross-platform Electron app, always check process.platform before importing to avoid loading the native binary on unsupported platforms. Use dynamic import() with a try-catch so that missing or incompatible modules fail gracefully.

if (process.platform === 'darwin') {
  try {
    const { PrintRequest } = await import('electron-macos-print');

    if (PrintRequest.isAvailable()) {
      const request = new PrintRequest({
        pdfPath: '/path/to/document.pdf',
        title: 'My Document' // optional
      });
      await request.print();
    }
  } catch {
    // Module not available, fall back to other printing method
  }
}

Printing HTML in Electron

This module prints PDF files, not HTML directly. In a typical Electron app, you need to convert HTML to PDF first using BrowserWindow.webContents.printToPDF(), then pass the PDF path to PrintRequest:

import { app, BrowserWindow } from 'electron';
import { writeFile } from 'fs/promises';
import { join } from 'path';
import { PrintRequest } from 'electron-macos-print';

async function printHTML(html: string, title?: string): Promise<boolean> {
  if (!PrintRequest.isAvailable()) return false;

  // 1. Create a hidden BrowserWindow to render HTML
  const win = new BrowserWindow({ show: false, width: 800, height: 600 });

  // 2. Load HTML and generate PDF
  const tempHtmlPath = join(app.getPath('temp'), `print-${Date.now()}.html`);
  await writeFile(tempHtmlPath, html, 'utf-8');
  await win.loadFile(tempHtmlPath);

  const pdfData = await win.webContents.printToPDF({
    printBackground: true,
    pageSize: 'A4',
  });
  win.close();

  // 3. Save PDF to a temp file
  const pdfPath = join(app.getPath('temp'), `print-${Date.now()}.pdf`);
  await writeFile(pdfPath, pdfData);

  // 4. Print using native dialog
  const request = new PrintRequest({ pdfPath, title });
  await request.print();
  return true;
}

API

PrintRequest.isAvailable(): boolean

Returns true if native printing is available (macOS only). Always returns false on other platforms.

new PrintRequest(params)

Create a print request.

Parameters:

  • params.pdfPath: string — Absolute path to the PDF file to print
  • params.title?: string — Print window title (optional, defaults to "Print")

request.print(): Promise<boolean>

Opens the system print dialog. The promise resolves to true immediately after the dialog is presented — it does not wait for the user to confirm or cancel.

The print operation runs asynchronously on the macOS main thread via dispatch_async. This means you cannot determine from the return value whether the user actually printed or cancelled.

How It Works

On macOS, the module loads the PDF via PDFDocument (Quartz framework) and presents the native NSPrintPanel as a modal sheet on the active Electron window. If no window is available, it falls back to an application-modal dialog.

On unsupported platforms, PrintRequest.isAvailable() returns false and print() throws an error.

Packaging

When packaging your Electron app for the Mac App Store, the native addon's build artifacts (debug symbols, Makefiles, config files, etc.) may cause MAS validation failures. You need to clean them up before signing.

Here's an example using Electron Forge — add this to your forge.config.ts in a packagerConfig.afterCopy hook:

import { join } from 'path'
import { existsSync, readdirSync, statSync, unlinkSync, rmdirSync } from 'fs'

// In packagerConfig.afterCopy:
async (buildPath: string) => {
  const nativePrintPath = join(buildPath, 'node_modules', 'electron-macos-print')
  if (!existsSync(nativePrintPath)) return

  // Remove node-addon-api (not needed at runtime)
  const nodeAddonApiPath = join(nativePrintPath, 'node-addon-api')
  if (existsSync(nodeAddonApiPath)) {
    rmdirSync(nodeAddonApiPath, { recursive: true })
  }

  // Remove dSYM debug symbols
  const dSYMPath = join(
    nativePrintPath, 'build', 'Release',
    'electron_native_print.node.dSYM',
  )
  if (existsSync(dSYMPath)) {
    rmdirSync(dSYMPath, { recursive: true })
  }

  // Clean build directory — keep only .o, .node, .stamp files
  const buildDir = join(nativePrintPath, 'build')
  if (existsSync(buildDir)) {
    const cleanBuildDir = (dir: string) => {
      for (const item of readdirSync(dir)) {
        const itemPath = join(dir, item)
        const stats = statSync(itemPath)
        if (stats.isDirectory()) {
          cleanBuildDir(itemPath)
          if (readdirSync(itemPath).length === 0) rmdirSync(itemPath)
        } else if (stats.isFile()) {
          const ext = item.split('.').pop()?.toLowerCase()
          if (ext !== 'o' && ext !== 'node' && ext !== 'stamp') {
            unlinkSync(itemPath)
          }
        }
      }
    }
    cleanBuildDir(buildDir)
  }
}

What this cleans up and why:

Artifact Reason to remove
node-addon-api/ Header files only needed at compile time, not at runtime
*.dSYM Debug symbols inflate bundle size and are rejected by MAS
Makefiles, config.gypi, etc. Build system files that trigger MAS validation errors

Only .o (object), .node (native binary), and .stamp files are kept — these are required for the addon to function.

Build Requirements

  • macOS 10.15+
  • Xcode Command Line Tools
  • Node.js 16+

License

MIT

About

A macOS native print module using NSPrintPanel to display the system print dialog.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages