executable-wrapper
v1.5.0
Published
Universal packaging tool that converts Node.js projects into native executables for macOS (.app/.pkg) and Windows (.exe)
Maintainers
Readme
Executable Wrapper
A universal Node.js application packager that creates signed and notarized executables for macOS and Windows.
🎯 Features
- ✅ Cross-platform - Build for macOS (x64, arm64, universal) and Windows
- ✅ Code Signing - Automatic signing with Developer ID certificates
- ✅ Notarization - Apple notarization with automatic stapling
- ✅ Native Addons - Full support for native Node.js modules (usb, node-hid, etc.)
- ✅ Universal Binaries - True universal macOS apps and PKG installers supporting both Intel and Apple Silicon
- ✅ Terminal Control - Optional
--terminalparameter to force terminal execution in macOS apps - ✅ Zero Configuration - Single
.envfile drives the entire build process - ✅ Production Ready - Apps pass Gatekeeper and can be distributed immediately
- ✅ NPM Package Ready - Works seamlessly as an npm dependency with proper path resolution
📦 What It Does
This wrapper project packages any Node.js application into native executables:
- macOS:
.appbundles and.pkginstallers (including universal binaries) - Windows:
.exeexecutables
No need to integrate build scripts into your project - just provide a .env configuration file and the wrapper handles everything.
🚀 Quick Start
1. Install Dependencies
cd executable-wrapper
npm install2. Prepare Your Project
Your Node.js project structure:
my-project/
├── dist/
│ └── index.js # Your bundled application
├── resources/
│ ├── appIcon.icns # macOS icon (optional)
│ └── appIcon.ico # Windows icon (optional)
├── pkg.json # pkg configuration (optional, for native modules)
└── .env # Wrapper configuration3. Create .env Configuration
Create a .env file in your project:
# Application Info
APP_NAME=my-app
BUNDLE_ID=com.company.myapp
APP_DISPLAY_NAME=My Application
APP_VERSION=1.0.0
# Build Configuration
JS_ENTRY_POINT=dist/index.js
PKG_CONFIG=pkg.json
# Resources
ICON_MACOS=resources/appIcon.icns
ICON_WINDOWS=resources/appIcon.ico
# macOS Signing & Notarization (required for --sign and --notarize)
APPLE_TEAM_NAME="Your Company Name"
APPLE_TEAM_ID=YOUR_TEAM_ID
[email protected]
APPLE_ID_PASSWORD=xxxx-xxxx-xxxx-xxxx
# macOS Configuration
INSTALL_LOCATION=/Applications/Utilities
MACOS_PERMISSIONS=network.client,device.usb
# Company Info
COMPANY_NAME=Your Company
COPYRIGHT=Copyright © 2024 Your CompanySee template.env for a complete configuration example.
4. Build Your Application
cd executable-wrapper
# macOS Universal (both Intel and Apple Silicon)
node index.js --env ../my-project/.env --platform macos-universal --format app
# macOS with signing and notarization
node index.js --env ../my-project/.env --platform macos-universal --format app --sign --notarize
# Windows
node index.js --env ../my-project/.env --platform win-x64
# macOS universal installer (.pkg) - supports both Intel and Apple Silicon
node index.js --env ../my-project/.env --platform macos-universal --format pkg --sign5. Find Your Executable
Output will be in your project's executable-wrapper-app-releases/ directory:
my-project/executable-wrapper-app-releases/
├── my-app-1_0_0-macos-universal.app
├── my-app-1_0_0-macos-universal.pkg
└── my-app-1_0_0-win-x64.exe📋 CLI Options
node index.js [options]
Options:
--env <path> Path to .env configuration file (required)
--platform <type> Target platform:
- macos-x64 (Intel Mac)
- macos-arm64 (Apple Silicon)
- macos-universal (Universal binary)
- win-x64 (Windows)
--format <type> Output format:
- executable (binary only)
- app (macOS .app bundle)
- pkg (macOS installer)
--sign Sign the application (requires credentials in .env)
--notarize Notarize the application (implies --sign, macOS only)
--terminal-script Generate wrapper script that shows terminal output (macOS only)
--output <path> Custom output directory (optional)
--help, -h Show help
--version, -v Show version🔐 Code Signing & Notarization
macOS Requirements
For --sign and --notarize flags, you need:
- Apple Developer Account with Developer ID certificates
- Certificates installed in Keychain:
- Developer ID Application (for .app)
- Developer ID Installer (for .pkg)
- App-Specific Password for notarization (generate at https://appleid.apple.com/account/manage)
Add these to your .env:
APPLE_TEAM_NAME="Your Company Name"
APPLE_TEAM_ID=ABC1234XYZ
[email protected]
APPLE_ID_PASSWORD=xxxx-xxxx-xxxx-xxxxWhat Happens During Signing & Notarization
- Signing - Code signs the .app with your Developer ID
- Notarization - Submits to Apple's notarization service
- Stapling - Attaches the notarization ticket to the .app
- Verification - Validates the signature and notarization
Result: Your app passes Gatekeeper and can be distributed without warnings.
🔧 Native Modules
If your app uses native Node.js modules (like usb, node-hid, serialport), create a pkg.json in your project root:
{
"assets": [
"node_modules/usb/prebuilds/**/*.node",
"node_modules/node-hid/prebuilds/**/*.node"
]
}Important: Asset paths in pkg.json are resolved relative to your project root directory (where your .env file is located), not relative to the JS entry point.
Reference it in your .env:
PKG_CONFIG=pkg.jsonVerifying Native Module Packaging
To ensure native modules are properly included:
- Place
pkg.jsonin your project root (same directory as.env) - Use paths relative to the project root (e.g.,
node_modules/*/prebuilds/**/*.node) - Check that the prebuilt binaries exist in your
node_modulesdirectory
🎨 Application Icons
macOS (.icns)
Create a .icns file with multiple resolutions:
- 16x16, 32x32, 64x64, 128x128, 256x256, 512x512, 1024x1024
Tools: Icon Composer, iconutil, or online converters.
Windows (.ico)
Create a .ico file with multiple resolutions:
- 16x16, 32x32, 48x48, 64x64, 128x128, 256x256
Tools: GIMP, ImageMagick, or online converters.
🏗️ Project Structure
executable-wrapper/
├── index.js # Main entry point
├── lib/
│ ├── config.js # Configuration management
│ ├── builder.js # Executable builder (pkg)
│ ├── macos/
│ │ ├── app-builder.js # .app bundle creator
│ │ ├── pkg-builder.js # .pkg installer creator
│ │ ├── universal-builder.js # Universal binary builder
│ │ ├── plist-generator.js # Info.plist generator
│ │ ├── entitlements-generator.js # Entitlements generator
│ │ ├── signer.js # Code signing
│ │ └── notarizer.js # Notarization & stapling
│ └── windows/
│ └── signer.js # Windows signing
├── mac/
│ └── app.entitlements.example # Example entitlements file
├── template.env # Configuration template
├── package.json
└── README.md📚 Configuration Reference
Required Fields
APP_NAME=my-app # Application name (lowercase, no spaces)
BUNDLE_ID=com.company.app # macOS bundle identifier
APP_DISPLAY_NAME=My Application # Display name (user-facing)
APP_VERSION=1.0.0 # Version number
JS_ENTRY_POINT=dist/index.js # Path to your bundled JS fileOptional Fields
# Resources
ICON_MACOS=resources/appIcon.icns # macOS icon
ICON_WINDOWS=resources/appIcon.ico # Windows icon
PKG_CONFIG=pkg.json # pkg configuration file
# macOS Permissions (comma-separated)
MACOS_PERMISSIONS=network.client,device.usb
# Custom Entitlements
ENTITLEMENTS_PATH=mac/custom.entitlements # Override default entitlements
# Company Info
COMPANY_NAME=My Company
COPYRIGHT=Copyright © 2024 My Company
# macOS Installer
INSTALL_LOCATION=/Applications/Utilities # .pkg install locationmacOS Permissions
Available permissions for MACOS_PERMISSIONS:
network.client- Outgoing network connectionsnetwork.server- Incoming network connectionsdevice.usb- USB device accessdevice.bluetooth- Bluetooth accessfiles.user-selected.read-write- File access via dialogsfiles.downloads.read-write- Downloads folder access
🖥️ Terminal Control (macOS)
For macOS applications, you can control the wrapper script behavior at build time:
Build-Time Control
Use the --terminal-script parameter during build to generate different wrapper scripts:
# Default: Background execution (no terminal popup)
node index.js --env ../myapp/.env --platform macos-universal --format app
# Terminal script: Always shows terminal output
node index.js --env ../myapp/.env --platform macos-universal --format app --terminal-scriptWrapper Script Types
Default Script (Background Execution)
- From Terminal: Runs in foreground (shows output)
- From Finder/GUI: Runs in background (no terminal popup)
- Use case: Regular applications that don't need terminal output
Terminal Script (Always Shows Terminal)
- From Terminal: Runs in foreground (shows output)
- From Finder/GUI: Opens Terminal and runs in foreground (shows output)
- Use case: CLI tools, debugging, interactive applications
Use Cases
- Debugging: See real-time output and error messages
- Interactive Apps: CLI tools that need user input
- Development: Testing and troubleshooting
- Logging: Monitor application behavior
🔍 Troubleshooting
"command not found: pkg"
Solution: Run npm install in the wrapper project.
"Missing signing configuration"
Solution: Add APPLE_TEAM_NAME and APPLE_TEAM_ID to your .env.
"Missing notarization configuration"
Solution: Add APPLE_ID and APPLE_ID_PASSWORD to your .env.
Notarization fails
- Check your Apple ID and app-specific password
- Ensure certificates are installed and valid
- Check Apple's notarization logs for specific errors
Native modules not working
- Ensure
pkg.jsonis in your project root directory (same location as.env) - Asset paths must be relative to the project root, not the entry point directory
- Check that prebuilt binaries exist in
node_modules - Verify the module supports your target platform
- Example: If your entry point is
dist/index.js, paths likenode_modules/usb/**/*.nodewill resolve from the project root, not fromdist/
📖 Examples
Example usage with the test-app project can be found in the neighboring test-app directory.
📄 License
MIT License - See package.json for details.
Ensure you have appropriate licenses and certificates for code signing when distributing applications.
🤝 Contributing
This is a wrapper tool designed for internal use. For issues or improvements, please contact the maintainer.
📝 Changelog
v1.3.1 (2025-10-09)
- Improved: More robust pkg execution with explicit
lib-es5/bin.jsresolution and clearer logging - Stability: Native module rebuild failures no longer fail the overall build, only warn
v1.3.0 (2025-01-27)
- Added: Universal PKG support for macOS installers
- Added: Automatic native module rebuilding for target platforms
- Improved: Enhanced universal build capabilities with better architecture detection
v1.2.0 (2025-10-09)
- Fixed: pkg assets path resolution now uses project root instead of entry point directory
- Improved: Native modules packaging for projects with JS entry points in subdirectories
- This ensures
pkg.jsonasset paths are correctly resolved from the project root
See CHANGELOG.md for full version history.
Version: 1.3.1
Last Updated: 2025-10-09
