From 435cbaa8abe091cfe6f888dafb2a2d5f5203da04 Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Sun, 15 Feb 2026 16:42:18 +0100 Subject: [PATCH 1/9] feat: deploy for frontend - unified across local and prod (using prod with nginx), also passed ssl certs; updated docs and CI/CD --- .github/workflows/stack-tests.yml | 19 ++++-------------- docker-compose.yaml | 9 +++------ docs/operations/cicd.md | 16 +++++++--------- frontend/Dockerfile | 32 +++++++++++++++++++++++-------- frontend/Dockerfile.prod | 31 ------------------------------ frontend/nginx.conf.template | 6 +++++- 6 files changed, 43 insertions(+), 70 deletions(-) delete mode 100644 frontend/Dockerfile.prod diff --git a/.github/workflows/stack-tests.yml b/.github/workflows/stack-tests.yml index 7ff6aac4..9f695916 100644 --- a/.github/workflows/stack-tests.yml +++ b/.github/workflows/stack-tests.yml @@ -194,7 +194,7 @@ jobs: cache-from: type=gha,scope=zookeeper-certgen cache-to: type=gha,mode=max,scope=zookeeper-certgen - # ── Frontend (dev for E2E, prod for scanning/deployment) ───────── + # ── Frontend (nginx + SSL) ───────────────────────────────────── - name: Build frontend image uses: docker/build-push-action@v6 with: @@ -205,16 +205,6 @@ jobs: cache-from: type=gha,scope=frontend cache-to: type=gha,mode=max,scope=frontend - - name: Build frontend-prod image - uses: docker/build-push-action@v6 - with: - context: ./frontend - file: ./frontend/Dockerfile.prod - load: true - tags: integr8scode-frontend-prod:latest - cache-from: type=gha,scope=frontend-prod - cache-to: type=gha,mode=max,scope=frontend-prod - # ── Push all images to GHCR in parallel ──────────────────────── - name: Push all images to GHCR if: ${{ !github.event.pull_request.head.repo.fork }} @@ -227,13 +217,12 @@ jobs: docker tag integr8scode-backend:latest "$IMG/backend:$TAG" docker tag integr8scode-cert-generator:latest "$IMG/cert-generator:$TAG" docker tag integr8scode-zookeeper-certgen:latest "$IMG/zookeeper-certgen:$TAG" - docker tag integr8scode-frontend:latest "$IMG/frontend-dev:$TAG" - docker tag integr8scode-frontend-prod:latest "$IMG/frontend:$TAG" + docker tag integr8scode-frontend:latest "$IMG/frontend:$TAG" - # Push all 6 images in parallel, tracking each PID + # Push all 5 images in parallel, tracking each PID declare -A PIDS for name in base backend cert-generator zookeeper-certgen \ - frontend-dev frontend; do + frontend; do docker push "$IMG/$name:$TAG" & PIDS[$name]=$! done diff --git a/docker-compose.yaml b/docker-compose.yaml index e49a6bc8..fdfb80c1 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -127,7 +127,7 @@ services: start_period: 3s frontend: - image: ghcr.io/hardmax71/integr8scode/frontend-dev:${IMAGE_TAG:-latest} + image: ghcr.io/hardmax71/integr8scode/frontend:${IMAGE_TAG:-latest} container_name: frontend build: context: ./frontend @@ -138,17 +138,14 @@ services: backend: condition: service_started volumes: - - ./frontend:/app - - /app/node_modules - - ./frontend/certs:/app/certs:ro + - ./frontend/certs:/etc/nginx/certs:ro - shared_ca:/shared_ca:ro ports: - "5001:5001" networks: - app-network environment: - - VITE_BACKEND_URL=https://backend:443 - - NODE_EXTRA_CA_CERTS=/shared_ca/ca.pem + - BACKEND_URL=https://backend:443 healthcheck: test: ["CMD-SHELL", "curl -k -f -s https://localhost:5001 >/dev/null || exit 1"] interval: 2s diff --git a/docs/operations/cicd.md b/docs/operations/cicd.md index ff452d85..b0819088 100644 --- a/docs/operations/cicd.md +++ b/docs/operations/cicd.md @@ -92,7 +92,7 @@ no setup to overlap. ## Stack Tests (the main workflow) -This is the core testing workflow. It builds all 6 container images, pushes them to GHCR with immutable SHA-based +This is the core testing workflow. It builds all 5 container images, pushes them to GHCR with immutable SHA-based tags, then runs E2E tests on separate runners that pull images from the registry. ```mermaid @@ -131,7 +131,7 @@ the image build is skipped entirely. ### Phase 2: Build and push -All 6 images are built on a single runner and pushed to GHCR with an immutable `sha-<7chars>` tag: +All 5 images are built on a single runner and pushed to GHCR with an immutable `sha-<7chars>` tag: | Image | Source | |----------------------|---------------------------------------------| @@ -139,19 +139,17 @@ All 6 images are built on a single runner and pushed to GHCR with an immutable ` | `backend` | `backend/Dockerfile` | | `cert-generator` | `cert-generator/Dockerfile` | | `zookeeper-certgen` | `backend/zookeeper/Dockerfile.certgen` | -| `frontend-dev` | `frontend/Dockerfile` | -| `frontend` | `frontend/Dockerfile.prod` | +| `frontend` | `frontend/Dockerfile` | Workers reuse the `backend` image with different `command:` overrides in docker-compose, so no separate worker images -are needed. Of these 6 images, 5 are scanned by Trivy and promoted to `latest` in the -[Docker Scan & Promote](#docker-scan-promote) workflow. The `frontend-dev` image is excluded — it's the Rollup dev -server build used only for E2E tests in CI and is never deployed to production. +are needed. All 5 images are scanned by Trivy and promoted to `latest` in the +[Docker Scan & Promote](#docker-scan-promote) workflow. The base image is cached separately as a zstd-compressed tarball since its dependencies rarely change. The backend image depends on it via `--build-context base=docker-image://integr8scode-base:latest`. Utility and frontend images use GHA layer caching. -All 6 images are pushed to GHCR in parallel, with each push tracked by PID so individual failures are reported: +All 5 images are pushed to GHCR in parallel, with each push tracked by PID so individual failures are reported: ```yaml declare -A PIDS @@ -440,7 +438,7 @@ Playwright browsers are cached by `package-lock.json` hash. On cache hit, only s ### Parallel image push -All 6 images are pushed to GHCR concurrently using background processes with PID tracking. Each push failure is +All 5 images are pushed to GHCR concurrently using background processes with PID tracking. Each push failure is reported individually via `::error::` annotations. ## Running locally diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 965c92d0..4922300e 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,19 +1,35 @@ -FROM node:22-slim +# Build stage +FROM node:22-alpine AS builder WORKDIR /app -# Install curl for healthcheck (not included in slim image) -RUN apt-get update && apt-get install -y --no-install-recommends curl \ - && rm -rf /var/lib/apt/lists/* - -# Copy lockfile for reproducible, faster installs COPY package.json package-lock.json ./ RUN npm ci COPY . . +RUN npm run build + +# --8<-- [start:production_stage] +# Production stage +FROM nginx:alpine + +# Install curl for healthcheck +RUN apk add --no-cache curl + +# Copy built static files +COPY --from=builder /app/public /usr/share/nginx/html + +# Copy nginx config template (envsubst runs at container startup) +# The nginx image automatically processes /etc/nginx/templates/*.template +# and outputs to /etc/nginx/conf.d/ with the .template suffix removed +COPY nginx.conf.template /etc/nginx/templates/default.conf.template -COPY openssl.cnf /app/openssl.cnf +# Create writable directories for nginx (required for read-only root filesystem) +# and certs directory for TLS certificates mounted at runtime +RUN mkdir -p /var/cache/nginx /var/run /etc/nginx/certs && \ + chown -R nginx:nginx /var/cache/nginx /var/run /etc/nginx/certs EXPOSE 5001 -CMD ["npm", "run", "dev"] \ No newline at end of file +CMD ["nginx", "-g", "daemon off;"] +# --8<-- [end:production_stage] diff --git a/frontend/Dockerfile.prod b/frontend/Dockerfile.prod deleted file mode 100644 index f99de6ce..00000000 --- a/frontend/Dockerfile.prod +++ /dev/null @@ -1,31 +0,0 @@ -# Build stage -FROM node:22-alpine AS builder - -WORKDIR /app - -COPY package.json package-lock.json ./ -RUN npm ci - -COPY . . -RUN npm run build - -# --8<-- [start:production_stage] -# Production stage -FROM nginx:alpine - -# Copy built static files -COPY --from=builder /app/public /usr/share/nginx/html - -# Copy nginx config template (envsubst runs at container startup) -# The nginx image automatically processes /etc/nginx/templates/*.template -# and outputs to /etc/nginx/conf.d/ with the .template suffix removed -COPY nginx.conf.template /etc/nginx/templates/default.conf.template - -# Create writable directories for nginx (required for read-only root filesystem) -RUN mkdir -p /var/cache/nginx /var/run && \ - chown -R nginx:nginx /var/cache/nginx /var/run - -EXPOSE 5001 - -CMD ["nginx", "-g", "daemon off;"] -# --8<-- [end:production_stage] diff --git a/frontend/nginx.conf.template b/frontend/nginx.conf.template index 3d45ac55..1357ee30 100644 --- a/frontend/nginx.conf.template +++ b/frontend/nginx.conf.template @@ -1,8 +1,12 @@ # --8<-- [start:server_block] server { - listen 5001; + listen 5001 ssl; server_name _; + ssl_certificate /etc/nginx/certs/server.crt; + ssl_certificate_key /etc/nginx/certs/server.key; + ssl_protocols TLSv1.2 TLSv1.3; + root /usr/share/nginx/html; index index.html; # --8<-- [end:server_block] From c924008e01bd4dff81bc2d1da5e53beaaf303949 Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Sun, 15 Feb 2026 17:06:33 +0100 Subject: [PATCH 2/9] fix: deploy for frontend, also plot twist: all observability stuff is dpeloyed by default (removed separate profile) --- docker-compose.yaml | 5 ----- docs/operations/cicd.md | 2 +- docs/operations/nginx-configuration.md | 2 +- frontend/Dockerfile | 2 +- frontend/nginx.conf.template | 3 +++ 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index fdfb80c1..434ffe4b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -157,7 +157,6 @@ services: grafana: container_name: grafana image: grafana/grafana:12.3.1 - profiles: ["observability"] user: "472" ports: - "3000:3000" @@ -478,7 +477,6 @@ services: jaeger: image: jaegertracing/all-in-one:1.52 container_name: jaeger - profiles: ["observability"] ports: - "5775:5775/udp" # Zipkin/thrift compact - "6831:6831/udp" # Thrift compact @@ -539,7 +537,6 @@ services: victoria-metrics: image: victoriametrics/victoria-metrics:v1.96.0 container_name: victoria-metrics - profiles: ["observability"] ports: - "8428:8428" volumes: @@ -561,7 +558,6 @@ services: kafka-exporter: image: danielqsj/kafka-exporter:latest container_name: kafka-exporter - profiles: ["observability"] command: - "--kafka.server=kafka:29092" - "--web.listen-address=:9308" @@ -580,7 +576,6 @@ services: otel-collector: image: otel/opentelemetry-collector-contrib:0.91.0 container_name: otel-collector - profiles: ["observability"] command: ["--config=/etc/otel-collector-config.yaml"] volumes: - ./backend/otel-collector-config.yaml:/etc/otel-collector-config.yaml:ro diff --git a/docs/operations/cicd.md b/docs/operations/cicd.md index b0819088..b22f10b9 100644 --- a/docs/operations/cicd.md +++ b/docs/operations/cicd.md @@ -103,7 +103,7 @@ graph TD end subgraph "Phase 2: Build" - C["Build & Push 6 Images to GHCR"] + C["Build & Push 5 Images to GHCR"] end subgraph "Phase 3: E2E (parallel runners)" diff --git a/docs/operations/nginx-configuration.md b/docs/operations/nginx-configuration.md index ae0e90d8..aa79d5b5 100644 --- a/docs/operations/nginx-configuration.md +++ b/docs/operations/nginx-configuration.md @@ -244,7 +244,7 @@ The nginx configuration uses environment variable substitution via the official feature: ```dockerfile ---8<-- "frontend/Dockerfile.prod:production_stage" +--8<-- "frontend/Dockerfile:production_stage" ``` The nginx image automatically processes files in `/etc/nginx/templates/*.template` and outputs the result to diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 4922300e..3b7f9438 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -11,7 +11,7 @@ RUN npm run build # --8<-- [start:production_stage] # Production stage -FROM nginx:alpine +FROM nginx:1.27-alpine # Install curl for healthcheck RUN apk add --no-cache curl diff --git a/frontend/nginx.conf.template b/frontend/nginx.conf.template index 1357ee30..66873bff 100644 --- a/frontend/nginx.conf.template +++ b/frontend/nginx.conf.template @@ -6,6 +6,8 @@ server { ssl_certificate /etc/nginx/certs/server.crt; ssl_certificate_key /etc/nginx/certs/server.key; ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers on; root /usr/share/nginx/html; index index.html; @@ -13,6 +15,7 @@ server { # --8<-- [start:security_headers] add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; connect-src 'self';"; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options "DENY"; add_header X-Content-Type-Options "nosniff"; add_header Referrer-Policy "strict-origin-when-cross-origin"; From d611f5b168362ec15d096c6a2be1979c18b39044 Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Sun, 15 Feb 2026 17:25:26 +0100 Subject: [PATCH 3/9] resource preccuse -> tests failing; -> resolver for nginx for grafana and brought back observability profile --- .github/workflows/release-deploy.yml | 1 + docker-compose.yaml | 5 +++++ docs/operations/nginx-configuration.md | 8 +++++++- frontend/nginx.conf.template | 4 +++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-deploy.yml b/.github/workflows/release-deploy.yml index 7400aa91..1ecde4a7 100644 --- a/.github/workflows/release-deploy.yml +++ b/.github/workflows/release-deploy.yml @@ -137,6 +137,7 @@ jobs: echo "$GHCR_TOKEN" | docker login ghcr.io -u "$GHCR_USER" --password-stdin export IMAGE_TAG="$IMAGE_TAG" + export COMPOSE_PROFILES=observability docker compose pull docker compose up -d --remove-orphans --no-build diff --git a/docker-compose.yaml b/docker-compose.yaml index 434ffe4b..aedb618c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -156,6 +156,7 @@ services: grafana: container_name: grafana + profiles: ["observability"] image: grafana/grafana:12.3.1 user: "472" ports: @@ -477,6 +478,7 @@ services: jaeger: image: jaegertracing/all-in-one:1.52 container_name: jaeger + profiles: ["observability"] ports: - "5775:5775/udp" # Zipkin/thrift compact - "6831:6831/udp" # Thrift compact @@ -537,6 +539,7 @@ services: victoria-metrics: image: victoriametrics/victoria-metrics:v1.96.0 container_name: victoria-metrics + profiles: ["observability"] ports: - "8428:8428" volumes: @@ -558,6 +561,7 @@ services: kafka-exporter: image: danielqsj/kafka-exporter:latest container_name: kafka-exporter + profiles: ["observability"] command: - "--kafka.server=kafka:29092" - "--web.listen-address=:9308" @@ -576,6 +580,7 @@ services: otel-collector: image: otel/opentelemetry-collector-contrib:0.91.0 container_name: otel-collector + profiles: ["observability"] command: ["--config=/etc/otel-collector-config.yaml"] volumes: - ./backend/otel-collector-config.yaml:/etc/otel-collector-config.yaml:ro diff --git a/docs/operations/nginx-configuration.md b/docs/operations/nginx-configuration.md index aa79d5b5..55db200a 100644 --- a/docs/operations/nginx-configuration.md +++ b/docs/operations/nginx-configuration.md @@ -99,9 +99,15 @@ block defines **any** `proxy_set_header`, all parent-level `proxy_set_header` di Grafana is only available when the `observability` Docker Compose profile is active. Without it, requests to `/grafana/` return 502 (expected). +The `resolver` + `set $upstream` pattern is used here so nginx resolves `grafana` at request time instead of at startup. +Without this, nginx would fail to start when the Grafana container is not running (e.g., when the `observability` profile +is not active). Docker's embedded DNS resolver (`127.0.0.11`) handles container name resolution on the internal network. + | Directive | Purpose | |---------------------------------------------------------------|------------------------------------------------------------------------------| -| `proxy_pass http://grafana:3000` | Forward requests to the Grafana container on the internal Docker network | +| `resolver 127.0.0.11 valid=30s ipv6=off` | Use Docker's embedded DNS; cache results for 30s; skip IPv6 (Docker bridge is IPv4) | +| `set $grafana_upstream http://grafana:3000` | Store upstream in a variable so nginx resolves it at request time, not startup | +| `proxy_pass $grafana_upstream` | Forward requests to the Grafana container on the internal Docker network | | `proxy_set_header Host $host` | Forward the original `Host` header so Grafana sees the client's hostname | | `proxy_set_header X-Real-IP $remote_addr` | Pass the client's real IP address | | `proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for` | Append client IP to the proxy chain header | diff --git a/frontend/nginx.conf.template b/frontend/nginx.conf.template index 66873bff..88df162c 100644 --- a/frontend/nginx.conf.template +++ b/frontend/nginx.conf.template @@ -92,7 +92,9 @@ server { # --8<-- [start:grafana_proxy] location /grafana/ { - proxy_pass http://grafana:3000; + resolver 127.0.0.11 valid=30s ipv6=off; + set $grafana_upstream http://grafana:3000; + proxy_pass $grafana_upstream; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; From 87b5af6fce32b99694d6f255d913b28baa30f13e Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Sun, 15 Feb 2026 18:35:55 +0100 Subject: [PATCH 4/9] further fixes --- frontend/src/app.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/app.css b/frontend/src/app.css index 3f0df861..5f3d6f39 100644 --- a/frontend/src/app.css +++ b/frontend/src/app.css @@ -4,6 +4,9 @@ /* Tailwind CSS v4 */ @import "tailwindcss"; +/* Explicit source path for Docker builds (no .git/.gitignore in container) */ +@source "."; + /* Import component and page styles (after tailwindcss, before other directives) */ @import './styles/components.css'; @import './styles/pages.css'; From fb3ff7c0aa109ee3ae38dcd09b1ecd4c87316e9f Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Sun, 15 Feb 2026 18:46:44 +0100 Subject: [PATCH 5/9] further fixes --- frontend/src/app.css | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/frontend/src/app.css b/frontend/src/app.css index 5f3d6f39..e7d317e2 100644 --- a/frontend/src/app.css +++ b/frontend/src/app.css @@ -1,11 +1,8 @@ /* Import Google Fonts */ @import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&family=Inter:wght@400;500;600;700&display=swap'); -/* Tailwind CSS v4 */ -@import "tailwindcss"; - -/* Explicit source path for Docker builds (no .git/.gitignore in container) */ -@source "."; +/* Tailwind CSS v4 — source(".") sets scan root for Docker builds (no .git/.gitignore in container) */ +@import "tailwindcss" source("."); /* Import component and page styles (after tailwindcss, before other directives) */ @import './styles/components.css'; From 8bb57683e43d438018d24d1af5bb7108117f2a42 Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Sun, 15 Feb 2026 19:23:48 +0100 Subject: [PATCH 6/9] further fixes --- frontend/.dockerignore | 6 ++++-- frontend/.gitignore | 6 ++++++ frontend/src/app.css | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 frontend/.gitignore diff --git a/frontend/.dockerignore b/frontend/.dockerignore index 3f73aed7..b7bd6489 100644 --- a/frontend/.dockerignore +++ b/frontend/.dockerignore @@ -21,6 +21,9 @@ build/ # Testing coverage/ .nyc_output/ +test-results/ +playwright-report/ +e2e/ # Logs logs/ @@ -51,9 +54,8 @@ temp/ *.swp *.orig -# Git +# Git (keep .gitignore — Tailwind CSS v4 needs it for content detection) .git/ -.gitignore .gitattributes # Documentation diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 00000000..23f50edb --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +public/build/ +dist/ +coverage/ +test-results/ +playwright-report/ diff --git a/frontend/src/app.css b/frontend/src/app.css index e7d317e2..3f0df861 100644 --- a/frontend/src/app.css +++ b/frontend/src/app.css @@ -1,8 +1,8 @@ /* Import Google Fonts */ @import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&family=Inter:wght@400;500;600;700&display=swap'); -/* Tailwind CSS v4 — source(".") sets scan root for Docker builds (no .git/.gitignore in container) */ -@import "tailwindcss" source("."); +/* Tailwind CSS v4 */ +@import "tailwindcss"; /* Import component and page styles (after tailwindcss, before other directives) */ @import './styles/components.css'; From eade86ba1b78e04c13871d51c017161e60822e9d Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Sun, 15 Feb 2026 20:32:04 +0100 Subject: [PATCH 7/9] =?UTF-8?q?Replaced=20with=20a=20standard=20render-blo?= =?UTF-8?q?cking=20.=20The=20146KB=20bundle.css?= =?UTF-8?q?=20doesn't=20need=20this=20optimization=20=E2=80=94=20a=20norma?= =?UTF-8?q?l=20stylesheet=20load=20is=20perfectly=20fine=20and=20eliminate?= =?UTF-8?q?s=20the=20race=20condition=20entirel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/public/index.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/public/index.html b/frontend/public/index.html index 6df6c8c3..da0c9786 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -21,9 +21,7 @@ } - - - + From 33494e7053cc83cafa6327dc54cbe5588eb7c9fb Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Sun, 15 Feb 2026 21:08:01 +0100 Subject: [PATCH 8/9] =?UTF-8?q?rollup-plugin-postcss=20with=20minimize:=20?= =?UTF-8?q?true=20runs=20cssnano,=20which=20incorrectly=20handles=20Tailwi?= =?UTF-8?q?nd=20CSS=20v4's=20output=20(CSS=20nesting=20+=20@layer).=20It?= =?UTF-8?q?=20merges=20selectors=20from=20different=20responsive=20breakpo?= =?UTF-8?q?int=20=20=20rules=20into=20a=20single=20unrelated=20rule,=20com?= =?UTF-8?q?pletely=20destroying=20all=20responsive=20utility=20definitions?= =?UTF-8?q?.=20The=20class=20names=20existed=20in=20the=20CSS=20but=20mapp?= =?UTF-8?q?ed=20to=20wrong=20properties=20=E2=80=94=20.sm\:inline=20was=20?= =?UTF-8?q?being=20applied=20to=20space-y-0=20instead=20of=20display:=20?= =?UTF-8?q?=20=20inline.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/rollup.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/rollup.config.js b/frontend/rollup.config.js index a6e02157..c995cacc 100644 --- a/frontend/rollup.config.js +++ b/frontend/rollup.config.js @@ -175,7 +175,7 @@ export default { }), postcss({ extract: 'bundle.css', - minimize: production, + minimize: false, }), typescript({ sourceMap: true, From 1b8ea99479870079d7137db902a663ef65b5840d Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Sun, 15 Feb 2026 21:18:40 +0100 Subject: [PATCH 9/9] aother minification lib to use --- frontend/package-lock.json | 17 +++++++++++++++++ frontend/package.json | 1 + frontend/postcss.config.cjs | 7 ++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 715c11b3..e7662ded 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -70,6 +70,7 @@ "http-proxy": "^1.18.1", "jsdom": "^27.4.0", "monocart-reporter": "^2.10.0", + "postcss-lightningcss": "^1.0.2", "rollup-plugin-serve": "^3.0.0", "svelte-check": "^4.3.6", "svelte-eslint-parser": "^1.4.1", @@ -6698,6 +6699,22 @@ "postcss": "^8.2.15" } }, + "node_modules/postcss-lightningcss": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/postcss-lightningcss/-/postcss-lightningcss-1.0.2.tgz", + "integrity": "sha512-jI9gBe/2/ZEDYGDAHEHKbGLA3Dfn2uUTUCVsP3mDxpvmX6ifDdFqYB00GNRdny676gTcfo7XUCQoc4OYz20/TA==", + "dev": true, + "dependencies": { + "browserslist": "^4.19.1", + "lightningcss": "^1.22.0" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >= 21" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, "node_modules/postcss-load-config": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index 16ec596b..a1d57c3b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -79,6 +79,7 @@ "http-proxy": "^1.18.1", "jsdom": "^27.4.0", "monocart-reporter": "^2.10.0", + "postcss-lightningcss": "^1.0.2", "rollup-plugin-serve": "^3.0.0", "svelte-check": "^4.3.6", "svelte-eslint-parser": "^1.4.1", diff --git a/frontend/postcss.config.cjs b/frontend/postcss.config.cjs index 78286dd6..4653db3a 100644 --- a/frontend/postcss.config.cjs +++ b/frontend/postcss.config.cjs @@ -1,5 +1,10 @@ module.exports = { plugins: { "@tailwindcss/postcss": {}, + "postcss-lightningcss": { + lightningcssOptions: { + minify: true, + }, + }, }, -} \ No newline at end of file +}