diff --git a/.dockerignore b/.dockerignore index df06f328..8491d13e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -48,3 +48,22 @@ src/frontend/.vite/ templates/ static/css/ static/js/ + +# Developer-only trees. `COPY . .` puts the whole context into /app, so anything +# left here ships to production: the CodeGraph index alone was 38MB of the image. +# NOTE: this file applies to EVERY stage, so `src/` cannot be listed — the +# frontend-builder stage needs it. The final stage drops it after the copy. +# Deliberately NOT listed: `data/` (languages.py:19 reads +# data/book-languages.json at runtime) and `genDebug.sh` (the final stage +# chmod +x's it, so excluding it fails the build). +.codegraph/ +.ruff_cache/ +.claude/ +tests/ +docs/ +scripts/ +compose/ +downloaded_files/ +frontend-dist/ +SESSION_STATE.md +Makefile diff --git a/Dockerfile b/Dockerfile index 1b2395a4..cb01304d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -57,11 +57,11 @@ ENV FLASK_PORT=8084 # Configure locale, timezone, and perform initial cleanup in a single layer RUN apt-get update && \ apt-get install -y --no-install-recommends \ - # For building C-extensions (cffi, gevent, etc.) - gcc \ - g++ \ - libffi-dev \ - python3-dev \ + # No C toolchain: every compiled dependency (cffi, gevent, greenlet, + # zope-interface) ships a cp314 manylinux wheel for amd64 and arm64, and + # the sdist-only ones are pure Python. The toolchain was 290MB of the + # runtime image, and python3-dev pulled Debian's libpython3.13 into a 3.14 + # image. If a dependency ever needs compiling, build it in a separate stage. # For locale locales tzdata \ # For healthcheck @@ -209,6 +209,13 @@ RUN --mount=type=cache,target=/root/.cache/uv \ uv pip install --python /app/.venv/bin/python --reinstall python-xlib==0.33 && \ /app/.venv/bin/python -c "import Xlib.X; assert hasattr(Xlib.X, 'FamilyServerInterpreted'), 'Xlib.X.FamilyServerInterpreted missing after fix'; print('Xlib namespace OK:', Xlib.__version__)" +# The venv's own pip goes too. uv seeded a copy into /app/.venv and nothing +# installs at runtime. setuptools deliberately STAYS: several deps still import +# pkg_resources on the hot path. +RUN rm -rf /app/.venv/bin/pip /app/.venv/bin/pip3 /app/.venv/bin/pip3.* \ + /app/.venv/lib/python*/site-packages/pip \ + /app/.venv/lib/python*/site-packages/pip-*.dist-info + # Keep SeleniumBase's bundled driver cache writable for the fixed non-root user. RUN SELENIUMBASE_DRIVERS_DIR=$(/app/.venv/bin/python -c "import pathlib, seleniumbase; print(pathlib.Path(seleniumbase.__file__).resolve().parent / 'drivers')") && \ chown -R 1000:1000 "${SELENIUMBASE_DRIVERS_DIR}" && \ @@ -224,6 +231,11 @@ COPY . . COPY --from=frontend-builder /frontend/dist /app/frontend-dist +# The frontend SOURCE cannot be excluded via .dockerignore — that file applies +# to every stage and frontend-builder needs src/. Only the built dist (copied +# above) is served at runtime, so drop the source here. +RUN rm -rf /app/src + # Image-owned runtime paths for the fixed non-root user. Root/PUID mode still # re-homes ownership at startup when needed. RUN mkdir -p \ @@ -262,6 +274,11 @@ COPY . . COPY --from=frontend-builder /frontend/dist /app/frontend-dist +# The frontend SOURCE cannot be excluded via .dockerignore — that file applies +# to every stage and frontend-builder needs src/. Only the built dist (copied +# above) is served at runtime, so drop the source here. +RUN rm -rf /app/src + # Image-owned runtime paths for the fixed non-root user. Root/PUID mode still # re-homes ownership at startup when needed. RUN mkdir -p \