Creating Docker images in a lerna monorepo without the need for publishing

In the context of Lerna monorepos, the primary goal is to facilitate branch building and deployments.

The challenge arises from the fact that Lerna monorepos either consolidate dependencies in NPM or utilize yarn workspaces to achieve the same outcome, resulting in all dependencies being stored in the node_modules folder of the workspace/monorepo. This setup poses an issue when constructing Dockerfiles in subfolders, as Docker build contexts do not have access to these dependencies.

One potential solution could involve implementing a "lower" function (in contrast to hoisting) that relocates package dependencies into the node_modules directory of the Docker/package.json project before initiating the docker build process.

Therefore, the query is whether there are alternative approaches or existing methods that can address this issue more effectively?

Answer №1

To solve the challenges in my project, I have implemented a strategy using docker BuildKit. This involves first building all the workspace components and then creating a docker image for the project workspace while reusing previously built files.

The process includes copying the top package.json along with the yarn lock file in the dockerfile, followed by selecting the package.json specific to the required workspace. Subsequently, running commands for yarn install and yarn build to ensure smooth functionality.

Below is the outline of my project:

# base image
FROM @myscope/base:latest as base

# set working directory
WORKDIR /app

# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH

# install and cache app dependencies
COPY ["package.json","yarn.lock", "./"]
COPY ./packages/server/package.json ./packages/server/
COPY ./packages/shared/package.json ./packages/shared/
COPY ./packages/app/package.json ./packages/app/

RUN yarn install --frozen-lockfile --non-interactive --production=false --ignore-scripts
COPY . /app
RUN yarn build

FROM nodejs:14.15 as serverapp

WORKDIR /app

COPY ["package.json","yarn.lock", "./"]
COPY ./packages/server/package.json ./packages/server/
COPY ./packages/shared/package.json ./packages/shared/

RUN yarn install --frozen-lockfile --non-interactive --production=true --ignore-scripts

# copy artifact build from the 'build environment'
COPY --from=base /app/packages/shared/dist /app/packages/shared/dist

COPY ["./packages/server/", "./packages/server/"]

WORKDIR /app/packages/server
VOLUME ["/app/packages/server/logs", "/app/packages/server/uploads"]
EXPOSE $PORT
CMD ["yarn", "start"]

shared denotes a private workspace that serves as a dependency for the server workspace.

Answer №2

Despite finding no satisfactory answers, I took matters into my own hands and created an npm package that automatically generates a Dockerfile for lerna projects. This package leverages Docker's stage feature to create stages for each package.

Latest Version:

To get started, simply run the following command to allow lerna-dockerize to configure everything:

npx lerna-dockerize init

Original Version:

All you need is a base Dockerfile for global setup:

Dockerfile.base:

FROM node:14 as base
COPY ./package.json ./
RUN npm i
COPY ./lerna.json ./

And a template for the packages:

Dockerfile.template:

FROM base as build
COPY ./package.json ./
RUN npm install
RUN --if-exists npm run build

Additionally, you can create custom Dockerfiles for specific packages by adding them within the package itself. This will override the template with the custom Dockerfile.

Once set up, you can generate your Dockerfile by running the command:

npx lerna-dockerize

Answer №3

When it comes to yarn workspaces, my main goal was to eliminate the need for a private npm registry. I have found a solution by using webpack alongside both webpack-node-externals and

generate-package-json-webpack-plugin
. You can find more information about this approach at npmjs.com/package/generate-package-json-webpack-plugin.

With webpack node externals, we are able to bundle all dependencies from our other workspaces (libs) into the main app, making a private npm registry unnecessary. The generate package json plugin helps create a new package json file that includes all dependencies except those from our workspace. By placing this package json next to the bundle, we can easily use npm or yarn install in the dockerfile.

Although setting up the webpack config may take some time, I believe it is a scalable solution that helps maintain a clean dockerfile.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The installation process for Angular 4 on npm seems to be never-ending

Recently, I've been encountering difficulties while attempting to install the latest version of Angular 4. Despite upgrading my Node to 6.11.2 and npm to 3.10.10, the global installation of angular-cli is proving to be a time-consuming task with no su ...

Helping React and MUI components become mobile responsive - Seeking guidance to make it happen

My React component uses Material-UI (MUI) and I'm working on making it mobile responsive. Here's how it looks currently: https://i.sstatic.net/kxsSD.png But this is the look I want to achieve: https://i.sstatic.net/kJC2m.png Below is the code ...

Struggling with adding headers in React application

When I try to include an h1 heading, either the heading doesn't show up if I comment out the buttons, or if I comment out the heading, then the buttons don't display. But when both are included, nothing is displayed. Any suggestions on how to fix ...

Managing multiple sets of radio buttons using the useState hook

Within my renderUpgrades-function, I handle the options of an item by including them in radio-button-groups. Each item has multiple options and each option has its own radio-button-group. Typically, a radio-button-group can be managed using useState, wit ...

What is a reliable method to retrieve the text from the current LI if all LI elements in the list share the

I'm encountering an issue with retrieving the text from LI elements because I have 10 list items and they all have the same class name. When I attempt to fetch the text using the class name or id, I only get the text of the last item. Here is my code ...

Is there a way for us to determine the time at which the user last took a screenshot or photo?

I am currently developing a website using Django and I have a unique requirement. I need to access the last image that a user has taken on their phone, without the image being shared by anyone else. The photo must be captured by the user's device itse ...

Routes are no longer being qualified by Express once a subdomain is incorporated

We had developed a compact app that was working flawlessly, but then we were tasked with transforming it into something accessible for others in our organization to utilize... and that led to everything breaking down. Our initial setup included a simple ex ...

innerhtml does not display the entire array contents

I'm facing an issue with my innerHTML output where it seems to be displaying one less value than expected from the array. I've been unable to pinpoint the exact problem. await fetch(urlbody, bodyrequestOptions) .then((response) => response ...

What is the most effective way to display a star rating determined by the average score?

Currently, I am working on a project using Django and Jquery. The task at hand is to display hotel ratings with stars colored in orange based on an average score obtained from user votes. Let me provide you with an example: score = 8 vote= 2 average = 4 T ...

Display intricate header and preview in a printed datatable

Hey there, I've been using the Datatable plugin and it's really great. However, I've come across a problem with complex headers like this: <thead> <tr><td>some text</td></tr> <tr><td>some te ...

Encountering an Error when Integrating Pusher (real-time data library) with Next.js: PusherRequestError - Unexpected status code 400

I encountered an issue while trying to integrate Pusher into my Next.js application due to Vercel's restriction on websockets in their serverless functions. The error message I keep receiving after running the program with Pusher is: error - unhandled ...

Tips for defining a function without an arrow as a parameter

Understand that there may be individuals quick to flag this as a duplicate question, but trust me when I say that I have exhaustively searched on Google for almost an hour before turning to ask here. methods: { stylizeHeader: debounce(event => { ...

Incorrectly colored buttons upon clicking

I am experiencing an issue with my website where the color of the container div is not changing to the correct color when a button representing a color is clicked. Instead, it seems to be displaying the next color in the array of color codes that I have se ...

Concealing a Specific Element with Text using jQuery

Is there a way to conceal the section that includes the element labeled as "Product Tags" on a webpage? ...

Determine which JavaScript script to include based on whether the code is being executed within a Chrome extension

I am in the process of developing a Chrome extension as well as a web JavaScript application. I currently have an HTML container. I need the container.html file to include <script src="extension.js"> when it is running in the Chrome extension, and ...

Issue with retrieving relative time using Moment.js - fromNow()

I want to utilize moment.js to display relative time fromNow(), but I am encountering an issue where the values are being rounded and showing higher durations instead of exact completion times. For example, moment().subtract('s',110).fromNow() / ...

Utilizing jQuery AJAX to transfer files from the client side in .NET platform

I need to upload files from the client side using a jQuery Ajax function to a location on a different server, rather than sending them to my application's web server. This is to prevent unauthorized or virus-infected uploads to the application web ser ...

Tips on creating and elegantly showcasing an image from a PDF document on the screen with React-PDF

I am currently working on developing a user interface in JavaScript (React) to enable users to create PDFs directly on the screen. The concept involves having input boxes on one side, which instantly update the fields on the PDF displayed on the other side ...

Troubleshooting issues with applying styles in Vue framework when configured with webpack

I'm facing an issue with setting up the Vue framework using webpack. Specifically, I'm having trouble with styles not being applied when included in the <style> tag within single file components. Despite following several tutorials on this ...

Ways to have a React Component trigger a function with each state update

Using this specific component, the getDisplay function is triggered on every update like normal. When the <div> element is clicked, it becomes hidden: class Example extends React.Component { constructor(props) { super(props); thi ...