nuxt / image

Plug-and-play image optimization for Nuxt applications.
https://image.nuxt.com
MIT License
1.35k stars 270 forks source link

[500] [IPX_ERROR] Could not load the \"sharp\" module using the linuxmusl-x64 runtime #1253

Closed vitaliytsoy closed 9 months ago

vitaliytsoy commented 9 months ago

image

Have a problem with the sharp module required by IPX dependency. Some images return 500 status with error. Happening because of the different installation and runtime environments.

Installation(pnpm i) and build(pnpm build) runs on ubuntu machine in github action. Then production build copied to Docker container that runs on node:20-alpine linux which uses musl libc and require sharp to use different binaries - specific for alpine environment (linuxmusl-x64).

Tried to install sharp manually as onptional dependency with pnpm.supportedArchitectures(link), had no effect - target binaries are still not present in production build.

  "pnpm": {
    "supportedArchitectures": {
      "os": ["linux", "current"],
      "cpu": ["x64", "current"],
      "libc": ["musl", "current"]
    }
  },

Found pretty ugly fix, which requires you to reinstall sharp package in server production build. Run npm install sharp --force --omit=dev --cpu=x64 --os=linux --libc=musl Inside .output/server folder Which basically installs @img/sharp-linuxmusl-x64 - sharp's optional dependency inside server production build.

Is it possible to take in consideration supportedArchitectures when building production build and add required dependency in server's node_modules?

Setup:

pnpm: v8.15.2 node: v20.7.0 @nuxt/image: ^1.3.0 nuxt": ^3.8.2

slantz commented 9 months ago

I had similar problem recently:

At the end after checking all the installed dependencies under the .output/server/node_modules the sharp distribution for linux was there, since we have it pinned in the pnpm-lock.yaml the project was working but always missing images.

But the problem was in how pnpm resolves the dependencies. Unlike npm or yarn, pnpm uses a content-addressable filesystem to store its packages, which results in a more efficient disk space usage and faster installations. However, this approach means that pnpm heavily relies on symlinks within the node_modules directory to link back to its global store, which is typically located in node_modules/.pnpm.

So on the last stage of the Dockerfile, the one which launches the running container, I had to import node_modules, so .output folder only was not enough. Here's the simple Dockerfile, that also hsa a line of RUN pnpm rebuild sharp just in case if pnpm-lock.yaml misses the linux definition for sharp.


# Base image for installing dependencies
FROM node:20.8.0-alpine as dependencies

WORKDIR /app

# Install system and build dependencies
RUN apk add --update --no-cache python3 make g++ vips-dev fftw-dev gcc libc6-compat autoconf automake libtool nasm libpng-dev \
    && ln -sf python3 /usr/bin/python \
    && python3 -m ensurepip \
    && pip3 install --no-cache --upgrade pip setuptools

# Install and configure pnpm
ENV PNPM_HOME=/pnpm
ENV PATH=$PNPM_HOME:$PATH

RUN corepack enable pnpm

# Copy package files and install dependencies
COPY ["package.json", "pnpm-lock.yaml", ".npmrc", "./"]

RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile

# https://github.com/nuxt/image/issues/1210#issuecomment-1917921546
RUN pnpm rebuild sharp

# Builder stage for compiling the application
FROM dependencies as builder

# Copy the entire project source files and build it
COPY . .
RUN pnpm run build

# Final production stage
FROM node:20.8.0-alpine as production

WORKDIR /app

ARG PORT=80
ENV NODE_ENV=production \
    UV_THREADPOOL_SIZE=16 \
    PORT=${PORT} \
    HOST=0.0.0.0

# Copy built assets and necessary scripts from the builder stage
# Copy the dependencies so pnpm can use those during the runtime
COPY --from=dependencies /app/node_modules ./node_modules
COPY --from=builder /app/.output ./.output

EXPOSE $PORT

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

HEALTHCHECK --start-period=5s --timeout=5s CMD curl -f http://0.0.0.0:${PORT}/health || exit 1
manniL commented 9 months ago

Duplicate of https://github.com/nuxt/image/issues/1210