# ---- vendor ---------------------------------------------------------------- FROM composer:2 AS vendor WORKDIR /app # anagram-finder/core is a VCS repository, so composer needs git. RUN apk add --no-cache git COPY composer.json composer.lock ./ RUN composer install \ --no-dev \ --no-scripts \ --no-autoloader \ --prefer-dist \ --no-interaction COPY . . # --no-scripts: Laravel's post-autoload-dump hook runs artisan, which wants an # environment that does not exist at build time. Package discovery happens on boot. RUN composer dump-autoload --no-dev --optimize --classmap-authoritative --no-scripts # ---- assets ---------------------------------------------------------------- FROM node:22-alpine AS assets WORKDIR /app # @lvl0/ui is a git dependency, so npm needs git available. RUN apk add --no-cache git COPY package.json package-lock.json ./ RUN npm ci COPY vite.config.js ./ COPY resources ./resources # app.css imports Flux's stylesheet from vendor/ and scans three vendor globs # for class names, so the asset build needs composer's output present. COPY --from=vendor /app/vendor ./vendor RUN npm run build # ---- runtime --------------------------------------------------------------- FROM dunglas/frankenphp:1-php8.4-alpine RUN apk add --no-cache mariadb-client curl RUN install-php-extensions \ pdo_mysql \ opcache \ zip \ gd \ intl \ bcmath \ pcntl RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" WORKDIR /app COPY --from=vendor /app /app COPY --from=assets /app/public/build /app/public/build # The dev server writes public/hot and only removes it on a clean shutdown; a # stray copy makes @vite() point at a dev server that does not exist here. RUN rm -f /app/public/hot RUN cat > /etc/caddy/Caddyfile <<'EOF' { frankenphp order php_server before file_server } :8000 { root * /app/public php_server { index index.php } encode gzip file_server header { X-Frame-Options "SAMEORIGIN" X-Content-Type-Options "nosniff" Referrer-Policy "strict-origin-when-cross-origin" } } EOF RUN cat > /start.sh <<'EOF' #!/bin/sh set -e if [ -n "$DB_HOST" ]; then echo "Waiting for database..." until mariadb -h "$DB_HOST" -u "$DB_USERNAME" -p"$DB_PASSWORD" -e "SELECT 1" >/dev/null 2>&1; do sleep 2 done fi # Rebuild the package manifest from what is actually installed. Any manifest # baked in at build time could name a dev provider that --no-dev omitted. rm -f bootstrap/cache/packages.php bootstrap/cache/services.php php artisan package:discover --ansi php artisan migrate --force # Cached at boot rather than at build: config:cache bakes in environment values, # which are not known until the container runs. php artisan config:cache php artisan route:cache php artisan view:cache exec frankenphp run --config /etc/caddy/Caddyfile EOF RUN chmod +x /start.sh RUN chown -R www-data:www-data /app/storage /app/bootstrap/cache EXPOSE 8000 CMD ["/start.sh"]