From 380a11dafed93e95cb2907610868ba891fd7bf65 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 17:51:33 +0000 Subject: [PATCH 1/8] Initial plan From 2e79df31554e3c6723c2b8a2f6a020e8d1822e0b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:04:07 +0000 Subject: [PATCH 2/8] Optimize Docker build: Build assets outside ARM emulation - Add multi-stage build with separate composer-deps and assets stages - Assets are built once on native platform (node:22-bookworm-slim) - Pre-built assets copied into final images for all platforms - Remove Node.js/Yarn installation from final images (smaller size) - Use --ignore-platform-reqs for composer in assets stage - Applies to both Dockerfile and Dockerfile-frankenphp Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> --- Dockerfile | 49 +++++++++++++++++++++++---------- Dockerfile-frankenphp | 64 ++++++++++++++++++++++--------------------- 2 files changed, 68 insertions(+), 45 deletions(-) diff --git a/Dockerfile b/Dockerfile index cb18c78f4..a44e4f55c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,37 @@ ARG BASE_IMAGE=debian:bookworm-slim ARG PHP_VERSION=8.4 +# --- +# Build assets stage - runs on native platform (not emulated) +# This stage builds the frontend assets (JavaScript, CSS) using Node.js and Yarn +FROM composer:latest AS composer-deps + +WORKDIR /build + +# Copy composer files and install PHP dependencies (needed for Symfony UX assets) +COPY composer.json composer.lock symfony.lock ./ +RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist --ignore-platform-reqs + +# --- + +FROM node:22-bookworm-slim AS assets + +WORKDIR /build + +# Copy vendor directory from composer stage (needed for Symfony UX packages) +COPY --from=composer-deps /build/vendor ./vendor + +# Copy package files +COPY package.json yarn.lock webpack.config.js ./ +COPY assets ./assets + +# Install dependencies and build assets +RUN yarn install --network-timeout 600000 && \ + yarn build && \ + yarn cache clean + +# --- + FROM ${BASE_IMAGE} AS base ARG PHP_VERSION @@ -45,15 +76,6 @@ RUN apt-get update && apt-get -y install \ # delete the "index.html" that installing Apache drops in here && rm -rvf /var/www/html/* -# Install node and yarn -RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ - echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ - curl -sL https://deb.nodesource.com/setup_22.x | bash - && \ - apt-get update && apt-get install -y \ - nodejs \ - yarn \ - && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/* - # Install composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer @@ -149,14 +171,13 @@ RUN a2dissite 000-default.conf && \ a2enconf docker-php && \ a2enmod rewrite -# Install composer and yarn dependencies for Part-DB +# Install composer dependencies for Part-DB USER www-data RUN composer install -a --no-dev && \ composer clear-cache -RUN yarn install --network-timeout 600000 && \ - yarn build && \ - yarn cache clean && \ - rm -rf node_modules/ + +# Copy pre-built assets from the assets stage +COPY --from=assets --chown=www-data:www-data /build/public/build ./public/build # Use docker env to output logs to stdout ENV APP_ENV=docker diff --git a/Dockerfile-frankenphp b/Dockerfile-frankenphp index f381f3306..f558c5390 100644 --- a/Dockerfile-frankenphp +++ b/Dockerfile-frankenphp @@ -1,3 +1,34 @@ +# --- +# Build assets stage - runs on native platform (not emulated) +# This stage builds the frontend assets (JavaScript, CSS) using Node.js and Yarn +FROM composer:latest AS composer-deps + +WORKDIR /build + +# Copy composer files and install PHP dependencies (needed for Symfony UX assets) +COPY composer.json composer.lock symfony.lock ./ +RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist --ignore-platform-reqs + +# --- + +FROM node:22-bookworm-slim AS assets + +WORKDIR /build + +# Copy vendor directory from composer stage (needed for Symfony UX packages) +COPY --from=composer-deps /build/vendor ./vendor + +# Copy package files +COPY package.json yarn.lock webpack.config.js ./ +COPY assets ./assets + +# Install dependencies and build assets +RUN yarn install --network-timeout 600000 && \ + yarn build && \ + yarn cache clean + +# --- + FROM dunglas/frankenphp:1-php8.4 AS frankenphp_upstream RUN apt-get update && apt-get -y install \ @@ -13,33 +44,6 @@ RUN apt-get update && apt-get -y install \ zip \ && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/*; -RUN set -eux; \ - # Prepare keyrings directory - mkdir -p /etc/apt/keyrings; \ - \ - # Import Yarn GPG key - curl -fsSL https://dl.yarnpkg.com/debian/pubkey.gpg \ - | tee /etc/apt/keyrings/yarn.gpg >/dev/null; \ - chmod 644 /etc/apt/keyrings/yarn.gpg; \ - \ - # Add Yarn repo with signed-by - echo "deb [signed-by=/etc/apt/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian stable main" \ - | tee /etc/apt/sources.list.d/yarn.list; \ - \ - # Run NodeSource setup script (unchanged) - curl -sL https://deb.nodesource.com/setup_22.x | bash -; \ - \ - # Install Node.js + Yarn - apt-get update; \ - apt-get install -y --no-install-recommends \ - nodejs \ - yarn; \ - \ - # Cleanup - apt-get -y autoremove; \ - apt-get clean autoclean; \ - rm -rf /var/lib/apt/lists/* - # Install PHP RUN set -eux; \ @@ -90,10 +94,8 @@ RUN set -eux; \ composer run-script --no-dev post-install-cmd; \ chmod +x bin/console; sync; -RUN yarn install --network-timeout 600000 && \ - yarn build && \ - yarn cache clean && \ - rm -rf node_modules/ +# Copy pre-built assets from the assets stage +COPY --from=assets /build/public/build ./public/build # Use docker env to output logs to stdout ENV APP_ENV=docker From 84fa3268398c22f59505407c475089e8e5324032 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:08:30 +0000 Subject: [PATCH 3/8] Remove redundant --chown flag from COPY in Dockerfile The assets are copied while running as www-data user, so the --chown flag is redundant. This makes it consistent with the frankenphp version. Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a44e4f55c..3f4b5783d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -177,7 +177,7 @@ RUN composer install -a --no-dev && \ composer clear-cache # Copy pre-built assets from the assets stage -COPY --from=assets --chown=www-data:www-data /build/public/build ./public/build +COPY --from=assets /build/public/build ./public/build # Use docker env to output logs to stdout ENV APP_ENV=docker From 564b8f2891f4f2f101caaa156fa8cecad399a48c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:28:11 +0000 Subject: [PATCH 4/8] Add git package to Dockerfile base stage Git is required by composer when installing packages from source. This dependency was exposed by the multi-stage build changes where composer-deps stage uses --no-scripts and the final stage needs to complete the installation. Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 3f4b5783d..c2a0e8ae0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -67,6 +67,7 @@ RUN apt-get update && apt-get -y install \ php${PHP_VERSION}-sqlite3 \ php${PHP_VERSION}-mysql \ php${PHP_VERSION}-pgsql \ + git \ gpg \ sudo \ && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/* \ From a604ec8476fa3cf30e9848f8a76889f52f5160ed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:43:51 +0000 Subject: [PATCH 5/8] Add translations stage to generate Symfony translations for webpack Webpack build requires var/translations files generated by Symfony's cache warmup. Added intermediate 'translations' stage that: - Copies composer dependencies and app files - Generates autoloader - Runs cache warmup to create translation files - Assets stage now copies these translations before building This fixes the webpack build errors about missing translation exports. Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> --- Dockerfile | 25 +++++++++++++++++++++++++ Dockerfile-frankenphp | 25 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/Dockerfile b/Dockerfile index c2a0e8ae0..a11137425 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,28 @@ RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist --ignor # --- +# Stage to generate Symfony translations needed for webpack +FROM composer:latest AS translations + +WORKDIR /build + +# Copy composer dependencies and application files +COPY --from=composer-deps /build/vendor ./vendor +COPY composer.json composer.lock symfony.lock ./ +COPY bin ./bin +COPY config ./config +COPY public ./public +COPY src ./src +COPY templates ./templates +COPY translations ./translations + +# Generate autoloader and dump translations +RUN composer dump-autoload --no-dev --classmap-authoritative && \ + php bin/console cache:clear --no-warmup && \ + php bin/console cache:warmup + +# --- + FROM node:22-bookworm-slim AS assets WORKDIR /build @@ -21,6 +43,9 @@ WORKDIR /build # Copy vendor directory from composer stage (needed for Symfony UX packages) COPY --from=composer-deps /build/vendor ./vendor +# Copy generated translations from Symfony +COPY --from=translations /build/var/translations ./var/translations + # Copy package files COPY package.json yarn.lock webpack.config.js ./ COPY assets ./assets diff --git a/Dockerfile-frankenphp b/Dockerfile-frankenphp index f558c5390..d043cccad 100644 --- a/Dockerfile-frankenphp +++ b/Dockerfile-frankenphp @@ -11,6 +11,28 @@ RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist --ignor # --- +# Stage to generate Symfony translations needed for webpack +FROM composer:latest AS translations + +WORKDIR /build + +# Copy composer dependencies and application files +COPY --from=composer-deps /build/vendor ./vendor +COPY composer.json composer.lock symfony.lock ./ +COPY bin ./bin +COPY config ./config +COPY public ./public +COPY src ./src +COPY templates ./templates +COPY translations ./translations + +# Generate autoloader and dump translations +RUN composer dump-autoload --no-dev --classmap-authoritative && \ + php bin/console cache:clear --no-warmup && \ + php bin/console cache:warmup + +# --- + FROM node:22-bookworm-slim AS assets WORKDIR /build @@ -18,6 +40,9 @@ WORKDIR /build # Copy vendor directory from composer stage (needed for Symfony UX packages) COPY --from=composer-deps /build/vendor ./vendor +# Copy generated translations from Symfony +COPY --from=translations /build/var/translations ./var/translations + # Copy package files COPY package.json yarn.lock webpack.config.js ./ COPY assets ./assets From 9402382d565bec27aa5541583ae2025b63c9f739 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 19:06:07 +0000 Subject: [PATCH 6/8] Copy .env file to translations stage for Symfony console commands Symfony console requires .env file to bootstrap. Added COPY .env to translations stage so cache:warmup can run successfully. Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> --- Dockerfile | 1 + Dockerfile-frankenphp | 1 + 2 files changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index a11137425..b3dbf6a35 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,6 +22,7 @@ WORKDIR /build # Copy composer dependencies and application files COPY --from=composer-deps /build/vendor ./vendor COPY composer.json composer.lock symfony.lock ./ +COPY .env ./ COPY bin ./bin COPY config ./config COPY public ./public diff --git a/Dockerfile-frankenphp b/Dockerfile-frankenphp index d043cccad..acdeaf1f6 100644 --- a/Dockerfile-frankenphp +++ b/Dockerfile-frankenphp @@ -19,6 +19,7 @@ WORKDIR /build # Copy composer dependencies and application files COPY --from=composer-deps /build/vendor ./vendor COPY composer.json composer.lock symfony.lock ./ +COPY .env ./ COPY bin ./bin COPY config ./config COPY public ./public From 6a1792d46a231401f3664375da5b1ccf377caa04 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 20:48:51 +0000 Subject: [PATCH 7/8] Simplify asset build: copy entire project instead of individual files Refactored to copy the entire project directory in composer-deps and assets stages instead of cherry-picking specific files. This: - Eliminates the separate translations stage - Avoids missing file issues - Simplifies the build process - Maintains performance benefit of building assets once on native platform Both stages now use COPY . . to get all project files, avoiding the complexity of tracking which files are needed. Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> --- Dockerfile | 39 +++++++-------------------------------- Dockerfile-frankenphp | 39 +++++++-------------------------------- 2 files changed, 14 insertions(+), 64 deletions(-) diff --git a/Dockerfile b/Dockerfile index b3dbf6a35..f07b65b98 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,30 +8,12 @@ FROM composer:latest AS composer-deps WORKDIR /build -# Copy composer files and install PHP dependencies (needed for Symfony UX assets) -COPY composer.json composer.lock symfony.lock ./ -RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist --ignore-platform-reqs +# Copy entire project to install dependencies and generate translations +COPY . . -# --- - -# Stage to generate Symfony translations needed for webpack -FROM composer:latest AS translations - -WORKDIR /build - -# Copy composer dependencies and application files -COPY --from=composer-deps /build/vendor ./vendor -COPY composer.json composer.lock symfony.lock ./ -COPY .env ./ -COPY bin ./bin -COPY config ./config -COPY public ./public -COPY src ./src -COPY templates ./templates -COPY translations ./translations - -# Generate autoloader and dump translations -RUN composer dump-autoload --no-dev --classmap-authoritative && \ +# Install composer dependencies (needed for Symfony UX assets and cache warmup) +RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist --ignore-platform-reqs && \ + composer dump-autoload --no-dev --classmap-authoritative && \ php bin/console cache:clear --no-warmup && \ php bin/console cache:warmup @@ -41,15 +23,8 @@ FROM node:22-bookworm-slim AS assets WORKDIR /build -# Copy vendor directory from composer stage (needed for Symfony UX packages) -COPY --from=composer-deps /build/vendor ./vendor - -# Copy generated translations from Symfony -COPY --from=translations /build/var/translations ./var/translations - -# Copy package files -COPY package.json yarn.lock webpack.config.js ./ -COPY assets ./assets +# Copy entire project with vendor and generated translations from composer-deps stage +COPY --from=composer-deps /build ./ # Install dependencies and build assets RUN yarn install --network-timeout 600000 && \ diff --git a/Dockerfile-frankenphp b/Dockerfile-frankenphp index acdeaf1f6..ba4b01db9 100644 --- a/Dockerfile-frankenphp +++ b/Dockerfile-frankenphp @@ -5,30 +5,12 @@ FROM composer:latest AS composer-deps WORKDIR /build -# Copy composer files and install PHP dependencies (needed for Symfony UX assets) -COPY composer.json composer.lock symfony.lock ./ -RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist --ignore-platform-reqs +# Copy entire project to install dependencies and generate translations +COPY . . -# --- - -# Stage to generate Symfony translations needed for webpack -FROM composer:latest AS translations - -WORKDIR /build - -# Copy composer dependencies and application files -COPY --from=composer-deps /build/vendor ./vendor -COPY composer.json composer.lock symfony.lock ./ -COPY .env ./ -COPY bin ./bin -COPY config ./config -COPY public ./public -COPY src ./src -COPY templates ./templates -COPY translations ./translations - -# Generate autoloader and dump translations -RUN composer dump-autoload --no-dev --classmap-authoritative && \ +# Install composer dependencies (needed for Symfony UX assets and cache warmup) +RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist --ignore-platform-reqs && \ + composer dump-autoload --no-dev --classmap-authoritative && \ php bin/console cache:clear --no-warmup && \ php bin/console cache:warmup @@ -38,15 +20,8 @@ FROM node:22-bookworm-slim AS assets WORKDIR /build -# Copy vendor directory from composer stage (needed for Symfony UX packages) -COPY --from=composer-deps /build/vendor ./vendor - -# Copy generated translations from Symfony -COPY --from=translations /build/var/translations ./var/translations - -# Copy package files -COPY package.json yarn.lock webpack.config.js ./ -COPY assets ./assets +# Copy entire project with vendor and generated translations from composer-deps stage +COPY --from=composer-deps /build ./ # Install dependencies and build assets RUN yarn install --network-timeout 600000 && \ From c5210a33c4c59b68d44c3d14080a2df8f023cd65 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 21:06:09 +0000 Subject: [PATCH 8/8] Force asset build stages to run on native platform with --platform=$BUILDPLATFORM Added --platform=$BUILDPLATFORM to composer-deps and assets stages to ensure they run on the native build platform (amd64) instead of being built separately for each target architecture (amd64, arm64, arm/v7). This is the critical change that makes the optimization work: - Without this flag, Docker Buildx builds these stages for each target platform - With this flag, stages run once on native platform and results are copied to all targets - Eliminates ARM emulation overhead for CPU-intensive asset compilation Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> --- Dockerfile | 6 ++++-- Dockerfile-frankenphp | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index f07b65b98..1cfb0e5a7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,9 @@ ARG PHP_VERSION=8.4 # --- # Build assets stage - runs on native platform (not emulated) # This stage builds the frontend assets (JavaScript, CSS) using Node.js and Yarn -FROM composer:latest AS composer-deps +# The --platform=$BUILDPLATFORM ensures this stage runs on the native build platform (amd64) +# and not under emulation for ARM builds +FROM --platform=$BUILDPLATFORM composer:latest AS composer-deps WORKDIR /build @@ -19,7 +21,7 @@ RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist --ignor # --- -FROM node:22-bookworm-slim AS assets +FROM --platform=$BUILDPLATFORM node:22-bookworm-slim AS assets WORKDIR /build diff --git a/Dockerfile-frankenphp b/Dockerfile-frankenphp index ba4b01db9..0f5231897 100644 --- a/Dockerfile-frankenphp +++ b/Dockerfile-frankenphp @@ -1,7 +1,9 @@ # --- # Build assets stage - runs on native platform (not emulated) # This stage builds the frontend assets (JavaScript, CSS) using Node.js and Yarn -FROM composer:latest AS composer-deps +# The --platform=$BUILDPLATFORM ensures this stage runs on the native build platform (amd64) +# and not under emulation for ARM builds +FROM --platform=$BUILDPLATFORM composer:latest AS composer-deps WORKDIR /build @@ -16,7 +18,7 @@ RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist --ignor # --- -FROM node:22-bookworm-slim AS assets +FROM --platform=$BUILDPLATFORM node:22-bookworm-slim AS assets WORKDIR /build