#!/bin/bash # build-web.sh # Author: Matthew Raymer # Description: Web build script for TimeSafari application # This script handles the complete web build process including cleanup, # environment setup, Vite build, and optional Docker containerization. # # Usage: # ./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 # # NPM Script Equivalents: # npm run build:web # Development build # npm run build:web:test # Test environment build # npm run build:web:prod # Production environment build # npm run build:web:docker # Docker build # npm run build:web:docker:test # Test Docker build # npm run build:web:docker:prod # Production Docker build # # Exit Codes: # 1 - Web cleanup failed # 2 - Environment setup failed # 3 - Vite build failed # 4 - Docker build failed # 5 - Serve command failed # 6 - Invalid build mode # Exit on any error set -e # Source common utilities source "$(dirname "$0")/common.sh" # Default values BUILD_MODE="development" BUILD_ACTION="build" DOCKER_BUILD=false SERVE_BUILD=false # Function to show usage show_usage() { cat << EOF Usage: $0 [OPTIONS] OPTIONS: --dev, --development Build for development environment (default) --test Build for test environment --prod, --production Build for production environment --docker Build and create Docker container --docker:test Build for test environment and create Docker container --docker:prod Build for production environment and create Docker container --serve Build and serve locally --help Show this help message --verbose Enable verbose logging --env Show environment variables EXAMPLES: $0 # Development build $0 --test # Test environment build $0 --prod # Production environment build $0 --docker # Development + Docker $0 --docker:test # Test + Docker $0 --docker:prod # Production + Docker $0 --serve # Build and serve BUILD MODES: development: Starts Vite development server with hot reload (default) test: Optimized for testing with minimal minification production: Optimized for production with full minification and optimization EOF } # Function to parse web-specific arguments parse_web_args() { while [[ $# -gt 0 ]]; do case $1 in --dev|--development) BUILD_MODE="development" shift ;; --test) BUILD_MODE="test" shift ;; --prod|--production) BUILD_MODE="production" shift ;; --docker) DOCKER_BUILD=true shift ;; --docker:test) BUILD_MODE="test" DOCKER_BUILD=true shift ;; --docker:prod) BUILD_MODE="production" DOCKER_BUILD=true shift ;; --serve) SERVE_BUILD=true shift ;; --help) show_usage exit 0 ;; --verbose) VERBOSE=true shift ;; --env) print_env_vars "VITE_" exit 0 ;; *) log_warn "Unknown option: $1" shift ;; esac done } # Function to validate web build environment validate_web_environment() { log_info "Validating web build environment..." # Check if Node.js is available if ! check_command "node"; then log_error "Node.js is required but not installed" exit 2 fi # Check if npm is available if ! check_command "npm"; then log_error "npm is required but not installed" exit 2 fi # Check if Vite is available if ! check_command "npx"; then log_error "npx is required but not installed" exit 2 fi # Check if package.json exists if ! check_file "package.json"; then log_error "package.json not found in current directory" exit 2 fi log_success "Web build environment validated" } # Function to setup web-specific environment setup_web_environment() { log_info "Setting up web environment for $BUILD_MODE mode..." # Set NODE_ENV based on build mode case $BUILD_MODE in "production") export NODE_ENV="production" ;; "test") export NODE_ENV="test" ;; "development"|*) export NODE_ENV="development" ;; esac # Load environment-specific .env file if it exists local env_file=".env.$BUILD_MODE" if [ -f "$env_file" ]; then load_env_file "$env_file" else log_debug "No $env_file file found, using default environment" fi # Load .env file if it exists (fallback) if [ -f ".env" ]; then load_env_file ".env" fi log_success "Web environment configured for $BUILD_MODE mode" log_debug "NODE_ENV=$NODE_ENV" } # Function to execute Vite build execute_vite_build() { local mode="$1" log_info "Executing Vite build for $mode mode..." # Set git hash environment variable export VITE_GIT_HASH=$(git log -1 --pretty=format:%h) # Construct Vite build command local vite_cmd="npx vite build --config vite.config.web.mts" # Add mode if not development (development is default) if [ "$mode" != "development" ]; then vite_cmd="$vite_cmd --mode $mode" fi log_debug "Vite command: $vite_cmd" if ! measure_time eval "$vite_cmd"; then log_error "Vite build failed for $mode mode!" exit 3 fi log_success "Vite build completed for $mode mode" } # Function to execute Docker build execute_docker_build() { local mode="$1" log_info "Executing Docker build for $mode mode..." # Build Docker image with appropriate tags local docker_cmd="docker build" local image_tag="timesafari-web" # Add build arguments docker_cmd="$docker_cmd --build-arg BUILD_MODE=$mode" docker_cmd="$docker_cmd --build-arg NODE_ENV=$NODE_ENV" # Add image tag docker_cmd="$docker_cmd -t $image_tag:$mode" docker_cmd="$docker_cmd -t $image_tag:latest" # Add context docker_cmd="$docker_cmd ." log_debug "Docker command: $docker_cmd" if ! measure_time eval "$docker_cmd"; then log_error "Docker build failed for $mode mode!" exit 4 fi log_success "Docker build completed for $mode mode" log_info "Docker image available as: $image_tag:$mode" } # Function to start Vite development server start_dev_server() { log_info "Starting Vite development server..." # Set git hash environment variable export VITE_GIT_HASH=$(git log -1 --pretty=format:%h) # Construct Vite dev server command local vite_cmd="npx vite --config vite.config.web.mts" # Add mode if specified (though development is default) if [ "$BUILD_MODE" != "development" ]; then vite_cmd="$vite_cmd --mode $BUILD_MODE" fi log_debug "Vite dev server command: $vite_cmd" log_info "Starting development server on http://localhost:8080" log_info "Press Ctrl+C to stop the server" # Start the development server (this will block and run the server) # Note: This command will not return until the server is stopped exec $vite_cmd } # Function to serve build locally serve_build() { log_info "Serving build locally..." # Check if dist directory exists if [ ! -d "dist" ]; then log_error "dist directory not found. Build must be completed first." exit 5 fi # Use a simple HTTP server to serve the build if command -v python3 &> /dev/null; then log_info "Starting Python HTTP server on port 8080..." cd dist && python3 -m http.server 8080 elif command -v python &> /dev/null; then log_info "Starting Python HTTP server on port 8080..." cd dist && python -m SimpleHTTPServer 8080 elif command -v npx &> /dev/null; then log_info "Starting npx serve on port 8080..." npx serve -s dist -l 8080 else log_error "No suitable HTTP server found. Install Python or npx serve." exit 5 fi } # Parse command line arguments parse_web_args "$@" # Print build header print_header "TimeSafari Web Build Process" log_info "Starting web build process at $(date)" log_info "Build mode: $BUILD_MODE" log_info "Docker build: $DOCKER_BUILD" log_info "Serve build: $SERVE_BUILD" # Validate environment validate_web_environment # Setup environment for web build setup_build_env "web" # Setup application directories setup_app_directories # Setup web-specific environment setup_web_environment # Handle different build modes if [ "$BUILD_MODE" = "development" ] && [ "$DOCKER_BUILD" = false ] && [ "$SERVE_BUILD" = false ]; then # Development mode: Start dev server log_info "Development mode detected - starting development server" start_dev_server # Note: start_dev_server doesn't return, it runs the server elif [ "$SERVE_BUILD" = true ]; then # Serve mode: Build then serve log_info "Serve mode detected - building then serving" # Step 1: Clean dist directory log_info "Cleaning dist directory..." clean_build_artifacts "dist" # Step 2: Execute Vite build safe_execute "Vite build for $BUILD_MODE mode" "execute_vite_build $BUILD_MODE" || exit 3 # Step 3: Serve the build log_info "Starting local server..." serve_build # Note: serve_build doesn't return, it starts the server else # Build mode: Build (and optionally Docker) log_info "Build mode detected - building for $BUILD_MODE" # Step 1: Clean dist directory log_info "Cleaning dist directory..." clean_build_artifacts "dist" # Step 2: Execute Vite build safe_execute "Vite build for $BUILD_MODE mode" "execute_vite_build $BUILD_MODE" || exit 3 # Step 3: Execute Docker build if requested if [ "$DOCKER_BUILD" = true ]; then safe_execute "Docker build for $BUILD_MODE mode" "execute_docker_build $BUILD_MODE" || exit 4 fi # Print build summary log_success "Web build completed successfully!" log_info "Build output available in: dist/" if [ "$DOCKER_BUILD" = true ]; then log_info "Docker image available as: timesafari-web:$BUILD_MODE" fi print_footer "Web Build" # Exit with success exit 0 fi