4.4 KiB
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
We don't need many Node.js features for VibeTunnel:
- No internationalization (ICU) support needed
- No npm package manager in the binary
- No inspector/debugging protocol
- No V8 snapshots or code cache
By building a custom Node.js without these features, we achieve a significantly smaller app bundle while maintaining full functionality.
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
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):
cd web
node build-custom-node.js --latest
This will:
- Download the latest Node.js source
- Configure it without unnecessary features
- Build with optimizations (
-Os,-flto, etc.) - Cache the result in
web/.node-builds/
To use the custom Node.js for building the executable:
cd web
npm run build -- --custom-node
Or directly:
node build-native.js --custom-node
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
Note: You may see a warning about "invalidating the code signature" during the strip process - this is expected and harmless since we re-sign immediately after.
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 in web/.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