Guide to Pnpm and Docker with TypeScript and Dockerfile
Posted October 13, 2023
Learn to create and build Pnpm with Docker along side Dockerfile. In this guide, you’ll create a Pnpm Docker container to fire up your Pnpm projects with different Dockerfile structures.
What You Will Learn
This is a comprehensive tutorial on Pnpm and Docker with Dockerfile . It covers all you need to know and get your Pnpm project running with Docker. You will learn the following:
- Creating a simple basic Pnpm TypeScript app and use Pnpm Docker file to run it.
- Create a Docker multistage Dockerfile for creating production Pnpm Docker containers
- Use template frameworks such as Nest.js and Next.js to bootstrap the Pnpm app and run them with Docker
Are you ready? Let’s now dive and take your Pnpm Docker app to the next level.
Prerequisites to Running Pnpm with Docker
- Pnpm only runs with Node.js 16.17 or newer. Ensure you have the latest version ready.
- Pnpm installed globally on your computer.
- Some basic knowledge working with Docker and Dockerfiles.
All Code samples used on this exmaple are on this GitHub repo
Using Pnpm and Docker: A TypeScript Example
Pnpm has support for TypeScript. I choose to use TypeScript, Pnpm and Docker so you can understand Pnpm Docker integration in detail.
First, you need a working TypeScript app. If you don’t have one, follow these steps and get ready.
- Get your Pnpm manager installed using npm or Yarn
npm install -g pnpm
yarn global add pnpm
- Create a project directory:
mkdir typescript_pnpm
cd typescript_pnpm
- Now use Pnpm to initialize your app:
pnpm init
- Install TypeScript for both your project and globally:
npm install -g typescript
pnpm add --save-dev typescript
- Use TypeScript to generate your
tsconfig.json
file:
npx tsc --init
- Get your packages ready using Pnpm manager:
pnpm add express ts-node @types/express @types/node
- Create your project files:
mkdir src
touch src/app.ts
- Create a simple TypeScript app:
// src/app.ts
import express from 'express';
const app = express();
const port = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.send('Hello, TypeScript with Express!');
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
- Update the
package.json
file to add build and start scripts.
"scripts": {
"start": "node dist/app.js",
"build": "tsc",
"dev": "ts-node src/app.ts"
},
- Make sure your
tsconfig.ts
file can access and build your app:
"rootDir": "./src",
"outDir": "./dist",
Your app is ready, and the run command should be:
# Compile typescript code to JavaScript
pnpm run build
# development (with automatic code reloading)
pnpm run dev
# production
pnpm start
This app runs using Pnpm as the packager manager; the question is, how do we get everything working as a Pnpm Docker container? Let’s find out.
Creating TypeScript Pnpm Dockerfile
If you have used Docker before, Dockerfile gives instructions on how docker should run your application as a container. This is not different to what you need for a Pnpm Docker container running.
On your project directory, create a Dockerfile
and add the following commands: I have added comments to make it easier for you to understand:
# Use an official Node.js, and it should be version 16 and above
FROM node:20-alpine
# Set the working directory in the container
WORKDIR /app
# Copy package.json and pnpm-lock.yaml
COPY pnpm-lock.yaml package.json ./
# Install app dependencies using PNPM
RUN npm install -g pnpm
# Install dependencies
RUN pnpm i
# Copy the application code
COPY . .
# Build the TypeScript code
RUN pnpm run build
# Expose the app
EXPOSE 3000
# Start the application
CMD ["pnpm", "start"]
Basically, this Dockerfile will complete all the previous steps that you would have done manually:
- You have Node.js runtime installed:
- Create your working directory
- Copy the
package.json
andpnpm-lock.yaml
files that contain all your dependencies and their related version. - To use Pnpm, you must install it within Docker using
RUN npm install -g pnpm
. - When it is installed, you can now run
pnpm i
to install dependencies, then copy your Pnpm TypeScript code to Docker - Because TypeScript must be complied with JavaScript,
RUN pnpm run build
will handle that perfectly, expose your application and start it usingCMD ["pnpm", "start"]
as you would on your terminal.
Your TypeScript Pnpm Dockerfile is ready. Now, you need to run the following command to build your Pnpm Docker image:
Ensure you run the command inside your project directory pointing to the Dockerfile
root path.
docker build -t pnpm-app .
This should build and Create your Pnpm image on Docker, so confirm those results:
To test your Pnpm Docker container, run the following command to run a Pnpm Docker container:
docker run -d -p 3000:3000 test-app
This should successfully open your application and serve on http://localhost:3000/
Creating Pnpm with Docker Multistage Builds
The above example is the simplest Pnpm Docker setup you can create. Using the same application, let’s dive deeper and create a multistage image that you can use to run the same application in production.
Multistage builds create different images within one Dockerfile. However, Doker will complete the artifacts of those images to create a final optimized image that is slim and production-ready.
If you want to learn more about Multistage Builds and how it Slims a Docker Image, check out this guide.
In the example, the following will be the perfect Dockerfile
example you can create to run your Pnpm Docker Multistage Builds:
FROM node:20-slim AS base
# Enable Corepack
RUN corepack enable
COPY . /app
WORKDIR /app
# Create a new image for production dependencies
FROM base as prod-deps
# Install production dependencies
# use a cache if available
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile
# Create build image for building the TypeScript code
FROM base AS build
# Install build dependencies
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
# Build the TypeScript
RUN pnpm run build
# Create an image base
FROM base
# Copy production dependencies from the prod-deps stage
COPY --from=prod-deps /app/node_modules /app/node_modules
# Copy the compiled TypeScript code from the build stage
COPY --from=build /app/dist /app/dist
# Expose incoming connections
EXPOSE 5000
# Start PNPM script
CMD [ "pnpm", "start" ]
Let’s digest what’s happening here:
- You have all the basic setup as the previous example, until you introduce another
FROM
statement. You basically run the as follows: - Stage 1: base image using the node.js that copies your project code and sets the working directory.
- Stage 2: prod-deps image - Install production dependencies using and if you have a cache, it improves build performance.
- Stage 3: build stage - build TypeScript code and prepare it for production.
- Stage 4: final image - creates the final image for production. Use the
prod-deps
andbuild
stages. Here, your Pnpm image is ready, and you can expose it and use the Pnpm start script.
In this case, Docker will only use the final image to compile Pnpm, making your app small and easy to deploy.
Now you can build your Pnpm Docker image:
docker build -t pnpm-multistage .
To test your Pnpm Docker container, run the following command to run a Pnpm Docker container:
docker run -d -p 5000:5000 pnpm-multistage
This should successfully open your Pnpm Docker application and serve on http://localhost:5000/
Using CLI Template Frameworks to Build Pnpm Docker
If you have used templated frameworks using CLI, such as Next.js, Nest.js, React and Nuxt, you will find that creating a Pnpm project is out of the box. This means you don’t have to go the long way as we did in the above steps.
So, in this section, you will learn how to take such applications and run Pnpm with Docker. In this example, I will use Nest.js. And you can use your framework of choice as well.
To use Nest.js, install its CLI:
npm install -g @nestjs/cli
Bootstrap your Nest.js app using the CLI as follows:
nest new pnpm_example
Be keen here as you must select to use Pnpm as your package manager:
This step is similar to using other framework CLIs such as create-react-app
, create-next-app
and create-nuxt-app
. So, you are using, let’s say, Next.js, you will create your Pnpm project specifying that in your command, i.e, pnpm create next-app my-nextjs-app
:
To verify your app was created using Pnpm and not NPM or Yarn, you should have a pnpm-lock.yaml
instead.
Now let’s create a Pnpm Docker container for the Next.js and Nest.js Examples so you can get the difference in details.
Change the directory to your pnpm_example
folder:
cd pnpm_example
Create a Dockerfile inside the pnpm_example
root as follows:
FROM node:20
# Install pnpm globally
RUN npm i -g pnpm
WORKDIR /app
# Copy pnpm-lock.yaml and package.json
COPY pnpm-lock.yaml package.json ./
# Install project dependencies using pnpm
RUN pnpm i
# Copy source code
COPY . .
EXPOSE 3000
# Command to run the container
CMD [ "pnpm", "start" ]
And you can see that your Pnpm Dockerfile is simple to understand, just like the previous step.
You can still go ahead and run the above just using the multistage build as follows:
FROM node:20
# Install pnpm globally
RUN npm i -g pnpm
#Build stage on top of 'base'
FROM base AS dependencies
WORKDIR /app
# Copy package.json and pnpm-lock.yaml
COPY package.json pnpm-lock.yaml ./
# Install dependencies
RUN pnpm install
# Create a build stage based on the 'base' stage
FROM base AS build
WORKDIR /app
# Copy code
COPY . .
# Copy dependencies stage
COPY --from=dependencies /app/node_modules ./node_modules
# Build the application using pnpm
RUN pnpm build
# Prune development dependencies
RUN pnpm prune --prod
# Deployment stage from the base
FROM base AS deploy
WORKDIR /app
# Copy the built application
COPY --from=build /app/dist/ ./dist/
# Copy the production dependencies
COPY --from=build /app/node_modules ./node_modules
# Run the application
CMD [ "node", "dist/main.js" ]
Conclusion
In this guide you’ve learned the following:
- How to Create a simple basic Pnpm TypeScript app and use Pnpm Docker to run it.
- Create a Docker multiBuild Dockerfile for creating production Pnpm Docker containers.
- Use a template framework such as nest.js to bootstrap the Pnpm app and run it with Docker.
More Related Articles:
-
Build Pnpm Workspace Monorepos with Docker Example Guide
Nov 12, 2023
-
Dockerize Node.js TypeScript with Docker, MySQL and Compose
Jan 25, 2024
-
Run Headless Kodi Player with Docker Compose Container for Home Server
Oct 12, 2023
-
Configure and Deploy Wazuh SIEM with Docker Compose Container
Oct 11, 2023