Custom Node.js Build
Motivation
VibeTunnel uses Node.js Single Executable Applications (SEA) to create a standalone terminal server. However, the standard Node.js binary is quite large:- Standard Node.js binary: ~110MB
- Custom minimal Node.js: ~43MB (61% reduction)
- Final executable size: ~45MB (down from ~105MB)
- Final app size impact: Reduces app from ~130MB to ~88MB
- No internationalization (ICU) support needed
- No npm package manager in the binary
- No inspector/debugging protocol
- No V8 snapshots or code cache
Build Behavior
Debug Mode (Xcode)
- Uses system Node.js for faster iteration
- No custom Node.js compilation required
- Build output shows:
"Debug build - using system Node.js for faster builds"
- If a custom Node.js was previously built, it will be reused for consistency
Release Mode (Xcode)
- Automatically builds custom minimal Node.js on first run
- Compilation takes 10-20 minutes but is cached for future builds
- Uses the custom Node.js to create a smaller executable
- Build output shows version and size comparison
Prerequisites
Required Build Tools
For optimal build performance, the following tools are required:- Ninja: Build system for faster compilation (significantly faster than Make)
- ccache: Compiler cache to speed up rebuilds
Installation
- macOS:
brew install ninja ccache
- Linux:
apt-get install ninja-build ccache
(or equivalent for your distribution)
Build Automation
Release Builds
The release script (mac/scripts/release.sh
) automatically checks for and builds custom Node.js if needed. You don’t need to manually build it before releases.
Manual Custom Node.js Build
To build the custom Node.js manually (outside of Xcode):- Download the latest Node.js source
- Configure it without unnecessary features
- Build with optimizations (
-Os
,-flto
, etc.) - Cache the result in
web/.node-builds/
Build Process Details
Automatic Detection
The build system automatically searches for custom Node.js builds in.node-builds/
when --custom-node
is passed without a path. It finds the most recent build by checking directory modification times.
Code Signing on macOS
When building the executable:- The Node.js binary is injected with our JavaScript code (SEA process)
- The binary is stripped to remove debug symbols
- The executable is re-signed with an ad-hoc signature
Technical Details
Features Disabled
--without-intl
- Removes internationalization support--without-npm
- Excludes npm from the binary--without-corepack
- Removes package manager wrapper--without-inspector
- Disables debugging protocol--without-node-snapshot
- Skips V8 snapshot (~2-3MB)--without-node-code-cache
- Skips code cache (~1-2MB)
Optimization Flags
-Os
- Optimize for size-flto
- Link-time optimization-ffunction-sections
/-fdata-sections
- Enable dead code elimination-Wl,-dead_strip
- Remove unused code at link time
Build Cache
Custom Node.js builds are stored inweb/.node-builds/
and are excluded from git via .gitignore
. The build system automatically detects and reuses existing builds.
File Locations
- Build script:
web/build-custom-node.js
- Native executable builder:
web/build-native.js
- Xcode integration:
mac/scripts/build-web-frontend.sh
- Build output:
web/.node-builds/node-v*-minimal/
- Final executable:
web/native/vibetunnel
Troubleshooting
Custom Node.js not detected
- Ensure the build completed successfully: check for
.node-builds/node-v*-minimal/out/Release/node
- In Debug mode, the system will use custom Node.js if already built
- In Release mode, it will build custom Node.js automatically if not present
Code signature warnings
The warning “changes being made to the file will invalidate the code signature” is expected and handled automatically. The build process re-signs the executable after all modifications.Known Limitations
- The custom Node.js build process takes 10-20 minutes on first run
- Cross-compilation is not supported - you must build on the target platform
- The custom build excludes some features that may be needed by certain npm packages
- Native module compatibility issues may occur when mixing Node.js versions