WIP: add Electron platform configuration to Capacitor

- Add electron platform section to capacitor.config.json
- Configure deep linking with timesafari:// scheme
- Set up build options for macOS, Windows, and Linux
- Configure output directory and file inclusion
- Add platform-specific build targets (DMG, NSIS, AppImage)
- Support both x64 and arm64 architectures for macOS
- Set appropriate app categories for each platform

This enables building TimeSafari as a native desktop application
using Capacitor's Electron platform while maintaining existing
mobile and web functionality.
This commit is contained in:
Matthew Raymer
2025-06-25 12:50:46 +00:00
parent ca014a52de
commit ea0f49d5c3
29 changed files with 420 additions and 1987 deletions

View File

@@ -27,7 +27,6 @@ All scripts automatically handle environment variables for different build types
|----------|------|-------------|-----------------|--------------|
| `web` | web | true | false | `build-web.sh` |
| `capacitor` | capacitor | false | true | `build-capacitor.sh` |
| `electron` | electron | false | true | `build-electron.sh` |
#### Automatic Environment Setup
@@ -96,10 +95,7 @@ exit 0
### Build Scripts
- **`build-electron.sh`**: Complete Electron build process
- **`build-android.sh`**: Complete Android build process
- **`build-electron-linux.sh`**: Linux Electron packaging (AppImage, .deb)
- **`build-electron-mac.sh`**: macOS Electron packaging (standard, universal)
### Development Scripts
@@ -152,10 +148,8 @@ print_footer "Script Title"
```
### Building Applications
```bash
# Build Electron
./scripts/build-electron.sh
```bash
# Build Android
./scripts/build-android.sh
@@ -170,19 +164,21 @@ print_footer "Script Title"
```
### Development Workflows
```bash
# Start Electron development
./scripts/electron-dev.sh
# Start development
npm run dev
```
## Environment Variable Features
### Automatic Setup
All scripts automatically configure the correct environment variables for their build type:
```bash
# Electron builds automatically get:
export VITE_PLATFORM=electron
# Capacitor builds automatically get:
export VITE_PLATFORM=capacitor
export VITE_PWA_ENABLED=false
export VITE_DISABLE_PWA=true
export DEBUG_MIGRATIONS=0
@@ -214,7 +210,6 @@ validate_env_vars "VITE_API_URL" "VITE_DEBUG" || exit 1
View current environment variables with the `--env` flag:
```bash
./scripts/build-electron.sh --env
./scripts/test-env.sh --env
```

View File

@@ -1,82 +0,0 @@
#!/bin/bash
# build-electron-linux.sh
# Author: Matthew Raymer
# Description: Electron Linux build script for TimeSafari application
# This script builds Electron packages for Linux with support for different formats.
#
# Usage: ./scripts/build-electron-linux.sh [deb|prod]
# - No argument: Builds AppImage
# - deb: Builds .deb package
# - prod: Builds production AppImage
#
# Exit Codes:
# 1 - Build failed
# 2 - Invalid argument
# Exit on any error
set -e
# Source common utilities
source "$(dirname "$0")/common.sh"
# Parse command line arguments
parse_args "$@"
# Parse build type argument
BUILD_TYPE=${1:-"appimage"}
PRODUCTION=false
case $BUILD_TYPE in
"deb")
BUILD_TARGET="deb"
log_info "Building .deb package"
;;
"prod")
BUILD_TARGET="AppImage"
PRODUCTION=true
log_info "Building production AppImage"
;;
"appimage"|"")
BUILD_TARGET="AppImage"
log_info "Building AppImage"
;;
*)
log_error "Invalid build type: $BUILD_TYPE"
log_error "Usage: $0 [deb|prod]"
exit 2
;;
esac
# Print build header
print_header "TimeSafari Electron Linux Build"
log_info "Starting Linux build process at $(date)"
log_info "Build type: $BUILD_TYPE"
log_info "Build target: $BUILD_TARGET"
log_info "Production mode: $PRODUCTION"
# Setup environment for Electron build
setup_build_env "electron" "$PRODUCTION"
# Setup application directories
setup_app_directories
# Load environment from .env file if it exists
load_env_file ".env"
# Step 1: Build Electron application
if [ "$PRODUCTION" = true ]; then
safe_execute "Building production Electron application" "npm run build:electron-prod" || exit 1
else
safe_execute "Building Electron application" "npm run build:electron" || exit 1
fi
# Step 2: Build package
safe_execute "Building Linux package" "npx electron-builder --linux $BUILD_TARGET" || exit 1
# Print build summary
log_success "Linux build completed successfully!"
log_info "Package type: $BUILD_TARGET"
print_footer "Linux Build"
# Exit with success
exit 0

View File

@@ -1,74 +0,0 @@
#!/bin/bash
# build-electron-mac.sh
# Author: Matthew Raymer
# Description: Electron Mac build script for TimeSafari application
# This script builds Electron packages for macOS with support for universal builds.
#
# Usage: ./scripts/build-electron-mac.sh [universal]
# - No argument: Builds standard Mac package
# - universal: Builds universal Mac package (Intel + Apple Silicon)
#
# Exit Codes:
# 1 - Build failed
# 2 - Invalid argument
# Exit on any error
set -e
# Source common utilities
source "$(dirname "$0")/common.sh"
# Parse command line arguments
parse_args "$@"
# Parse build type argument
BUILD_TYPE=${1:-"standard"}
UNIVERSAL=false
case $BUILD_TYPE in
"universal")
UNIVERSAL=true
log_info "Building universal Mac package (Intel + Apple Silicon)"
;;
"standard"|"")
log_info "Building standard Mac package"
;;
*)
log_error "Invalid build type: $BUILD_TYPE"
log_error "Usage: $0 [universal]"
exit 2
;;
esac
# Print build header
print_header "TimeSafari Electron Mac Build"
log_info "Starting Mac build process at $(date)"
log_info "Build type: $BUILD_TYPE"
log_info "Universal build: $UNIVERSAL"
# Setup environment for Electron build (production mode for packaging)
setup_build_env "electron" "true"
# Setup application directories
setup_app_directories
# Load environment from .env file if it exists
load_env_file ".env"
# Step 1: Build Electron application
safe_execute "Building Electron application" "npm run build:electron-prod" || exit 1
# Step 2: Build package
if [ "$UNIVERSAL" = true ]; then
safe_execute "Building universal Mac package" "npx electron-builder --mac --universal" || exit 1
else
safe_execute "Building Mac package" "npx electron-builder --mac" || exit 1
fi
# Print build summary
log_success "Mac build completed successfully!"
log_info "Package type: $([ "$UNIVERSAL" = true ] && echo "Universal" || echo "Standard")"
print_footer "Mac Build"
# Exit with success
exit 0

View File

@@ -1,148 +0,0 @@
const fs = require('fs');
const path = require('path');
console.log('Starting electron build process...');
// Define paths
const electronDistPath = path.join(__dirname, '..', 'dist-electron');
const wwwPath = path.join(electronDistPath, 'www');
// Create www directory if it doesn't exist
if (!fs.existsSync(wwwPath)) {
fs.mkdirSync(wwwPath, { recursive: true });
}
// Copy the Vite-built index.html to www directory
const viteIndexPath = path.join(electronDistPath, 'index.html');
const wwwIndexPath = path.join(wwwPath, 'index.html');
if (fs.existsSync(viteIndexPath)) {
console.log('Copying Vite-built index.html to www directory...');
fs.copyFileSync(viteIndexPath, wwwIndexPath);
// Remove the original index.html from dist-electron root
fs.unlinkSync(viteIndexPath);
console.log('Moved index.html to www directory');
} else {
console.error('Vite-built index.html not found at:', viteIndexPath);
process.exit(1);
}
// Copy assets directory if it exists in dist-electron
const assetsSrc = path.join(electronDistPath, 'assets');
const assetsDest = path.join(wwwPath, 'assets');
if (fs.existsSync(assetsSrc)) {
console.log('Moving assets directory to www...');
if (fs.existsSync(assetsDest)) {
fs.rmSync(assetsDest, { recursive: true, force: true });
}
fs.renameSync(assetsSrc, assetsDest);
console.log('Moved assets directory to www');
}
// Copy favicon if it exists
const faviconSrc = path.join(electronDistPath, 'favicon.ico');
const faviconDest = path.join(wwwPath, 'favicon.ico');
if (fs.existsSync(faviconSrc)) {
console.log('Moving favicon to www...');
fs.renameSync(faviconSrc, faviconDest);
console.log('Moved favicon to www');
}
// Remove service worker files from www directory
const swFilesToRemove = [
'sw.js',
'sw.js.map',
'workbox-*.js',
'workbox-*.js.map',
'registerSW.js',
'manifest.webmanifest'
];
console.log('Removing service worker files...');
swFilesToRemove.forEach(pattern => {
const files = fs.readdirSync(wwwPath).filter(file =>
file.match(new RegExp(pattern.replace(/\*/g, '.*')))
);
files.forEach(file => {
const filePath = path.join(wwwPath, file);
console.log(`Removing ${filePath}`);
try {
fs.unlinkSync(filePath);
} catch (err) {
console.warn(`Could not remove ${filePath}:`, err.message);
}
});
});
// Also check and remove from assets directory
if (fs.existsSync(assetsDest)) {
swFilesToRemove.forEach(pattern => {
const files = fs.readdirSync(assetsDest).filter(file =>
file.match(new RegExp(pattern.replace(/\*/g, '.*')))
);
files.forEach(file => {
const filePath = path.join(assetsDest, file);
console.log(`Removing ${filePath}`);
try {
fs.unlinkSync(filePath);
} catch (err) {
console.warn(`Could not remove ${filePath}:`, err.message);
}
});
});
}
// Verify the final index.html structure
const finalIndexContent = fs.readFileSync(wwwIndexPath, 'utf8');
console.log('Final index.html structure:');
console.log('- Has CSS link:', finalIndexContent.includes('<link rel="stylesheet"'));
console.log('- Has main script:', finalIndexContent.includes('main.electron.js'));
console.log('- No service worker references:', !finalIndexContent.includes('serviceWorker'));
// Copy main process files to the correct location
console.log('Setting up main process files...');
// The main process files are already in the correct location
// Just verify they exist and are ready
const mainPath = path.join(electronDistPath, 'main.js');
const preloadPath = path.join(electronDistPath, 'preload.js');
if (fs.existsSync(mainPath)) {
console.log('Main process file ready at:', mainPath);
} else {
console.error('Main process file not found at:', mainPath);
process.exit(1);
}
if (fs.existsSync(preloadPath)) {
console.log('Preload script ready at:', preloadPath);
} else {
console.warn('Preload script not found at:', preloadPath);
}
// Clean up any remaining files in dist-electron root (except main.js, preload.js, and www directory)
const remainingFiles = fs.readdirSync(electronDistPath);
remainingFiles.forEach(file => {
if (file !== 'main.js' && file !== 'preload.js' && file !== 'www') {
const filePath = path.join(electronDistPath, file);
console.log(`Removing remaining file: ${file}`);
try {
if (fs.statSync(filePath).isDirectory()) {
fs.rmSync(filePath, { recursive: true, force: true });
} else {
fs.unlinkSync(filePath);
}
} catch (err) {
console.warn(`Could not remove ${filePath}:`, err.message);
}
}
});
console.log('Electron build process completed successfully');
console.log('Final structure:');
console.log('- Main process:', path.join(electronDistPath, 'main.js'));
console.log('- Preload script:', path.join(electronDistPath, 'preload.js'));
console.log('- Web assets:', path.join(electronDistPath, 'www'));

View File

@@ -1,53 +0,0 @@
#!/bin/bash
# build-electron.sh
# Author: Matthew Raymer
# Description: Electron build script for TimeSafari application
# This script handles the complete Electron build process including cleanup,
# TypeScript compilation, Vite build, and Electron-specific setup.
#
# Exit Codes:
# 1 - Cleanup failed
# 2 - TypeScript compilation failed
# 3 - Vite build failed
# 4 - Electron build script failed
# Exit on any error
set -e
# Source common utilities
source "$(dirname "$0")/common.sh"
# Parse command line arguments
parse_args "$@"
# Print build header
print_header "TimeSafari Electron Build Process"
log_info "Starting Electron build process at $(date)"
# Setup environment for Electron build
setup_build_env "electron"
# Setup application directories
setup_app_directories
# Load environment from .env file if it exists
load_env_file ".env"
# Step 1: Clean previous builds
safe_execute "Cleaning previous builds" "npm run clean:electron" || exit 1
# Step 2: Compile TypeScript for Electron
safe_execute "Compiling TypeScript for Electron" "npx tsc -p tsconfig.electron.json" || exit 2
# Step 3: Build with Vite
safe_execute "Building with Vite" "npx vite build --config vite.config.electron.mts" || exit 3
# Step 4: Run Electron build script
safe_execute "Running Electron build script" "node scripts/build-electron.js" || exit 4
# Print build summary
log_success "Electron build completed successfully!"
print_footer "Electron Build"
# Exit with success
exit 0

View File

@@ -176,16 +176,6 @@ setup_build_env() {
log_debug "Set VITE_GIT_HASH=$git_hash"
case $build_type in
"electron")
export VITE_PLATFORM=electron
export VITE_PWA_ENABLED=false
export VITE_DISABLE_PWA=true
export DEBUG_MIGRATIONS=0
if [ "$production" = true ]; then
export NODE_ENV=production
log_debug "Set production mode for Electron"
fi
;;
"capacitor")
export VITE_PLATFORM=capacitor
export VITE_PWA_ENABLED=false
@@ -227,7 +217,6 @@ setup_app_directories() {
# Create build directories if they don't exist
mkdir -p dist
mkdir -p dist-electron
log_debug "Application directories created"
}

View File

@@ -1,44 +0,0 @@
#!/bin/bash
# electron-dev.sh
# Author: Matthew Raymer
# Description: Electron development script for TimeSafari application
# This script builds the application and starts Electron for development.
#
# Exit Codes:
# 1 - Build failed
# 2 - Electron start failed
# Exit on any error
set -e
# Source common utilities
source "$(dirname "$0")/common.sh"
# Parse command line arguments
parse_args "$@"
# Print dev header
print_header "TimeSafari Electron Development"
log_info "Starting Electron development at $(date)"
# Setup environment for Electron development
setup_build_env "electron"
# Setup application directories
setup_app_directories
# Load environment from .env file if it exists
load_env_file ".env"
# Step 1: Build the application
safe_execute "Building application" "npm run build" || exit 1
# Step 2: Start Electron
safe_execute "Starting Electron" "electron ." || exit 2
# Print dev summary
log_success "Electron development session ended"
print_footer "Electron Development"
# Exit with success
exit 0

View File

@@ -17,37 +17,34 @@ parse_args "$@"
print_header "Environment Variable Test"
log_info "Testing environment variable handling at $(date)"
# Test 1: Electron environment
log_info "Test 1: Setting up Electron environment..."
setup_build_env "electron"
print_env_vars "VITE_"
# Test 2: Capacitor environment
log_info "Test 2: Setting up Capacitor environment..."
# Test 1: Capacitor environment
log_info "Test 1: Setting up Capacitor environment..."
setup_build_env "capacitor"
print_env_vars "VITE_"
echo ""
# Test 3: Web environment
log_info "Test 3: Setting up Web environment..."
# Test 2: Web environment
log_info "Test 2: Setting up Web environment..."
setup_build_env "web"
print_env_vars "VITE_"
echo ""
# Test 4: Production Electron environment
log_info "Test 4: Setting up Production Electron environment..."
setup_build_env "electron" "true"
# Test 3: Production Capacitor environment
log_info "Test 3: Setting up Production Capacitor environment..."
setup_build_env "capacitor" "true"
print_env_vars "VITE_"
print_env_vars "NODE_ENV"
echo ""
# Test 5: Application directories
log_info "Test 5: Setting up application directories..."
# Test 4: Application directories
log_info "Test 4: Setting up application directories..."
setup_app_directories
# Test 6: Load .env file (if it exists)
log_info "Test 6: Loading .env file..."
# Test 5: Load .env file (if it exists)
log_info "Test 5: Loading .env file..."
load_env_file ".env"
# Test 7: Git hash
log_info "Test 7: Getting git hash..."
# Test 6: Git hash
log_info "Test 6: Getting git hash..."
GIT_HASH=$(get_git_hash)
log_info "Git hash: $GIT_HASH"