38 KiB
Building TimeSafari
This guide explains how to build TimeSafari for different platforms using the comprehensive build system.
Prerequisites
- Node.js 18+ and npm
- Git
- For mobile builds: Xcode (macOS) or Android Studio
- For desktop builds: Additional build tools based on your OS
Forks
If you have forked this to make your own app, you'll want to customize the iOS & Android files. You can either edit existing ones, or you can remove the ios
and android
directories and regenerate them before the npx cap sync
step in each setup.
npx cap add android
npx cap add ios
You'll also want to edit the deep link configuration (see below).
Initial Setup
Install dependencies:
npm install
Web Development
Local Development
npm run dev
Web Build for Server
- Run the production build:
rm -rf dist
npm run build:web
The built files will be in the dist
directory.
- To test the production build locally:
You'll likely want to use test locations for the Endorser & image & partner servers; see "DEFAULT_ENDORSER_API_SERVER" & "DEFAULT_IMAGE_API_SERVER" & "DEFAULT_PARTNER_API_SERVER" below.
npm run serve
Web Build Commands
# Development builds
npm run build:web:dev # Development build with hot reload
npm run build:web:test # Test environment build
npm run build:web:prod # Production build
npm run build:web:serve # Production build with serve
# Docker builds
npm run build:web:docker # Docker development build
npm run build:web:docker:test # Docker test build
npm run build:web:docker:prod # Docker production build
Web Build Script Details
All web build commands use the ./scripts/build-web.sh
script, which provides:
Build Modes:
- Development: Starts Vite dev server with hot reload (default)
- Test: Optimized for testing with minimal minification
- Production: Optimized for production with full minification
Script Features:
- Environment Validation: Checks for Node.js, npm, npx, package.json
- Environment Setup: Loads
.env
files based on build mode - Clean Build: Removes previous
dist/
directory - Vite Build: Executes
npx vite build --config vite.config.web.mts
- Docker Support: Optional Docker containerization
- Local Serving: Built-in HTTP server for testing builds
Direct Script Usage:
# Direct script usage (no npm chaining)
./scripts/build-web.sh # Development build
./scripts/build-web.sh --dev # Development build (explicit)
./scripts/build-web.sh --test # Test environment build
./scripts/build-web.sh --prod # Production environment build
./scripts/build-web.sh --docker # Build with Docker containerization
./scripts/build-web.sh --docker:test # Test environment + Docker
./scripts/build-web.sh --docker:prod # Production environment + Docker
./scripts/build-web.sh --serve # Build and serve locally
./scripts/build-web.sh --help # Show help
./scripts/build-web.sh --verbose # Enable verbose logging
Script Flow:
- Environment Validation: Check prerequisites (Node.js, npm, etc.)
- Environment Setup: Load
.env
files, set NODE_ENV - Clean Dist: Remove previous build artifacts
- Vite Build: Execute Vite with appropriate configuration
- Optional Docker: Build Docker container if requested
- Optional Serve: Start local HTTP server if requested
Exit Codes:
1
- Web cleanup failed2
- Environment setup failed3
- Vite build failed4
- Docker build failed5
- Serve command failed6
- Invalid build mode
Compile and minify for test & production
-
If there are DB changes: before updating the test server, open browser(s) with current version to test DB migrations.
-
Update the ClickUp tasks & CHANGELOG.md & the version in package.json, run
npm install
. -
Run a build to make sure package-lock version is updated, linting works, etc:
npm install && npm run build
-
Commit everything (since the commit hash is used the app).
-
Put the commit hash in the changelog (which will help you remember to bump the version in the step later).
-
Tag with the new version, online or
git tag 1.0.2 && git push origin 1.0.2
. -
For test, build the app (because test server is not yet set up to build):
TIME_SAFARI_APP_TITLE="TimeSafari_Test" \
VITE_APP_SERVER=https://test.timesafari.app \
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F \
VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch \
VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app \
VITE_DEFAULT_PARTNER_API_SERVER=https://test-partner-api.endorser.ch \
VITE_DEFAULT_PUSH_SERVER=https://test.timesafari.app \
VITE_PASSKEYS_ENABLED=true npm run build:web
... and transfer to the test server:
rsync -azvu -e "ssh -i ~/.ssh/..." dist ubuntutest@test.timesafari.app:time-safari
(Let's replace that with a .env.development or .env.test file.)
(Note: The test BVC_MEETUPS_PROJECT_CLAIM_ID does not resolve as a URL because it's only in the test DB and the prod redirect won't redirect there.)
- For prod, get on the server and run the correct build:
... and log onto the server:
-
pkgx +npm sh
-
cd crowd-funder-for-time-pwa && git checkout master && git pull && git checkout 1.0.2 && npm install && npm run build:web && cd -
(The plain npm run build:web
uses the .env.production file.)
-
Back up the time-safari/dist folder & deploy:
mv time-safari/dist time-safari-dist-prev-2 && mv crowd-funder-for-time-pwa/dist time-safari/
-
Record the new hash in the changelog. Edit package.json to increment version & add "-beta",
npm install
, commit, and push. Also record what version is on production.
Docker Deployment
The application can be containerized using Docker for consistent deployment across environments.
Prerequisites
- Docker installed on your system
- Docker Compose (optional, for multi-container setups)
Building the Docker Image
- Build the Docker image:
docker build -t timesafari:latest .
- For development builds with specific environment variables:
docker build --build-arg NODE_ENV=development -t timesafari:dev .
Running the Container
- Run the container:
docker run -d -p 80:80 timesafari:latest
- For development with hot-reloading:
docker run -d -p 80:80 -v $(pwd):/app timesafari:dev
Using Docker Compose
Create a docker-compose.yml
file:
version: '3.8'
services:
timesafari:
build: .
ports:
- "80:80"
environment:
- NODE_ENV=production
restart: unless-stopped
Run with Docker Compose:
docker-compose up -d
Docker Commands
# Docker operations
npm run docker:up # Start Docker services
npm run docker:up:test # Start test environment
npm run docker:up:prod # Start production environment
npm run docker:down # Stop Docker services
npm run docker:logs # View logs
Production Deployment
For production deployment, consider the following:
- Use specific version tags instead of 'latest'
- Implement health checks
- Configure proper logging
- Set up reverse proxy with SSL termination
- Use Docker secrets for sensitive data
Example production deployment:
# Build with specific version
docker build -t timesafari:1.0.0 .
# Run with production settings
docker run -d \
--name timesafari \
-p 80:80 \
--restart unless-stopped \
-e NODE_ENV=production \
timesafari:1.0.0
Troubleshooting Docker
-
Container fails to start
- Check logs:
docker logs <container_id>
- Verify port availability
- Check environment variables
- Check logs:
-
Build fails
- Ensure all dependencies are in package.json
- Check Dockerfile syntax
- Verify build context
-
Performance issues
- Monitor container resources:
docker stats
- Check nginx configuration
- Verify caching settings
- Monitor container resources:
Desktop Build (Electron)
TimeSafari's Electron build system provides comprehensive desktop application packaging and distribution capabilities across Windows, macOS, and Linux platforms. The system supports multiple build modes, environment configurations, and package formats.
Quick Start
Development Build
# Start development build (runs app)
npm run build:electron:dev
# Development build only
npm run build:electron --dev
Production Build
# Production build for all platforms
npm run build:electron:prod
# Platform-specific production builds
npm run build:electron:windows:prod
npm run build:electron:mac:prod
npm run build:electron:linux:prod
Package-Specific Builds
# AppImage for Linux
npm run build:electron:appimage:prod
# DEB package for Debian/Ubuntu
npm run build:electron:deb:prod
# DMG for macOS
npm run build:electron:dmg:prod
Single Instance Enforcement
The Electron app enforces single-instance operation to prevent:
- Database corruption from multiple instances
- Resource conflicts and performance issues
- User confusion from multiple windows
Behavior:
- Only one instance can run at a time
- Attempting to launch a second instance shows a user-friendly dialog
- The existing window is focused and restored if minimized
- Second instance exits gracefully
Implementation:
- Uses Electron's
requestSingleInstanceLock()
API - Handles
second-instance
events to focus existing window - Shows informative dialog explaining why only one instance is allowed
Direct Script Usage
# Direct script usage (no npm chaining)
./scripts/build-electron.sh --dev # Development build
./scripts/build-electron.sh --test # Test build
./scripts/build-electron.sh --prod # Production build
./scripts/build-electron.sh --prod --windows # Windows production
./scripts/build-electron.sh --test --appimage # Linux AppImage test
./scripts/build-electron.sh --dev --mac # macOS development
./scripts/build-electron.sh --prod --dmg # macOS DMG production
Build Architecture
The Electron build process follows a multi-stage approach:
1. Web Build (Vite) → 2. Capacitor Sync → 3. TypeScript Compile → 4. Package
Stage 1: Web Build
- Vite builds web assets with Electron-specific configuration
- Environment variables loaded based on build mode
- Assets optimized for desktop application
Stage 2: Capacitor Sync
- Copies web assets to Electron app directory
- Syncs Capacitor configuration and plugins
- Prepares native module bindings
Stage 3: TypeScript Compile
- Compiles Electron main process TypeScript
- Rebuilds native modules for target platform
- Generates production-ready JavaScript
Stage 4: Package Creation
- Creates platform-specific installers
- Generates distribution packages
- Signs applications (when configured)
Build Modes
Development Mode
Purpose: Local development and testing
Command: npm run build:electron:dev
Features:
- Hot reload enabled
- Debug tools available
- Development logging
- Unoptimized assets
Testing Mode
Purpose: Staging and testing environments
Command: npm run build:electron -- --mode test
Features:
- Test API endpoints
- Staging configurations
- Optimized for testing
- Debug information available
Production Mode
Purpose: Production deployment
Command: npm run build:electron -- --mode production
Features:
- Production optimizations
- Code minification
- Security hardening
- Performance optimizations
Platform-Specific Builds
Windows Builds
Target Platforms: Windows 10/11 (x64) Package Formats: NSIS installer, portable executable
# Windows development build
npm run build:electron:windows:dev
# Windows test build
npm run build:electron:windows:test
# Windows production build
npm run build:electron:windows:prod
Configuration:
- NSIS installer with custom options
- Desktop and Start Menu shortcuts
- Elevation permissions for installation
- Custom installation directory support
macOS Builds
Target Platforms: macOS 10.15+ (x64, arm64) Package Formats: DMG installer, app bundle
# macOS development build
npm run build:electron:mac:dev
# macOS test build
npm run build:electron:mac:test
# macOS production build
npm run build:electron:mac:prod
Configuration:
- Universal binary (x64 + arm64)
- DMG installer with custom branding
- App Store compliance (when configured)
- Code signing support
Linux Builds
Target Platforms: Ubuntu 18.04+, Debian 10+, Arch Linux Package Formats: AppImage, DEB, RPM
# Linux development build
npm run build:electron:linux:dev
# Linux test build
npm run build:electron:linux:test
# Linux production build
npm run build:electron:linux:prod
Configuration:
- AppImage for universal distribution
- DEB package for Debian-based systems
- RPM package for Red Hat-based systems
- Desktop integration
Package-Specific Builds
AppImage Package
Format: Self-contained Linux executable Distribution: Universal Linux distribution
# AppImage development build
npm run build:electron:appimage:dev
# AppImage test build
npm run build:electron:appimage:test
# AppImage production build
npm run build:electron:appimage:prod
Features:
- Single file distribution
- No installation required
- Portable across Linux distributions
- Automatic updates support
DEB Package
Format: Debian package installer Distribution: Debian-based Linux systems
# DEB development build
npm run build:electron:deb:dev
# DEB test build
npm run build:electron:deb:test
# DEB production build
npm run build:electron:deb:prod
Features:
- Native package management
- Dependency resolution
- System integration
- Easy installation/uninstallation
DMG Package
Format: macOS disk image Distribution: macOS systems
# DMG development build
npm run build:electron:dmg:dev
# DMG test build
npm run build:electron:dmg:test
# DMG production build
npm run build:electron:dmg:prod
Features:
- Native macOS installer
- Custom branding and layout
- Drag-and-drop installation
- Code signing support
Build Scripts Reference
Main Build Scripts
# Development builds
npm run build:electron:dev # Development build and run
npm run build:electron --dev # Development build only
# Testing builds
npm run build:electron:test # Test environment build
# Production builds
npm run build:electron:prod # Production environment build
Platform-Specific Scripts
# Windows builds
npm run build:electron:windows # Windows production build
npm run build:electron:windows:dev # Windows development build
npm run build:electron:windows:test # Windows test build
npm run build:electron:windows:prod # Windows production build
# macOS builds
npm run build:electron:mac # macOS production build
npm run build:electron:mac:dev # macOS development build
npm run build:electron:mac:test # macOS test build
npm run build:electron:mac:prod # macOS production build
# Linux builds
npm run build:electron:linux # Linux production build
npm run build:electron:linux:dev # Linux development build
npm run build:electron:linux:test # Linux test build
npm run build:electron:linux:prod # Linux production build
Package-Specific Scripts
# AppImage builds
npm run build:electron:appimage # Linux AppImage production build
npm run build:electron:appimage:dev # AppImage development build
npm run build:electron:appimage:test # AppImage test build
npm run build:electron:appimage:prod # AppImage production build
# DEB builds
npm run build:electron:deb # Debian package production build
npm run build:electron:deb:dev # DEB development build
npm run build:electron:deb:test # DEB test build
npm run build:electron:deb:prod # DEB production build
# DMG builds
npm run build:electron:dmg # macOS DMG production build
npm run build:electron:dmg:dev # DMG development build
npm run build:electron:dmg:test # DMG test build
npm run build:electron:dmg:prod # DMG production build
Direct Script Usage
All npm scripts use the underlying ./scripts/build-electron.sh
script:
# Direct script usage examples
./scripts/build-electron.sh --dev # Development build
./scripts/build-electron.sh --test # Test build
./scripts/build-electron.sh --prod # Production build
./scripts/build-electron.sh --prod --windows # Windows production
./scripts/build-electron.sh --test --appimage # Linux AppImage test
./scripts/build-electron.sh --dev --mac # macOS development
./scripts/build-electron.sh --prod --dmg # macOS DMG production
Utility Scripts
# Cleanup scripts
npm run clean:electron # Clean Electron build artifacts
# Development scripts
npm run electron:dev # Start development server
npm run electron:dev-full # Full development workflow
npm run electron:setup # Setup Electron environment
Build Output Structure
Development Build
electron/
├── app/ # Web assets
├── build/ # Compiled TypeScript
├── dist/ # Build artifacts (empty in dev)
└── node_modules/ # Dependencies
Production Build
electron/
├── app/ # Web assets
├── build/ # Compiled TypeScript
├── dist/ # Distribution packages
│ ├── TimeSafari.exe # Windows executable
│ ├── TimeSafari.dmg # macOS installer
│ ├── TimeSafari.AppImage # Linux AppImage
│ └── TimeSafari.deb # Debian package
└── node_modules/ # Dependencies
Code Signing and Notarization
macOS Code Signing
For public distribution on macOS, you need to code sign and notarize your app:
- Set up environment variables:
export CSC_LINK=/path/to/your/certificate.p12
export CSC_KEY_PASSWORD=your_certificate_password
export APPLE_ID=your_apple_id
export APPLE_ID_PASSWORD=your_app_specific_password
- Build with signing:
npm run build:electron:mac:prod
Windows Code Signing
For Windows distribution, configure Authenticode signing:
- Set up environment variables:
export CSC_LINK=/path/to/your/certificate.p12
export CSC_KEY_PASSWORD=your_certificate_password
- Build with signing:
npm run build:electron:windows:prod
Running the Packaged App
Linux
- AppImage: Make executable and run
chmod +x electron/dist/TimeSafari-*.AppImage
./electron/dist/TimeSafari-*.AppImage
- DEB: Install and run
sudo dpkg -i electron/dist/timesafari_*_amd64.deb
timesafari
macOS
.app
bundle: Double-clickTimeSafari.app
in Finder.dmg
installer:- Double-click the
.dmg
file - Drag the app to your Applications folder
- Launch from Applications
- Double-click the
Note: If you get a security warning when running the app:
- Right-click the app
- Select "Open"
- Click "Open" in the security dialog
Windows
- NSIS installer: Run the
.exe
installer and follow the setup wizard - Portable: Extract and run the portable executable
Troubleshooting
Common Build Issues
TypeScript Compilation Errors:
# Clean and rebuild
npm run clean:electron
cd electron && npm run build
Native Module Issues:
# Rebuild native modules
cd electron && npm run build
Asset Copy Issues:
# Verify Capacitor sync
npx cap sync electron
Platform-Specific Issues
Windows:
- Ensure Windows Build Tools installed
- Check NSIS installation
- Verify code signing certificates
macOS:
- Install Xcode Command Line Tools
- Configure code signing certificates
- Check app notarization requirements
Linux:
- Install required packages (rpm-tools, etc.)
- Check AppImage dependencies
- Verify desktop integration
Performance Optimization
Build Performance
- Use concurrent TypeScript compilation
- Optimize asset copying
- Minimize file system operations
- Cache node_modules between builds
Runtime Performance
- Optimize main process initialization
- Minimize startup dependencies
- Use lazy loading for features
- Monitor memory usage and implement proper cleanup
Security Considerations
Production Builds
- Disable developer tools
- Remove debug information
- Enable security policies
- Implement sandboxing
Update Security
- Secure update channels
- Package integrity verification
- Rollback capabilities
For detailed documentation, see docs/electron-build-patterns.md.
Mobile Builds (Capacitor)
iOS Build
Prerequisites: macOS with Xcode installed
Automated Build Script
The recommended way to build for iOS is using the automated build script:
# Standard build and open Xcode
./scripts/build-ios.sh
# Build with specific version numbers
./scripts/build-ios.sh --version 1.0.3 --build-number 35
# Build without opening Xcode (for CI/CD)
./scripts/build-ios.sh --no-xcode
# Show all available options
./scripts/build-ios.sh --help
The script handles all the necessary steps including:
- Environment setup and validation
- Web asset building
- Capacitor synchronization
- iOS asset generation
- Version number updates
- Xcode project opening
iOS Build Commands
# Standard builds
npm run build:ios # Standard build and open Xcode
npm run build:ios:dev # Development build
npm run build:ios:test # Test build
npm run build:ios:prod # Production build
# Auto-run builds
npm run build:ios:test:run # Test build with auto-run
npm run build:ios:prod:run # Production build with auto-run
# Debug and release builds
npm run build:ios:debug # Debug build
npm run build:ios:debug:run # Debug build with auto-run
npm run build:ios:release # Release build
npm run build:ios:release:run # Release build with auto-run
# Additional operations
npm run build:ios:studio # Open in Xcode Studio
npm run build:ios:ipa # Generate IPA file
npm run build:ios:clean # Clean build artifacts
npm run build:ios:sync # Sync Capacitor
npm run build:ios:assets # Generate assets
npm run build:ios:deploy # Deploy to device/simulator
Manual Build Process
If you need to build manually or want to understand the individual steps:
First-time iOS Configuration
- Generate certificates inside XCode.
- Right-click on App and under Signing & Capabilities set the Team.
Each Release
- First time (or if dependencies change):
-
pkgx +rubygems.org sh
-
... and you may have to fix these, especially with pkgx:
gem_path=$(which gem)
shortened_path="${gem_path:h:h}"
export GEM_HOME=$shortened_path
export GEM_PATH=$shortened_path
-
Build the web assets & update ios:
rm -rf dist npm run build:web npm run build:capacitor npx cap sync ios
- If that fails with "Could not find..." then look at the "gem_path" instructions above.
-
Copy the assets:
# It makes no sense why capacitor-assets will not run without these but it actually changes the contents. mkdir -p ios/App/App/Assets.xcassets/AppIcon.appiconset echo '{"images":[]}' > ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json mkdir -p ios/App/App/Assets.xcassets/Splash.imageset echo '{"images":[]}' > ios/App/App/Assets.xcassets/Splash.imageset/Contents.json npx capacitor-assets generate --ios
-
Bump the version to match Android & package.json:
cd ios/App && xcrun agvtool new-version 35 && perl -p -i -e "s/MARKETING_VERSION = .*;/MARKETING_VERSION = 1.0.2;/g" App.xcodeproj/project.pbxproj && cd - # Unfortunately this edits Info.plist directly. #xcrun agvtool new-marketing-version 0.4.5
-
Open the project in Xcode:
npx cap open ios
-
Use Xcode to build and run on simulator or device.
- Select Product -> Destination with some Simulator version. Then click the run arrow.
- Release
- Someday: Under "General" we want to rename a bunch of things to "Time Safari"
- Choose Product -> Destination -> Any iOS Device
- Choose Product -> Archive
- This will trigger a build and take time, needing user's "login" keychain password (user's login password), repeatedly.
- If it fails with
building for 'iOS', but linking in dylib (.../.pkgx/zlib.net/v1.3.0/lib/libz.1.3.dylib) built for 'macOS'
then run XCode outside that terminal (ie. not withnpx cap open ios
). - Click Distribute -> App Store Connect
- In AppStoreConnect, add the build to the distribution: remove the current build with the "-" when you hover over it, then "Add Build" with the new build.
- May have to go to App Review, click Submission, then hover over the build and click "-".
- It can take 15 minutes for the build to show up in the list of builds.
- You'll probably have to "Manage" something about encryption, disallowed in France.
- Then "Save" and "Add to Review" and "Resubmit to App Review".
Android Build
Prerequisites: Android Studio with Java SDK installed
Automated Build Script
The recommended way to build for Android is using the automated build script:
# Standard build and open Android Studio
./scripts/build-android.sh
# Build with specific version numbers
./scripts/build-android.sh --version 1.0.3 --build-number 35
# Build without opening Android Studio (for CI/CD)
./scripts/build-android.sh --no-studio
# Show all available options
./scripts/build-android.sh --help
Android Build Commands
# Standard builds
npm run build:android # Standard build and open Android Studio
npm run build:android:dev # Development build
npm run build:android:test # Test build
npm run build:android:prod # Production build
# Auto-run builds
npm run build:android:test:run # Test build with auto-run
npm run build:android:prod:run # Production build with auto-run
# Debug and release builds
npm run build:android:debug # Debug build
npm run build:android:debug:run # Debug build with auto-run
npm run build:android:release # Release build
npm run build:android:release:run # Release build with auto-run
# Additional operations
npm run build:android:studio # Open in Android Studio
npm run build:android:apk # Generate APK
npm run build:android:aab # Generate AAB (App Bundle)
npm run build:android:clean # Clean build artifacts
npm run build:android:sync # Sync Capacitor
npm run build:android:assets # Generate assets
npm run build:android:deploy # Deploy to device/emulator
Manual Build Process
-
Build the web assets:
rm -rf dist npm run build:web npm run build:capacitor
-
Update Android project with latest build:
npx cap sync android
-
Copy the assets
npx capacitor-assets generate --android
-
Bump version to match iOS & package.json: android/app/build.gradle
-
Open the project in Android Studio:
npx cap open android
-
Use Android Studio to build and run on emulator or device.
Android Build from the console
cd android
./gradlew clean
./gradlew build -Dlint.baselines.continue=true
cd -
... or, to create the aab
file, bundle
instead of build
:
./gradlew bundleDebug -Dlint.baselines.continue=true
... or, to create a signed release:
- Setup by adding the app/gradle.properties.secrets file (see properties at top of app/build.gradle) and the app/time-safari-upload-key-pkcs12.jks file
- In app/build.gradle, bump the versionCode and maybe the versionName
- Then
bundleRelease
:
cd android
./gradlew bundleRelease -Dlint.baselines.continue=true
cd -
... and find your aab
file at app/build/outputs/bundle/release
At play.google.com/console:
-
Go to the Testing Track (eg. Closed).
-
Click "Create new release".
-
Upload the
aab
file. -
Hit "Next".
-
Save, go to "Publishing Overview" as prompted, and click "Send changes for review".
-
Note that if you add testers, you have to go to "Publishing Overview" and send those changes or your (closed) testers won't see it.
Capacitor Operations
# Build Capacitor assets
npm run build:capacitor
# Sync Capacitor
npm run build:capacitor:sync
Testing
Web Testing
# Run web tests
npm run test:web
Mobile Testing
# Run mobile tests
npm run test:mobile
# Android tests
npm run test:android
# iOS tests
npm run test:ios
Device Checks
# Check Android device connection
npm run check:android-device
# Check iOS device/simulator
npm run check:ios-device
Test Prerequisites
# Test prerequisites
npm run test:prerequisites
Auto-Run System
The auto-run system provides automated development workflows:
# Auto-run with default settings
npm run auto-run
# Auto-run test environment
npm run auto-run:test
# Auto-run production environment
npm run auto-run:prod
# Platform-specific auto-run
npm run auto-run:ios
npm run auto-run:android
npm run auto-run:electron
Cleaning
# Clean Android
npm run clean:android
# Clean iOS
npm run clean:ios
# Clean Electron
npm run clean:electron
Fastlane Integration
iOS Fastlane
# Beta release
npm run fastlane:ios:beta
# App Store release
npm run fastlane:ios:release
Android Fastlane
# Beta release
npm run fastlane:android:beta
# Play Store release
npm run fastlane:android:release
Code Quality
# Lint code
npm run lint
# Fix linting issues
npm run lint-fix
Build Architecture
Web Build Process
- Environment Setup: Load platform-specific environment variables
- Asset Building: Vite builds optimized web assets
- PWA Generation: Service worker and manifest creation
- Output: Production-ready files in
dist/
directory
Electron Build Process
- Web Build: Vite builds web assets for Electron
- Capacitor Sync: Copies assets to Electron app directory
- TypeScript Compile: Compiles main process code
- Native Module Rebuild: Rebuilds native dependencies
- Package Creation: Generates platform-specific installers
Mobile Build Process
- Web Build: Vite builds web assets
- Capacitor Sync: Syncs with native platforms
- Asset Generation: Creates platform-specific assets
- Native Build: Platform-specific compilation
- Package Creation: APK/IPA generation
Environment Configuration
Environment Files
.env.development
- Development environment.env.test
- Testing environment.env.production
- Production environment
Key Environment Variables
# API Servers
VITE_DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch
VITE_DEFAULT_IMAGE_API_SERVER=https://image-api.timesafari.app
VITE_DEFAULT_PARTNER_API_SERVER=https://partner-api.endorser.ch
# Platform Configuration
VITE_PLATFORM=web|electron|capacitor
VITE_APP_SERVER=https://timesafari.app
# Feature Flags
VITE_PASSKEYS_ENABLED=true
Android Configuration for deep links
You must add the following intent filter to the android/app/src/main/AndroidManifest.xml
file:
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="timesafari.app" />
<data android:scheme="http" android:host="timesafari.app" />
</intent-filter>
... though when we tried that most recently it failed to 'build' the APK with: http(s) scheme and host attribute are missing, but are required for Android App Links [AppLinkUrlError]
Troubleshooting
Common Issues
Build Failures
# Clean and rebuild
npm run clean:electron
npm run build:electron:dev
Native Module Issues
# Rebuild native modules
cd electron && npm run build
Asset Issues
# Regenerate assets
npm run build:ios:assets
npm run build:android:assets
Platform-Specific Issues
Windows
- Ensure Windows Build Tools installed
- Check NSIS installation
- Verify code signing certificates
macOS
- Install Xcode Command Line Tools
- Configure code signing certificates
- Check app notarization requirements
Linux
- Install required packages (rpm-tools, etc.)
- Check AppImage dependencies
- Verify desktop integration
iOS
- Install Xcode and Command Line Tools
- Configure signing certificates
- Check provisioning profiles
Android
- Install Android Studio and SDK
- Configure signing keys
- Check device/emulator setup
Additional Resources
- Electron Build Patterns
- iOS Build Scripts
- Android Build Scripts
- Web Build Scripts
- Build Troubleshooting
Appendix: Build System Organization
Build Process Overview
TimeSafari's build system follows a multi-stage process that prepares assets, combines scripts, and generates platform-specific outputs.
Pre-Build Preparation
1. Service Worker Script Preparation
# Optional: Format third-party service worker scripts
npx prettier --write ./sw_scripts/
What this does:
- Formats cryptographic libraries (
nacl.js
,noble-curves.js
,noble-hashes.js
, etc.) - These scripts are automatically combined during the build process
- Improves readability and makes version control diffs cleaner
- Note: This is optional and only needed when updating third-party scripts
2. Automatic Pre-Build Steps
The prebuild
script automatically runs before any build:
"prebuild": "eslint --ext .js,.ts,.vue --ignore-path .gitignore src && node sw_combine.js && node scripts/copy-wasm.js"
What happens automatically:
- ESLint: Checks and fixes code formatting in
src/
- Script Combination:
sw_combine.js
combines allsw_scripts/*.js
files intosw_scripts-combined.js
- WASM Copy:
copy-wasm.js
copies SQLite WASM files topublic/wasm/
Build Architecture
Web Build Process:
1. Pre-Build: ESLint + Script Combination + WASM Copy
2. Environment Setup: Load .env files, set NODE_ENV
3. Vite Build: Bundle web assets with PWA support
4. Service Worker: Inject combined scripts into PWA
5. Output: Production-ready files in dist/
Electron Build Process:
1. Web Build: Vite builds web assets for Electron
2. Capacitor Sync: Copies assets to Electron app directory
3. TypeScript Compile: Compiles main process code
4. Native Module Rebuild: Rebuilds native dependencies
5. Package Creation: Generates platform-specific installers
Mobile Build Process:
1. Web Build: Vite builds web assets
2. Capacitor Sync: Syncs with native platforms
3. Asset Generation: Creates platform-specific assets
4. Native Build: Platform-specific compilation
5. Package Creation: APK/IPA generation
Service Worker Architecture
Script Organization:
sw_scripts/
- Individual third-party scriptssw_combine.js
- Combines scripts into single filesw_scripts-combined.js
- Combined service worker (317KB, 10K+ lines)vite.config.utils.mts
- PWA configuration using combined script
PWA Integration:
// vite.config.utils.mts
pwaConfig: {
strategies: "injectManifest",
filename: "sw_scripts-combined.js", // Uses our combined script
// ... manifest configuration
}
What Gets Combined:
nacl.js
- NaCl cryptographic librarynoble-curves.js
- Elliptic curve cryptography (177KB)noble-hashes.js
- Cryptographic hash functions (91KB)safari-notifications.js
- Safari-specific notificationsadditional-scripts.js
- Additional service worker functionality
Environment Configuration
Environment Files:
.env.development
- Development environment.env.test
- Testing environment.env.production
- Production environment
Key Environment Variables:
# API Servers
VITE_DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch
VITE_DEFAULT_IMAGE_API_SERVER=https://image-api.timesafari.app
VITE_DEFAULT_PARTNER_API_SERVER=https://partner-api.endorser.ch
# Platform Configuration
VITE_PLATFORM=web|electron|capacitor
VITE_APP_SERVER=https://timesafari.app
# Feature Flags
VITE_PASSKEYS_ENABLED=true
Build Output Structure
Web Build:
dist/
├── index.html # Main HTML file
├── assets/ # Bundled JavaScript/CSS
├── sw.js # Service worker (injected)
├── manifest.webmanifest # PWA manifest
└── wasm/ # SQLite WASM files
Electron Build:
electron/
├── app/ # Web assets
├── build/ # Compiled TypeScript
├── dist/ # Distribution packages
│ ├── TimeSafari.exe # Windows executable
│ ├── TimeSafari.dmg # macOS installer
│ ├── TimeSafari.AppImage # Linux AppImage
│ └── TimeSafari.deb # Debian package
└── node_modules/ # Dependencies
Manual vs Automatic Steps
Manual Steps (Developer Responsibility):
- Database migration testing
- Service worker script formatting (optional)
- Version updates and changelog
- Environment-specific builds
Automatic Steps (Build System):
- Code linting and formatting
- Script combination
- Asset optimization
- Package creation
- Service worker injection
This architecture ensures consistent builds across all platforms while providing flexibility for platform-specific optimizations and manual quality assurance steps.