You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							398 lines
						
					
					
						
							12 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							398 lines
						
					
					
						
							12 KiB
						
					
					
				| #!/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..." | |
|      | |
|     # Construct Vite build command | |
|     local vite_cmd="VITE_GIT_HASH=\$(git log -1 --pretty=format:%h) 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 run type checking based on build mode | |
| run_type_checking() { | |
|     local mode="$1" | |
|      | |
|     # Only run type checking for production and test builds | |
|     if [ "$mode" = "production" ] || [ "$mode" = "test" ]; then | |
|         log_info "Running TypeScript type checking for $mode mode..." | |
|          | |
|         if ! measure_time npm run type-check; then | |
|             log_error "TypeScript type checking failed for $mode mode!" | |
|             exit 2 | |
|         fi | |
|          | |
|         log_success "TypeScript type checking completed for $mode mode" | |
|     else | |
|         log_debug "Skipping TypeScript type checking for development mode" | |
|     fi | |
| } | |
| 
 | |
| # Function to start Vite development server | |
| start_dev_server() { | |
|     log_info "Starting Vite development server..." | |
|      | |
|     # Construct Vite dev server command | |
|     local vite_cmd="VITE_GIT_HASH=\$(git log -1 --pretty=format:%h) 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" | |
|      | |
|     # Start the development server (this will block and run the server) | |
|     eval "$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 server that supports SPA routing (serves index.html for all routes) | |
|     if command -v npx &> /dev/null; then | |
|         log_info "Starting npx serve with SPA support on port 8080..." | |
|         npx serve -s dist -l 8080 | |
|     elif command -v python3 &> /dev/null; then | |
|         log_warn "Python HTTP server doesn't support SPA routing. Routes like /discover, /account will return 404." | |
|         log_info "Starting Python HTTP server on port 8080..." | |
|         cd dist && python3 -m http.server 8080 | |
|     elif command -v python &> /dev/null; then | |
|         log_warn "Python HTTP server doesn't support SPA routing. Routes like /discover, /account will return 404." | |
|         log_info "Starting Python HTTP server on port 8080..." | |
|         cd dist && python -m SimpleHTTPServer 8080 | |
|     else | |
|         log_error "No suitable HTTP server found. Install npx serve or Python." | |
|         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" "$BUILD_MODE" | |
| 
 | |
| # 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: Run type checking (for production/test builds) | |
|     safe_execute "Type checking for $BUILD_MODE mode" "run_type_checking $BUILD_MODE" || exit 2 | |
|      | |
|     # Step 3: 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: Run type checking (for production/test builds) | |
|     safe_execute "Type checking for $BUILD_MODE mode" "run_type_checking $BUILD_MODE" || exit 2 | |
|      | |
|     # Step 3: 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  |