Next.js 应用部署
Vercel 部署
Vercel 是 Next.js 的开发商,也是 Next.js 应用的推荐部署平台。Vercel 提供了一定额度的免费部署服务。
平台独立的争议性
Vercel 声称 Next.js 是平台独立的,可部署在各种云平台和独立服务器。但似乎只有 Vercel 对 Next.js 有完美的支持,其他云平台就没那么好了,例如 Netlify、AWS 等目前只有实验性支持。关于这方面的批评可参考 Remix 开发者 Kent C. Dodds 对 Next.js 的评价文章 Why I Won't Use Next.js 这篇文章。
Vercel 部署。
TIP
推荐阅读 Vercel 平台的官方文档 Next.js on Vercel 来了解更多。同时,Vercel 官方还提供了一些 社区模板,用于快速部署应用。
Docker 部署
对于大多数不使用云服务平台的公司来说,Docker 部署是最常见的方式,这可以和公司内部的 Kubernetes 集群、DevOps 等系统结合使用。
构建产物
和 Nuxt 构建器不同的是,Next.js 应用的构建产物中不包含 node_modules/
,因此需要在构建操作后复制相关的依赖,然后再运行应用。我们不希望将开发依赖也一起复制过来,我们可使用下面的 pnpm
命令来安装运行时依赖:
pnpm i --prod --ignore-scripts
使用 Docker 多阶段构建可以显著减小镜像大小,提高构建速度。这里使用两个阶段来构建 Next.js 应用的 Docker 镜像。
在第一阶段我们使用 Node.js 完整的 Bookworm 镜像来打包 Next.js 应用,此处可根据项目进行调整。在第二阶段我们将第一阶段的产物复制过来,然后确保 next
命令行工具在路径,并在启动时运行 Next.js 应用。
NOTE
node:bookworm
和 node:bookworm-slim
镜像的大小差异很大,前者包含了各种常见的构建工具,我们在打包应用时常常需要构建原生依赖库(用 C/C++/Rust 等编写的库),而后者则只包含了 Node.js 运行时。和纯 SPA 的前端应用不同,Next.js 的构建结果不是跨平台的,而且其中的原生依赖通常不是跨 Linux 二进制兼容的,因此我们选择同一个 Linux 发行版本的镜像来构建和运行应用。
ARG NODE_VERSION=22.2.0
ARG NPM_REGISTRY=https://registry.npmjs.org
# Builder image
FROM node:${NODE_VERSION}-bookworm as builder
ARG NPM_REGISTRY
WORKDIR /app
COPY . ./
ENV NODE_OPTIONS=--max-old-space-size=4096
RUN npm -v && \
npm config set registry ${NPM_REGISTRY} && \
npm i -g pnpm && \
pnpm -v && \
pnpm config set registry ${NPM_REGISTRY} && \
mv .env.production .env && \
pnpm i
RUN pnpm build
RUN mkdir -p dist/ && \
rm -rf .next/cache && \
mv .next/ dist/ && \
mv package.json dist/ && \
mv pnpm-lock.yaml dist/ && \
mv .env dist/ && \
mv tsconfig.json dist/ && \
cd dist/ && \
pnpm i --prod --ignore-scripts && \
rm -rf pnpm-lock.yaml
# Production image
FROM node:${NODE_VERSION}-bookworm-slim
WORKDIR /app
COPY --from=builder /app/dist /app
ENV PATH=/app/node_modules/.bin:$PATH
EXPOSE 3000
CMD ["next", "start"]
将上述 Dockerfile
文件放在 Next.js 项目根目录,然后执行构建命令:
docker build -t hello-nextjs .
构建成功后将生成名为 hello-nextjs
的镜像,我们可以使用下面的命令来运行:
docker run -p 3000:3000 hello-nextjs
添加依赖
generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "debian-openssl-1.1.x"]
}