Building assets inside the runtime image drags a compiler toolchain into production, and deleting it afterwards does nothing because layers are additive. Until May the workaround was two Dockerfiles and a copy step in CI.
FROM node:8 AS assets
WORKDIR /src
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM php:7.1-fpm
COPY --from=assets /src/public/dist /var/www/public/dist
Only the last stage becomes the image; everything above it is discarded, including Node and 400 MB of node_modules. Stages can be named or referenced by index, and naming them survives someone inserting a stage in the middle. The build still runs every stage, so this saves image size rather than build time.