npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

windows-portable-packager

v0.0.18

Published

Go-based portable launcher for Windows Electron apps — hash verification, version management, multi-arch support, and electron-builder integration

Readme

windows-portable-packager

한국어

Go-based Windows portable launcher for Electron apps.

Electron's default portable build extracts files every time it runs. This tool extracts to %APPDATA% only once, verifies file integrity using xxHash64 hashes, and automatically cleans up previous versions.

How it works

All information such as app name, version, and architecture is read from the .kbpkg manifest at runtime. No app-specific information is hardcoded into the tool itself.

When used with electron-builder, settings like productName, version, and target architecture are automatically retrieved from the electron-builder configuration.

  • First run: Extracts embedded data from exe to %APPDATA%\<productName>\app\<version>\ → Verifies hashes → Launches app.
  • Re-run: Checks installation directory → Quickly verifies exe hash → Launches immediately.
  • Update: New exe version distributed → Replaces automatically on next run → Deletes old versions.

Single EXE Build Pipeline

  1. pnpm dist (electron-builder)
  2. afterAllArtifactBuild hook runs automatically:
    • win-unpacked/ → Generates embedded/app.kbpkg
    • go build (with go:embed) → <productName>-<version>-<arch>.exe
    • Restores embedded/app.kbpkg to placeholder

Installation

pnpm add -D windows-portable-packager

Then run init to configure your project automatically:

npx windows-portable-packager init

This adds the afterAllArtifactBuild hook to your package.json automatically.

Usage — electron-builder integration (Recommended)

Add a single line to your package.json:

{
  "build": {
    "productName": "MyApp",
    "afterAllArtifactBuild": "windows-portable-packager/hooks/afterAllArtifactBuild"
  }
}

Values automatically detected by the hook:

  • App Name: build.productName
  • Version: version
  • Architecture: Target architecture (x64 → amd64, ia32 → 386, arm64 → arm64)
  • EXE Name: build.productName + ".exe"

Optional portablePackager config:

{
  "portablePackager": {
    "exeName": "MyApp.exe",
    "arch": "amd64",
    "splash": "build/splash.png",
    "splashMinDuration": 2000,
    "compression": "zstd",
    "level": 0
  }
}

| Field | Description | Default | |-------|-------------|---------| | exeName | Executable filename | <productName>.exe | | arch | Target architecture | amd64 | | splash | Splash image path (png/jpg/gif/apng) | — | | splashMinDuration | Minimum splash visible time in ms. 0 (or omitted) closes immediately when the child app spawns. | 0 | | compression | Compression format: zstd, gzip, xz | zstd | | level | Compression level (zstd: 1–19, gzip: 1–9, xz: 1–9, 0=default) | 0 |

Usage — manual build

1. Pack

windows-portable-packager pack dist/win-unpacked \
  -app MyApp -v 1.0.0 -arch amd64 \
  -o windows-portable-packager/embedded/app.kbpkg

2. Go build

cd windows-portable-packager
set GOARCH=amd64 && go build -ldflags="-s -w" -o dist/MyApp-1.0.0-amd64.exe .

CLI Commands

| Command | Description | |---------|-------------| | init | Add the electron-builder hook to your project's package.json | | pack <dir> | Compress build directory into a .kbpkg package | | run | Extract (if needed) and run the app (default) | | verify | Verify integrity of installed files | | clean | Delete previous installation versions | | version | Print version | | help | Print help |

Global Options

| Option | Description | |--------|-------------| | -v, --verbose | Enable verbose logging |

Pack Options

| Option | Description | |--------|-------------| | -app <name> | Application name (Required) | | -o <path> | Output file path (Default: <app>-<version>-<arch>.kbpkg) | | -v <version> | Version string (Required) | | -arch <arch> | Target architecture: amd64, 386, arm64 (Default: amd64) | | -exe <name> | Executable name (Default: <app>.exe) | | -splash <path> | Splash image path (png/jpg/gif/apng) | | -compression <fmt> | Compression format: zstd, gzip, xz (Default: zstd) | | -level <n> | Compression level (zstd: 1–19, gzip: 1–9, xz: 1–9, 0=default) | | -splash-min-duration <ms> | Minimum splash visible time in ms (Default: 0 = close immediately) |

Run Options

| Option | Description | |--------|-------------| | -package <path> | Path to .kbpkg file (Auto-searches if no embed) | | -exe <name> | Override executable name | | -splash <path> | Override splash image path |

Splash Screen

A splash image is displayed immediately on launch and stays visible during extraction. It closes automatically when the app starts.

Supported formats: PNG, JPG, GIF (animated), APNG (animated).

Embed via portablePackager.splash in your electron-builder package.json, or pass -splash at runtime.

By default the splash window closes the moment the child app spawns, which can be jarring on fast machines (the splash flashes for under 100ms). Set portablePackager.splashMinDuration (or pack -splash-min-duration <ms>) to keep the splash on screen for at least N milliseconds. Errors that abort the launcher always close the splash immediately and bypass this minimum, so a failing app cannot strand the user staring at a frozen splash.

.kbpkg Package Format

.kbpkg is a compressed tar archive. The first entry must be _manifest.json. Default compression is zstd; gzip and xz packages are auto-detected on unpack.

{
  "appName": "MyApp",
  "version": "1.0.0",
  "arch": "amd64",
  "exe": "MyApp.exe",
  "splash": "_splash.png",
  "timestamp": "2026-01-01T00:00:00Z",
  "files": {
    "MyApp.exe": "xxhash64hex...",
    "resources/app.asar": "xxhash64hex...",
    "locales/en-US.pak": "xxhash64hex..."
  }
}

Installation Path Layout

%APPDATA%\<productName>\
└── app\
    ├── 1.0.0\          ← Previous version (auto-deleted)
    └── 1.1.0\          ← Current version
        ├── _manifest.json
        ├── <productName>.exe
        └── resources\

Supported Architectures

| GOARCH | Windows Arch | electron-builder Target | |--------|--------------|-------------------------| | amd64 | x64 (64-bit) | x64 | | 386 | x86 (32-bit) | ia32 | | arm64 | ARM64 | arm64 |

Localization

UI messages (dialogs, log output) are automatically displayed in Korean or English based on the system locale. Korean (ko-*) is detected on Windows via GetUserDefaultLocaleName; all other locales fall back to English.

Troubleshooting

The launcher hangs on first run / nothing happens when I double-click

The launcher is a large unsigned executable (it embeds the entire app payload, often 100+ MB). Some security products treat such binaries as suspicious and run deep behavioural analysis before allowing execution. When that analysis stalls, the launcher process is blocked at the OS image-loader stage — before any of our code runs.

Symptoms:

  • Launcher window never appears
  • Process stays alive in Task Manager with steady CPU usage
  • No %APPDATA%\<productName>\app\ directory ever gets created
  • Even --help / -v produce no output

Built-in safeguards: The launcher includes two defenses to limit the damage of this scenario:

  • Single-instance mutex — additional double-clicks exit immediately instead of piling up zombie processes
  • 60-second startup watchdog — if the launcher cannot start the app within 60 seconds it terminates itself and shows a dialog

Resolutions, in order of preference:

  1. Add an exclusion in your security software for the launcher executable (or the entire output directory). The exact menu varies by product; look for "Exclusions", "Exceptions", "Trusted applications", "Allow list", or similar terms.
  2. Disable application sandboxing / behavioural analysis if a per-file exclusion is not enough. Many endpoint protection suites have a separate "isolation" or "deep analysis" feature that is not covered by simple file allow-lists.
  3. Sign the launcher with a code-signing certificate (self-signed is enough to clear most heuristics; an EV certificate clears Microsoft SmartScreen reputation as well). This is the only resolution that does not require user-side configuration.

If the launcher still hangs after these steps, please open an issue with:

  • Your OS version (winver)
  • The security software you have installed
  • Output of Get-Process <appname>* | Select Id, CPU, WorkingSet64, Threads while the launcher is hung

Requirements

  • Go must be installed for manual builds.
  • Go is not required when using the npm package with pre-built binaries.