Files
HostKeeper/docs/BUILD_SYSTEM.md
T
swanadiva c215d68c81 refactor: flatten docs/ — move V2 docs from docs/v2/ to docs/
- git mv docs/v2/*.md docs/ (11 planning documents)
- Remove empty docs/v2/ directory
- Update all references: AGENTS.md, CHANGELOG.md, README.md, ARCHITECTURE.md
- Fix outdated repo tree in ARCHITECTURE.md to match actual structure
2026-07-07 12:04:59 +07:00

12 KiB

Hostkeeper V2 — Build System

Status: V2 Planning Complete Last Updated: 2026-06-29


1. Build Overview

Hostkeeper V2 produces 4 platform outputs from a single codebase:

Platform Output Wrapper Backend
macOS (ARM64) .dmg Electron Go binary (embedded)
macOS (x64) .dmg Electron Go binary (embedded)
Windows (x64) .exe installer Electron Go binary (embedded)
Linux (x64) .AppImage Electron Go binary (embedded)
Android (ARM64) .aab / .apk WebView Go library (.aar)
iOS (ARM64) .ipa WKWebView Go framework (.xcframework)

2. Build Pipeline

┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  Go Build   │    │ Frontend    │    │  Electron   │    │  Platform   │
│  (backend)  │ →  │  Build      │ →  │  Package    │ →  │  Sign       │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘

Step 1: Go Backend Cross-Compile

# macOS ARM64
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 \
    go build -ldflags="-s -w" -o dist/hostkeeper-server .

# macOS x64
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 \
    go build -ldflags="-s -w" -o dist/hostkeeper-server .

# Windows x64
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 \
    go build -ldflags="-s -w" -o dist/hostkeeper-server.exe .

# Linux x64
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
    go build -ldflags="-s -w" -o dist/hostkeeper-server .

# Linux ARM64
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 \
    go build -ldflags="-s -w" -o dist/hostkeeper-server .

Notes:

  • CGO_ENABLED=0 — pure Go, no C dependencies
  • -ldflags="-s -w" — strip debug info, reduce binary size
  • Go binary size: ~15-20 MB (compressed)

Step 2: Frontend Build

cd app/frontend
npm ci
npm run build
# Output: app/frontend/dist/

Vite config (app/frontend/vite.config.ts):

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
    plugins: [react()],
    build: {
        outDir: 'dist',
        sourcemap: false,
        minify: 'terser',
        rollupOptions: {
            output: {
                manualChunks: {
                    xterm: ['@xterm/xterm', '@xterm/addon-fit'],
                    react: ['react', 'react-dom'],
                },
            },
        },
    },
    server: {
        proxy: {
            '/api': 'http://localhost:8080',
            '/ws': {
                target: 'ws://localhost:8080',
                ws: true,
            },
        },
    },
});

Step 3: Electron Package

# app/electron/electron-builder.yml
appId: com.hostkeeper.app
productName: Hostkeeper
copyright: Copyright © 2026

directories:
  output: ../../dist

files:
  - "**/*"
  - "!**/node_modules/*/{CHANGELOG.md,README.md,readme.md,LICENSE}"

extraResources:
  - from: "../backend/hostkeeper-server"
    to: "hostkeeper-server"
  - from: "../frontend/dist"
    to: "frontend"

mac:
  category: public.app-category.developer-tools
  icon: assets/icon.icns
  target:
    - dmg
    - zip
  hardenedRuntime: true
  notarize: true

win:
  icon: assets/icon.ico
  target:
    - nsis
  certificateFile: env.WIN_CERTIFICATE_FILE

linux:
  icon: assets/icon.png
  target:
    - AppImage
    - deb
  category: Development

nsis:
  oneClick: false
  allowToChangeInstallationDirectory: true

3. Mobile Build

Android

# Prerequisites:
# - Android SDK installed
# - Go 1.26+ with gomobile
# - Java 17+

# Install gomobile
go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init

# Build Go library
cd mobile/gomobile
gomobile bind -target=android -o=../android/app/libs/hostkeeper.aar \
    ./go/

# Build Android app
cd ../android
./gradlew assembleRelease
# Output: mobile/android/app/build/outputs/apk/release/app-release.apk

iOS

# Prerequisites:
# - Xcode 15+
# - Go 1.26+ with gomobile

# Build Go framework
cd mobile/gomobile
gomobile bind -target=ios -o=../ios/Hostkeeper/Hostkeeper.xcframework \
    ./go/

# Build iOS app
cd ../ios
xcodebuild -project Hostkeeper.xcodeproj \
    -scheme Hostkeeper \
    -sdk iphoneos \
    -configuration Release
# Output: mobile/ios/build/Release-iphoneos/Hostkeeper.app

4. Build Scripts

scripts/build.sh (Full Build)

#!/bin/bash
set -e

VERSION=${1:-"dev"}
PLATFORM=${2:-"all"}

echo "=== Building Hostkeeper V2 v${VERSION} ==="

# Step 1: Build Go backend
echo "Step 1: Building Go backend..."
cd app/backend

case $PLATFORM in
    macos|all)
        CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w -X main.version=${VERSION}" -o ../electron/hostkeeper-server .
        ;;
    windows|all)
        CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w -X main.version=${VERSION}" -o ../electron/hostkeeper-server.exe .
        ;;
    linux|all)
        CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -X main.version=${VERSION}" -o ../electron/hostkeeper-server .
        ;;
esac

cd ../..

# Step 2: Build frontend
echo "Step 2: Building frontend..."
cd app/frontend
npm ci
npm run build
cd ../..

# Step 3: Package Electron
echo "Step 3: Packaging Electron..."
cd app/electron

case $PLATFORM in
    macos)
        npx electron-builder --mac --arm64
        ;;
    windows)
        npx electron-builder --win --x64
        ;;
    linux)
        npx electron-builder --linux --x64
        ;;
    all)
        npx electron-builder --mac --win --linux
        ;;
esac

cd ../..

# Step 4: Generate checksums
echo "Step 4: Generating checksums..."
cd dist
shasum -a 256 *.dmg *.exe *.AppImage 2>/dev/null > checksums.txt

echo "=== Build complete ==="
echo "Output: dist/"
ls -la dist/

scripts/build-mobile.sh

#!/bin/bash
set -e

PLATFORM=${1:-"android"}

echo "=== Building Hostkeeper Mobile (${PLATFORM}) ==="

case $PLATFORM in
    android)
        cd mobile/gomobile
        gomobile bind -target=android -o=../android/app/libs/hostkeeper.aar ./go/
        cd ../android
        ./gradlew assembleRelease
        echo "APK: mobile/android/app/build/outputs/apk/release/"
        ;;
    ios)
        cd mobile/gomobile
        gomobile bind -target=ios -o=../ios/Hostkeeper/Hostkeeper.xcframework ./go/
        cd ../ios
        xcodebuild -project Hostkeeper.xcodeproj -scheme Hostkeeper -sdk iphoneos -configuration Release
        echo "IPA: mobile/ios/build/Release-iphoneos/"
        ;;
esac

echo "=== Mobile build complete ==="

5. Development Workflow

Quick Start

# Terminal 1: Go backend
cd app/backend
go run .

# Terminal 2: Frontend (with hot reload)
cd app/frontend
npm run dev

# Open browser: http://localhost:5173

With Electron

# Terminal 1: Go backend
cd app/backend
go run .

# Terminal 2: Frontend
cd app/frontend
npm run dev

# Terminal 3: Electron
cd app/electron
npm run dev
# Electron opens with hot reload

VS Code Launch Config

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Go Backend",
            "type": "go",
            "request": "launch",
            "program": "${workspaceFolder}/app/backend",
            "cwd": "${workspaceFolder}/app/backend"
        },
        {
            "name": "Electron",
            "type": "node",
            "request": "launch",
            "program": "${workspaceFolder}/app/electron/node_modules/.bin/electron",
            "args": ["."],
            "cwd": "${workspaceFolder}/app/electron"
        }
    ]
}

6. CI/CD (GitHub Actions)

# .github/workflows/build.yml
name: Build

on:
  push:
    tags: ['v*']
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: '1.26'
      - run: go test -race ./app/backend/...
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - run: cd app/frontend && npm ci && npm test

  build-macos:
    needs: test
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: '1.26'
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - run: ./scripts/build.sh ${{ github.ref_name }} macos
      - uses: actions/upload-artifact@v4
        with:
          name: hostkeeper-macos
          path: dist/*.dmg

  build-windows:
    needs: test
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: '1.26'
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - run: ./scripts/build.sh ${{ github.ref_name }} windows
      - uses: actions/upload-artifact@v4
        with:
          name: hostkeeper-windows
          path: dist/*.exe

  build-linux:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: '1.26'
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - run: ./scripts/build.sh ${{ github.ref_name }} linux
      - uses: actions/upload-artifact@v4
        with:
          name: hostkeeper-linux
          path: dist/*.AppImage

7. Binary Size Optimization

Technique Impact
-ldflags="-s -w" -20% Go binary size
UPX compression (optional) -60% Go binary size
Vite tree shaking -40% JS bundle size
Code splitting (lazy load) -30% initial load
Image optimization -50% icon sizes
Terser minification -30% JS size
CSS purging (Tailwind) -80% CSS size

Target sizes:

  • Go backend binary: ~15 MB (5 MB compressed)
  • Frontend dist: ~2 MB (500 KB compressed)
  • Electron package: ~200 MB total
  • Mobile APK: ~50 MB
  • Mobile IPA: ~60 MB

8. Version Management

Version Format

vMAJOR.MINOR.PATCH
  • MAJOR: Breaking changes (data format, API)
  • MINOR: New features
  • PATCH: Bug fixes

Version Injection

// In main.go
var version = "dev"

func main() {
    fmt.Printf("Hostkeeper v%s\n", version)
    // ...
}
# Build with version
go build -ldflags="-X main.version=v2.0.0" -o hostkeeper-server .

Changelog Format

## [v2.1.0] - 2026-07-15

### Added
- Port forwarding support (local, remote, dynamic)
- Import from ~/.ssh/config

### Changed
- Improved terminal performance with WebGL renderer

### Fixed
- Fixed SFTP upload progress not updating
- Fixed vault auto-lock not triggering on sleep

9. Code Signing

macOS

# Requires Apple Developer account + certificates
export CSC_LINK="path/to/certificate.p12"
export CSC_KEY_PASSWORD="certificate-password"

# electron-builder handles signing + notarization
npx electron-builder --mac --publish always

Windows

# Requires code signing certificate
export WIN_CERTIFICATE_FILE="path/to/certificate.pfx"
export WIN_CERTIFICATE_PASSWORD="certificate-password"

npx electron-builder --win --publish always

Linux

No code signing required. AppImage is self-contained.


10. Release Workflow

# 1. Update version
npm version minor  # or major, patch

# 2. Update CHANGELOG.md

# 3. Commit
git add .
git commit -m "chore: release v2.1.0"

# 4. Tag
git tag -a v2.1.0 -m "Release v2.1.0"

# 5. Push
git push origin main --tags

# 6. GitHub Actions builds + publishes artifacts

# 7. Create GitHub Release
gh release create v2.1.0 \
    --title "Hostkeeper v2.1.0" \
    --notes-file CHANGELOG.md \
    dist/*.dmg dist/*.exe dist/*.AppImage