diff --git a/Dockerfile b/Dockerfile index b8bb1db8..a1597268 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,14 +45,28 @@ COPY frontend/package*.json ./frontend/ # guard keeps NODE_EXTRA_CA_CERTS unset on a clean checkout (no cert), so Node # does not warn about a missing cert path; a proxy-inspected build still gets # the cert because the file is present. -# Force devDependencies in: vite and the rest of the build toolchain live under -# devDependencies, and some base images / proxied environments default npm to -# omit=dev, which leaves `vite: not found` at build time. A build stage always -# needs them, so include them explicitly regardless of the ambient NODE_ENV. +# Install the frontend dependencies. vite and the rest of the build toolchain +# live under devDependencies, so include them explicitly (--include=dev) in case +# the environment defaults npm to omit=dev. Behind an inspecting proxy (Zscaler) +# npm's many parallel fetches intermittently drop, and npm can even abort with +# "Exit handler never called", leaving an incomplete node_modules with no vite. +# Raise fetch retries/timeouts to ride out flaky connections, then hard-verify +# that the toolchain actually landed so the failure is loud and immediate here +# rather than a confusing "vite: not found" three steps later. RUN if [ -f /usr/local/share/ca-certificates/corp-root-ca.crt ]; then \ export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt; \ fi; \ - cd frontend && npm ci --include=dev + cd frontend && \ + npm config set fetch-retries 5 && \ + npm config set fetch-retry-factor 2 && \ + npm config set fetch-retry-mintimeout 20000 && \ + npm config set fetch-retry-maxtimeout 120000 && \ + npm config set fetch-timeout 600000 && \ + npm ci --include=dev --no-audit --no-fund && \ + test -x node_modules/.bin/vite || { \ + echo "ERROR: node_modules/.bin/vite missing after npm ci (proxy likely truncated the install)."; \ + exit 1; \ + } # The frontend keeps its repo-relative layout here, because npm prebuild runs # `node ../scripts/stage-frontend.mjs`, which stages each plugin's frontend/ into