How to build a docker image from a nodejs project in a monorepo with yarn workspaces

I’ve worked on a project following a structure similar to yours, it was looking like:

project
├── package.json
├── packages
│   ├── package1
│   │   ├── package.json
│   │   └── src
│   ├── package2
│   │   ├── package.json
│   │   └── src
│   └── package3
│       ├── package.json
│       └── src
├── services
│   ├── service1
│   │   ├── Dockerfile
│   │   ├── package.json
│   │   └── src
│   └── service2
│       ├── Dockerfile
│       ├── package.json
│       └── src
└── yarn.lock

The services/ folder contains one service per sub-folder. Every service is written in node.js and has its own package.json and Dockerfile.
They are typically web server or REST API based on Express.

The packages/ folder contains all the packages that are not services, typically internal libraries.

A service can depend on one or more package, but not on another service.
A package can depend on another package, but not on a service.

The main package.json (the one at the project root folder) only contains some devDependencies, such as eslint, the test runner etc.

An individual Dockerfile looks like this, assuming service1 depends on both package1 & package3:

FROM node:8.12.0-alpine AS base

WORKDIR /project

FROM base AS dependencies

# We only copy the dependencies we need
COPY packages/package1 packages/package1
COPY packages/package3 packages/package3

COPY services/services1 services/services1

# The global package.json only contains build dependencies
COPY package.json .

COPY yarn.lock .

RUN yarn install --production --pure-lockfile --non-interactive --cache-folder ./ycache; rm -rf ./ycache

The actual Dockerfiles I used were more complicated, as they had to build the sub-packages, run the tests etc. But you should get the idea with this sample.

As you can see the trick was to only copy the packages that are needed for a specific service.
The yarn.lock file contains a list of package@version with the exact version and dependencies resolved. To copy it without all the sub-packages is not a problem, yarn will use the version resolved there when installing the dependencies of the included packages.

In your case the react-native project will never be part of any Dockerfile, as it is the dependency of none of the services, thus saving a lot of space.

For sake of conciseness, I omitted a lot of details in that answer, feel free to ask for precision in the comment if something isn’t really clear.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)