When installing for production or in docker, it's important to keep package.json light and use cache.
When building you can not remove all devDependencies
since some of them are useful for building but not all of them.
This is also useful if you bump the version
prop regularly.
This script will clean up dependencies and returns only the mandatory fields. Adapt to your need
jq 'walk(
if type == "object" then with_entries(select(.key | test("jest|prettier|eslint|semantic|dotenv|nodemon|renovate") | not))
else . end) | { name, type, dependencies, devDependencies, packageManager, workspaces }'
# ------------------
# package.json cache
# ------------------
FROM apteno/alpine-jq:2022-03-27 AS deps
# To prevent cache invalidation from changes in fields other than dependencies
COPY package.json /tmp
RUN jq 'walk(if type == "object" then with_entries(select(.key | test("jest|prettier|eslint|semantic|nodemon|renovate") | not)) else . end) | { name, type, dependencies, devDependencies, packageManager, workspaces }' < /tmp/package.json > /tmp/deps.json
# ------------------
# New base image
# ------------------
FROM node:16.16.0-bullseye as tmp
# Setup the app WORKDIR
WORKDIR /app/tmp
# Copy and install dependencies separately from the app's code
# To leverage Docker's cache when no dependency has change
COPY --from=deps /tmp/deps.json ./package.json
COPY yarn.lock .yarnrc.yml ./
COPY .yarn .yarn
# Install dev dependencies
RUN true \
&& yarn install
# Copy everything back after installation
COPY . /app/tmp
# Remove all dev dependencies
RUN true \
&& yarn worskpaces focus --all --production \
&& rm -rf .yarn/
# ---- Web ----
# Resulting new, minimal image
# This image must have the minimum amount of layers
FROM node:16.16.0-bullseye as web
ENV NODE_ENV production
# Bash is just to be able to log inside the image and have a decent shell
# OpenSSL is here to handle HTTPS requests correctly
RUN apt-get -y install bash curl openssl
# Do not use root to run the app
USER node
WORKDIR /app
COPY --from=tmp --chown=node:node /app/tmp /app
EXPOSE 8000
Removing fields and packages on the fly can definitely break your builds.
- Typescript can break if you have referenced a removed package in
types
intsconfig.json
- Typescript won't compile if you remove all
@types
by default - Yarn can break in certain scenario if there is no
name
prop
Use regex at your advantages to restrict too wide selector, eg: jest|prettier
vs ^jest$|prettier