Add production build optimizations to Vite configuration; set target, output directory, and minification options for improved performance

This commit is contained in:
Torsten Schulz (local)
2025-10-18 21:19:07 +02:00
parent bda61c0ed4
commit 06a65e9130
16 changed files with 4210 additions and 1 deletions

663
deploy.sh Executable file
View File

@@ -0,0 +1,663 @@
#!/bin/bash
# =============================================================================
# TimeClock v3 - Deployment Script für Ubuntu 22.04
# =============================================================================
# Dieses Script automatisiert das Deployment auf dem Produktionsserver
#
# Verwendung:
# ./deploy.sh [OPTION]
#
# Optionen:
# install - Erste Installation (inkl. System-Setup)
# update - Update einer bestehenden Installation
# rollback - Rollback zur vorherigen Version
# backup - Erstelle Backup der Datenbank
# status - Zeige Status der Services
# logs - Zeige Logs
# help - Zeige diese Hilfe
#
# =============================================================================
set -e # Bei Fehler abbrechen
# Farben für Output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Konfiguration
PROJECT_NAME="TimeClock"
PROJECT_DIR="/var/www/timeclock"
BACKEND_DIR="$PROJECT_DIR/backend"
FRONTEND_DIR="$PROJECT_DIR/frontend"
DOMAIN="stechuhr3.tsschulz.de"
BACKUP_DIR="/var/backups/timeclock"
LOG_DIR="/var/log/timeclock"
# Service-Name (PM2 oder systemd)
USE_PM2=true # true für PM2, false für systemd
SERVICE_NAME="timeclock"
# Webserver (nginx oder apache2)
WEBSERVER="apache2" # "nginx" oder "apache2"
# =============================================================================
# Hilfsfunktionen
# =============================================================================
print_info() {
echo -e "${BLUE} $1${NC}"
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
print_header() {
echo ""
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE} $1${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
echo ""
}
check_root() {
if [ "$EUID" -eq 0 ]; then
print_error "Bitte führe dieses Script NICHT als root aus!"
print_info "Verwende stattdessen sudo für einzelne Befehle."
exit 1
fi
}
check_command() {
if ! command -v $1 &> /dev/null; then
print_error "$1 ist nicht installiert!"
return 1
fi
return 0
}
# =============================================================================
# Installation - Erste Einrichtung
# =============================================================================
install_dependencies() {
print_header "Installiere System-Abhängigkeiten"
print_info "Aktualisiere Paketquellen..."
sudo apt update
print_info "Installiere Node.js 20.x..."
if ! check_command node; then
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
else
print_success "Node.js ist bereits installiert ($(node -v))"
fi
if [ "$WEBSERVER" = "nginx" ]; then
print_info "Installiere Nginx..."
if ! check_command nginx; then
sudo apt install -y nginx
else
print_success "Nginx ist bereits installiert"
fi
else
print_info "Installiere Apache2..."
if ! check_command apache2; then
sudo apt install -y apache2
else
print_success "Apache2 ist bereits installiert"
fi
print_info "Aktiviere Apache2-Module..."
sudo a2enmod proxy proxy_http ssl rewrite headers deflate expires
fi
print_info "Installiere Certbot..."
if ! check_command certbot; then
if [ "$WEBSERVER" = "nginx" ]; then
sudo apt install -y certbot python3-certbot-nginx
else
sudo apt install -y certbot python3-certbot-apache
fi
else
print_success "Certbot ist bereits installiert"
fi
if [ "$USE_PM2" = true ]; then
print_info "Installiere PM2..."
if ! check_command pm2; then
sudo npm install -g pm2
else
print_success "PM2 ist bereits installiert"
fi
fi
print_success "Alle Abhängigkeiten installiert!"
}
setup_directories() {
print_header "Erstelle Verzeichnisse"
print_info "Erstelle Projekt-Verzeichnis..."
sudo mkdir -p $PROJECT_DIR
sudo chown -R $USER:$USER $PROJECT_DIR
print_info "Erstelle Log-Verzeichnis..."
sudo mkdir -p $LOG_DIR
sudo chown -R www-data:www-data $LOG_DIR
print_info "Erstelle Backup-Verzeichnis..."
sudo mkdir -p $BACKUP_DIR
sudo chown -R $USER:$USER $BACKUP_DIR
print_success "Verzeichnisse erstellt!"
}
copy_project_files() {
print_header "Kopiere Projekt-Dateien"
CURRENT_DIR=$(pwd)
print_info "Kopiere Backend..."
rsync -a --exclude 'node_modules' "$CURRENT_DIR/backend/" "$BACKEND_DIR/"
print_info "Kopiere Frontend..."
rsync -a --exclude 'node_modules' --exclude 'dist' "$CURRENT_DIR/frontend/" "$FRONTEND_DIR/"
print_success "Projekt-Dateien kopiert!"
}
setup_backend() {
print_header "Setup Backend"
cd $BACKEND_DIR
print_info "Installiere Backend-Dependencies..."
npm install --production
if [ ! -f .env ]; then
print_warning ".env Datei nicht gefunden!"
if [ -f env.production.template ]; then
print_info "Kopiere Template..."
cp env.production.template .env
print_warning "WICHTIG: Bitte bearbeite $BACKEND_DIR/.env und passe die Werte an!"
read -p "Drücke Enter wenn du fertig bist..."
else
print_error "Auch env.production.template nicht gefunden!"
exit 1
fi
else
print_success ".env bereits vorhanden"
fi
print_success "Backend Setup abgeschlossen!"
}
setup_frontend() {
print_header "Setup Frontend"
cd $FRONTEND_DIR
print_info "Installiere Frontend-Dependencies..."
npm install
print_info "Erstelle Produktions-Build..."
npm run build
if [ ! -d "dist" ]; then
print_error "Build fehlgeschlagen - dist/ Verzeichnis nicht gefunden!"
exit 1
fi
print_success "Frontend Build erstellt!"
}
setup_webserver() {
if [ "$WEBSERVER" = "nginx" ]; then
print_header "Setup Nginx"
WEBSERVER_CONF="/etc/nginx/sites-available/$DOMAIN"
if [ ! -f "$WEBSERVER_CONF" ]; then
print_info "Kopiere Nginx-Konfiguration..."
sudo cp "$PROJECT_DIR/nginx.conf" "$WEBSERVER_CONF"
print_info "Aktiviere Site..."
sudo ln -sf "$WEBSERVER_CONF" "/etc/nginx/sites-enabled/$DOMAIN"
print_info "Teste Nginx-Konfiguration..."
sudo nginx -t
print_info "Lade Nginx neu..."
sudo systemctl reload nginx
print_success "Nginx konfiguriert!"
else
print_warning "Nginx-Konfiguration existiert bereits"
read -p "Überschreiben? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
sudo cp "$PROJECT_DIR/nginx.conf" "$WEBSERVER_CONF"
sudo nginx -t && sudo systemctl reload nginx
print_success "Nginx-Konfiguration aktualisiert!"
fi
fi
else
print_header "Setup Apache2"
WEBSERVER_CONF="/etc/apache2/sites-available/$DOMAIN.conf"
if [ ! -f "$WEBSERVER_CONF" ]; then
print_info "Kopiere Apache2-Konfiguration..."
sudo cp "$PROJECT_DIR/apache2.conf" "$WEBSERVER_CONF"
print_info "Aktiviere Site..."
sudo a2ensite "$DOMAIN"
# Deaktiviere Default-Site (optional)
if [ -f "/etc/apache2/sites-enabled/000-default.conf" ]; then
print_info "Deaktiviere Default-Site..."
sudo a2dissite 000-default
fi
print_info "Teste Apache2-Konfiguration..."
sudo apache2ctl configtest
print_info "Lade Apache2 neu..."
sudo systemctl reload apache2
print_success "Apache2 konfiguriert!"
else
print_warning "Apache2-Konfiguration existiert bereits"
read -p "Überschreiben? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
sudo cp "$PROJECT_DIR/apache2.conf" "$WEBSERVER_CONF"
sudo apache2ctl configtest && sudo systemctl reload apache2
print_success "Apache2-Konfiguration aktualisiert!"
fi
fi
fi
}
setup_ssl() {
print_header "Setup SSL-Zertifikat"
print_info "Prüfe ob Zertifikat bereits existiert..."
if [ -d "/etc/letsencrypt/live/$DOMAIN" ]; then
print_success "SSL-Zertifikat bereits vorhanden"
return
fi
print_warning "Stelle sicher, dass $DOMAIN auf diesen Server zeigt!"
read -p "Fortfahren? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_info "SSL-Setup übersprungen"
return
fi
print_info "Erstelle SSL-Zertifikat mit Let's Encrypt..."
if [ "$WEBSERVER" = "nginx" ]; then
sudo certbot --nginx -d $DOMAIN
else
sudo certbot --apache -d $DOMAIN
fi
print_success "SSL-Zertifikat erstellt!"
}
setup_backend_service() {
print_header "Setup Backend-Service"
if [ "$USE_PM2" = true ]; then
print_info "Starte Backend mit PM2..."
cd $BACKEND_DIR
pm2 delete $SERVICE_NAME 2>/dev/null || true
pm2 start src/index.js --name $SERVICE_NAME --env production
pm2 save
print_info "Richte PM2 Auto-Start ein..."
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u $USER --hp $HOME
print_success "Backend läuft mit PM2!"
else
print_info "Installiere systemd-Service..."
sudo cp "$PROJECT_DIR/timeclock.service" /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable $SERVICE_NAME
sudo systemctl start $SERVICE_NAME
print_success "Backend läuft mit systemd!"
fi
}
setup_firewall() {
print_header "Setup Firewall"
if ! check_command ufw; then
print_warning "UFW nicht installiert, überspringe Firewall-Setup"
return
fi
print_info "Konfiguriere UFW..."
sudo ufw allow ssh
if [ "$WEBSERVER" = "nginx" ]; then
sudo ufw allow 'Nginx Full'
else
sudo ufw allow 'Apache Full'
fi
if ! sudo ufw status | grep -q "Status: active"; then
print_warning "UFW ist nicht aktiv"
read -p "UFW aktivieren? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
sudo ufw --force enable
print_success "UFW aktiviert!"
fi
else
print_success "UFW bereits konfiguriert"
fi
}
# =============================================================================
# Update - Aktualisierung einer bestehenden Installation
# =============================================================================
do_update() {
print_header "Update $PROJECT_NAME"
# Backup erstellen
do_backup
# Backend aktualisieren
print_info "Aktualisiere Backend..."
cd $BACKEND_DIR
npm install --production
# Frontend neu bauen
print_info "Aktualisiere Frontend..."
cd $FRONTEND_DIR
npm install
npm run build
# Service neu starten
restart_backend
print_success "Update abgeschlossen!"
}
# =============================================================================
# Backup & Rollback
# =============================================================================
do_backup() {
print_header "Erstelle Backup"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
print_info "Erstelle Datenbank-Backup..."
# Lese DB-Credentials aus .env
DB_NAME=$(grep DB_NAME $BACKEND_DIR/.env | cut -d '=' -f2)
DB_USER=$(grep DB_USER $BACKEND_DIR/.env | cut -d '=' -f2)
DB_PASSWORD=$(grep DB_PASSWORD $BACKEND_DIR/.env | cut -d '=' -f2)
mysqldump -u $DB_USER -p"$DB_PASSWORD" $DB_NAME | gzip > "$BACKUP_DIR/${PROJECT_NAME,,}_$TIMESTAMP.sql.gz"
print_info "Erstelle Code-Backup..."
tar -czf "$BACKUP_DIR/${PROJECT_NAME,,}_code_$TIMESTAMP.tar.gz" -C $(dirname $PROJECT_DIR) $(basename $PROJECT_DIR)
# Alte Backups löschen (älter als 30 Tage)
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete
print_success "Backup erstellt: $TIMESTAMP"
}
do_rollback() {
print_header "Rollback zu vorheriger Version"
print_warning "Rollback wird die letzte Code-Version wiederherstellen"
read -p "Fortfahren? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_info "Rollback abgebrochen"
return
fi
# Finde letztes Code-Backup
LAST_BACKUP=$(ls -t $BACKUP_DIR/${PROJECT_NAME,,}_code_*.tar.gz 2>/dev/null | head -n1)
if [ -z "$LAST_BACKUP" ]; then
print_error "Kein Backup gefunden!"
exit 1
fi
print_info "Stelle wieder her: $LAST_BACKUP"
# Aktuellen Code sichern
mv $PROJECT_DIR "${PROJECT_DIR}_rollback_backup_$(date +%Y%m%d_%H%M%S)"
# Backup wiederherstellen
tar -xzf "$LAST_BACKUP" -C $(dirname $PROJECT_DIR)
# Services neu starten
restart_backend
print_success "Rollback abgeschlossen!"
}
# =============================================================================
# Service Management
# =============================================================================
restart_backend() {
print_info "Starte Backend neu..."
if [ "$USE_PM2" = true ]; then
pm2 restart $SERVICE_NAME
else
sudo systemctl restart $SERVICE_NAME
fi
print_success "Backend neu gestartet!"
}
show_status() {
print_header "Service Status"
if [ "$USE_PM2" = true ]; then
pm2 status $SERVICE_NAME
echo ""
pm2 info $SERVICE_NAME
else
sudo systemctl status $SERVICE_NAME
fi
echo ""
if [ "$WEBSERVER" = "nginx" ]; then
print_info "Nginx Status:"
sudo systemctl status nginx --no-pager | head -n 10
else
print_info "Apache2 Status:"
sudo systemctl status apache2 --no-pager | head -n 10
fi
echo ""
print_info "SSL-Zertifikat:"
sudo certbot certificates | grep -A 5 $DOMAIN || print_warning "Kein Zertifikat gefunden"
}
show_logs() {
print_header "Logs"
echo "1) Backend-Logs"
echo "2) Webserver Access-Logs"
echo "3) Webserver Error-Logs"
echo "4) Alle Logs (follow)"
read -p "Auswahl (1-4): " choice
if [ "$WEBSERVER" = "nginx" ]; then
ACCESS_LOG="/var/log/nginx/stechuhr3.access.log"
ERROR_LOG="/var/log/nginx/stechuhr3.error.log"
else
ACCESS_LOG="/var/log/apache2/stechuhr3-access.log"
ERROR_LOG="/var/log/apache2/stechuhr3-error.log"
fi
case $choice in
1)
if [ "$USE_PM2" = true ]; then
pm2 logs $SERVICE_NAME
else
sudo journalctl -u $SERVICE_NAME -f
fi
;;
2)
sudo tail -f "$ACCESS_LOG"
;;
3)
sudo tail -f "$ERROR_LOG"
;;
4)
if [ "$USE_PM2" = true ]; then
pm2 logs $SERVICE_NAME &
PM2_PID=$!
else
sudo journalctl -u $SERVICE_NAME -f &
JOURNAL_PID=$!
fi
if [ "$WEBSERVER" = "nginx" ]; then
sudo tail -f /var/log/nginx/stechuhr3.*.log
else
sudo tail -f /var/log/apache2/stechuhr3-*.log
fi
;;
*)
print_error "Ungültige Auswahl"
;;
esac
}
# =============================================================================
# Vollständige Installation
# =============================================================================
do_install() {
print_header "$PROJECT_NAME - Vollständige Installation"
check_root
print_warning "Diese Installation wird folgendes tun:"
echo " - System-Abhängigkeiten installieren"
echo " - Projekt nach $PROJECT_DIR kopieren"
echo " - Backend und Frontend einrichten"
echo " - Nginx konfigurieren"
echo " - SSL-Zertifikat erstellen"
echo " - Backend-Service starten"
echo " - Firewall konfigurieren"
echo ""
read -p "Fortfahren? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_info "Installation abgebrochen"
exit 0
fi
install_dependencies
setup_directories
copy_project_files
setup_backend
setup_frontend
setup_webserver
setup_ssl
setup_backend_service
setup_firewall
print_header "Installation abgeschlossen! 🎉"
print_success "Deine TimeClock-App läuft jetzt auf https://$DOMAIN"
echo ""
print_info "Nützliche Befehle:"
echo " ./deploy.sh status - Zeige Service-Status"
echo " ./deploy.sh logs - Zeige Logs"
echo " ./deploy.sh update - Update durchführen"
echo " ./deploy.sh backup - Backup erstellen"
echo ""
}
# =============================================================================
# Hauptprogramm
# =============================================================================
show_help() {
cat << EOF
$PROJECT_NAME v3 - Deployment Script
Verwendung: $0 [OPTION]
Optionen:
install Erste Installation (inkl. System-Setup)
update Update einer bestehenden Installation
rollback Rollback zur vorherigen Version
backup Erstelle Backup der Datenbank
status Zeige Status der Services
logs Zeige Logs
help Zeige diese Hilfe
Beispiele:
$0 install # Erste Installation
$0 update # Update durchführen
$0 backup # Backup erstellen
$0 status # Status anzeigen
EOF
}
# Hauptlogik
case "${1:-help}" in
install)
do_install
;;
update)
do_update
;;
rollback)
do_rollback
;;
backup)
do_backup
;;
status)
show_status
;;
logs)
show_logs
;;
help|--help|-h)
show_help
;;
*)
print_error "Unbekannte Option: $1"
echo ""
show_help
exit 1
;;
esac
exit 0