Nexmoe

Nexmoe

一个开发者。关于勇敢与热爱,互联网/创造/赛博朋克
twitter
github

Optimize packaging Nuxt.js full-stack projects using Docker and pnpm.

This article will guide you on how to create an optimized Docker image for a full-stack project combining Prisma and Nuxt.js, and use pnpm as the package manager.

The final size of my project's image was reduced from 1.12GB to 160.21MB.

My Project Composition#

Nuxt.js is a server-side rendering application framework based on Vue.js, which is ideal for building modern web applications.

My project directly uses Nuxt to build a full-stack project.

  • Nuxt3
  • Prisma
  • PNPM

Getting Started with Building#

First, we will use the node:20-alpine base image, which is lighter, to reduce the final image size. Alpine Linux is popular due to its security, simplicity, and small size.

Multi-stage building is an effective strategy to reduce Docker image size. We will use three stages to build our image.

Stage 1: Building Dependencies#

ARG NODE_VERSION=node:20-alpine

FROM $NODE_VERSION AS dependency-base

WORKDIR /app

RUN npm install -g pnpm

COPY package.json pnpm-lock.yaml ./

RUN pnpm install --frozen-lockfile`

This stage is responsible for installing the dependencies of our project. We use pnpm instead of npm because pnpm is more efficient in terms of caching and disk usage.

Most projects now use pnpm as the package manager instead of npm.

Stage 2: Building the Application#

FROM dependency-base AS production-base

COPY . .

RUN pnpm run build 

In this stage, we copy the project code and execute the build command. Here, the build refers to the Nuxt.js build process, which generates static files and resources required for server-side rendering.

Stage 3: Generating the Production Image#

FROM $NODE_VERSION AS production

COPY --from=production-base /app/.output /app/.output

ENV NUXT_HOST=0.0.0.0 \
    NUXT_APP_VERSION=latest \
    DATABASE_URL=file:./db.sqlite \
    NODE_ENV=production

WORKDIR /app

EXPOSE 3000

CMD ["node", "/app/.output/server/index.mjs"]

Finally, we create an image for the production environment. This image only includes the necessary files to run the application, reducing unnecessary layers and keeping the image as slim as possible.

We also define some environment variables, such as NUXT_HOST and DATABASE_URL, which are required by the Nuxt.js application and Prisma. In this case, DATABASE_URL is set to use the SQLite file in the project's root directory as the database.

Finally, we expose port 3000 and specify the startup command to run the Nuxt.js application.

Image Size Comparison for Different Building Approaches#

The sizes are as follows:

  • 3-step build
  • 2-step build
  • Direct build

a3c345aaa51a4b8b802c25bc9d3591c0.png

Dockerfile Overview#

# Use a smaller base image
ARG NODE_VERSION=node:20-alpine

# Stage 1: Build dependencies
FROM $NODE_VERSION AS dependency-base

# Create app directory
WORKDIR /app

# Install pnpm
RUN npm install -g pnpm

# Copy the package files
COPY package.json pnpm-lock.yaml ./

# Install dependencies using pnpm
RUN pnpm install --frozen-lockfile

# Stage 2: Build the application
FROM dependency-base AS production-base

# Copy the source code
COPY . .

# Build the application
RUN pnpm run build

# Stage 3: Production image
FROM $NODE_VERSION AS production

# Copy built assets from previous stage
COPY --from=production-base /app/.output /app/.output

# Define environment variables
ENV NUXT_HOST=0.0.0.0 \
    NUXT_APP_VERSION=latest \
    DATABASE_URL=file:./db.sqlite \
    NODE_ENV=production

# Set the working directory
WORKDIR /app

EXPOSE 3000

# Start the app
CMD ["node", "/app/.output/server/index.mjs"]
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.