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

bundlerbus

v1.1.0

Published

Universal native bindings bundler for Bun's --compile flag

Downloads

16

Readme

📦🚍 Bundlerbus

Native bindings bundler for Bun's --compile flag

npm version npm downloads (monthly) npm downloads (total) license GitHub stars GitHub forks GitHub issues GitHub last commit Repo size THYPRESS.ORG

Compile Bun projects with Sharp, Canvas, or other native modules into single-file executables. Drop-in replacement for bun build --compile.

The Problem → The Solution

# ❌ This fails with native modules
bun build --compile ./app.js --outfile ./app.exe
# Error: Cannot find module '/path/to/$bunfs/node_modules/sharp/...'

# ✅ This works
bundlerbus ./app.js --outfile ./app.exe

How: Extracts your app + node_modules to a real filesystem at runtime. Native bindings see real paths instead of Bun's virtual $bunfs.

Trade-off: Larger bundles (~100MB+), ~2-3s first-run delay. Subsequent runs: < 50ms. Zero configuration.


Quick Start

# Install
npm install -g bundlerbus

# Use (same flags as Bun)
bundlerbus ./src/cli.js --target bun-windows-x64 --outfile ./dist/app.exe

# That's it. Your app with native modules now compiles.

Forwards all Bun flags: --target, --minify, --define, --windows-icon, etc.


How It Works

Build Time (your machine):
  [Your Code] + [node_modules] → payload.tar.gz → compiled.exe

First Run (user's machine):
  compiled.exe → Extract to cache (~/.cache/app/1.0.0/) → Launch app
                 └─ Native modules see real paths ✅

Subsequent Runs:
  compiled.exe → Check hash → Cache hit → Launch (< 50ms)

Cache locations (automatic fallback):

  • Windows: %LOCALAPPDATA%\your-app\1.0.0\
  • macOS: ~/Library/Application Support/your-app/1.0.0/
  • Linux: ~/.cache/your-app/1.0.0/

Falls back to system temp or current directory if standard location is locked.


Entry Point Detection

Bundlerbus finds your entry point automatically:

  1. Explicit argument: bundlerbus ./src/cli.js
  2. package.json"bin" field (if single entry)
  3. package.json"main" field
  4. Convention: ./index.js, ./src/index.js, or ./main.js

Multiple binaries? Specify explicitly:

bundlerbus ./src/cli.js --outfile ./dist/app.exe
bundlerbus ./src/server.js --outfile ./dist/server.exe

What Gets Packed

Strategy: Pack everything for maximum reliability.

Included:

  • All project files (except node_modules/ and dist/ during root scan)
  • Complete node_modules/ directory with zero filtering

Excluded:

  • dist/ directory (build output)

Why pack everything?

  • Zero configuration required
  • No missing dependencies at runtime
  • Works with any project structure
  • No "forgot to include X" errors

Trade-off: Larger bundles, but 100% reliability. Native modules have complex dependency chains—missing a single .dll causes runtime failures.


Examples

Basic

bundlerbus ./index.js --outfile ./dist/app.exe
bundlerbus ./src/main.js --minify --outfile ./build/app

Cross-Platform Build Script

// build.js
import { spawnSync } from 'child_process';
import pkg from './package.json' assert { type: 'json' };

const platforms = {
  win32: ['--target', 'bun-windows-x64', '--outfile', './dist/app-win.exe'],
  darwin: ['--target', 'bun-darwin-arm64', '--outfile', './dist/app-mac'],
  linux: ['--target', 'bun-linux-x64', '--outfile', './dist/app-linux']
};

Object.entries(platforms).forEach(([name, flags]) => {
  console.log(`Building for ${name}...`);
  const result = spawnSync('bundlerbus', ['./src/cli.js', ...flags], {
    stdio: 'inherit'
  });
  if (result.status !== 0) process.exit(1);
});

With Windows Metadata

const args = [
  './src/cli.js',
  '--windows-icon=./icon.ico',
  '--windows-publisher="Your Company"',
  `--windows-version="${pkg.version}"`,
  '--target=bun-windows-x64',
  '--outfile=./dist/app.exe'
];

spawnSync('bundlerbus', args, { stdio: 'inherit' });

Platform Support

| Platform | Status | Testing | |----------|--------|---------| | Windows x64 | ✅ Production | Fully tested (Sharp, Canvas) | | macOS Intel/ARM | ⚠️ Beta | Code ready, needs community testing | | Linux x64 | ⚠️ Beta | Code ready, needs community testing |


Troubleshooting

Native Module Not Found

Error: Cannot find module 'sharp'

Fix: Ensure module is in dependencies (not devDependencies), run npm install before building.


Permission Denied

[BOOTSTRAP ERROR] Cannot find writable cache directory!

Fix: Bundlerbus tries 3 locations automatically. Check logs to see which were tested. User needs write access to at least one.


Concurrent Starts (First Run)

[BOOTSTRAP LOCK] Waiting for other instance to finish extraction...

Not an error. If multiple instances start during first extraction:

  • First instance extracts (~2-3s)
  • Others wait safely
  • All start normally after extraction completes

This is race condition protection working correctly.


Files In Use (Development Only)

[BOOTSTRAP ERROR] Cannot delete cache - files are in use!

Cause: Old instance still running (common when rebuilding without closing).

Fix:

  1. Close all running instances
  2. Wait a few seconds
  3. Try again

Note: Only happens in dev with same version number. Production uses different versions → different cache dirs → no conflict.


Wrong Entry Point

[FAILURE] Could not determine entry point

Fix: Specify explicitly or add to package.json:

bundlerbus ./src/index.js [flags...]
{
  "bin": "./src/cli.js"
}

Comparison to Bun's --compile

| Feature | Bun --compile | Bundlerbus | |---------|---------------|------------| | Pure JS projects | ✅ | ✅ | | Native bindings | ❌ | ✅ | | Startup time | Instant | ~50ms cached, ~2s first | | Bundle size | Smaller | Larger (~100MB+) | | Configuration | None | None | | Reliability with natives | 0% | 100% |


Technical Deep Dive

Native modules use __dirname to locate binaries:

// sharp/lib/constructor.js
const libvips = require(path.join(__dirname, '../build/Release/sharp.node'));

In Bun's $bunfs: __dirname$bunfs/node_modules/sharp/lib (virtual, unreadable by native code)

After extraction: __dirnameC:\Users\...\AppData\Local\app\1.0.0\node_modules\sharp\lib (real path ✅)

Bundlerbus sets NODE_PATH to extracted node_modules:

process.env.NODE_PATH = '/cache/path/node_modules'

Modern native modules use relative loading:

  • Linux: RPATH=$ORIGIN
  • macOS: @loader_path
  • Windows: Same-directory search

No LD_LIBRARY_PATH manipulation needed. Works with macOS SIP.

Smart cwd management:

With path arguments (drag-and-drop, CLI):

app.exe ./content  # cwd unchanged, app gets correct path

Without paths (double-click):

app.exe --verbose  # cwd = exe folder (portable behavior)

Allows apps to work as both CLI tools and portable executables.

SHA-256 hash-based:

  • Payload hash stored in .hash file
  • Checked on every run (< 1ms)
  • Mismatch triggers re-extraction
  • Version number doesn't matter—any change detected

File-based locking prevents corruption if multiple instances start during extraction.


Debug Logging

Comprehensive logging for troubleshooting:

[BOOTSTRAP DEBUG] Platform: win32
[BOOTSTRAP CACHE] ✓ Selected writable cache directory: C:\...\AppData\Local\app\1.0.0
[BOOTSTRAP LOCK] ✓ Acquired lock (PID: 12345)
[BOOTSTRAP] Extracting archive...
[BOOTSTRAP] Extracted 500 files...
[BOOTSTRAP] ✓ Extraction complete: 3564 files, 0 directories
[BOOTSTRAP TIMING] Bootstrap completed in 2895ms

All errors include actionable solutions.


Manual Cache Cleanup

# Windows
del /s /q %LOCALAPPDATA%\your-app

# macOS
rm -rf ~/Library/Application\ Support/your-app

# Linux
rm -rf ~/.cache/your-app

Old versions accumulate but don't interfere. Safe to delete manually.


Limitations

| Limitation | Impact | Justification | |-----------|--------|---------------| | Large bundles (~100MB+) | Storage | Native modules + dependencies. Reliability > size. | | First-run delay (~2-3s) | UX | Extraction cost. Cached runs: < 50ms. | | Disk space (2x bundle) | Storage | Uncompressed cache. Users can clean old versions. |


Roadmap

  • [x] SHA-256 cache validation
  • [x] Cross-platform cache dirs
  • [x] Race condition protection
  • [x] Fallback cache locations
  • [ ] Smart filtering (opt-in "files" field support)
  • [ ] bundlerbus clean command
  • [ ] Delta extraction (only changed files)
  • [ ] Lazy loading (extract on require())

Related Projects

Built for THYPRESS — zero-config static site generator with Sharp image processing.

  • THYPRESS Launcher — https://github.com/thypress/launcher

Using Bundlerbus? Add your project here! 🚍


License

MIT


Credits

Created by @phteocos. Inspired by Electron ASAR, designed for Bun's native binding challenges.