第 31 课:部署(上)— Node.js、Docker 与静态导出

2 阅读3分钟

模块五:部署与生产 | 前置要求:第 18 课 覆盖文档:Deploying、Static Exports、Single-Page Applications 时长:90 分钟


一、Node.js 部署

1.1 标准流程

# 1. 构建生产产物
next build

# 2. 启动生产服务器
next start -p 3000

构建产物在 .next/ 目录,next start 启动一个 Node.js HTTP 服务器,支持所有 Next.js 功能:SSR、ISR、Middleware、Streaming 等。

1.2 构建产物结构

.next/
├── server/          # 服务端渲染代码
├── static/          # 客户端静态资源
├── cache/           # ISR/缓存数据
├── BUILD_ID         # 构建标识
└── routes-manifest.json

二、Docker 部署

2.1 output: 'standalone' 模式

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  output: 'standalone',
}

export default nextConfig

standalone 模式自动追踪依赖,生成最小化独立运行目录,无需安装 node_modules

2.2 多阶段 Dockerfile

# 阶段 1:安装依赖
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile

# 阶段 2:构建
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# 阶段 3:生产镜像(最小化)
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production

# 复制 standalone 产物
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public

EXPOSE 3000
CMD ["node", "server.js"]

2.3 镜像对比

方案镜像大小说明
完整 node_modules~1GB+包含所有依赖
standalone~100-200MB仅必要文件
standalone + alpine~80-150MB最小基础镜像

三、静态导出

3.1 配置

// next.config.ts
const nextConfig: NextConfig = {
  output: 'export',
}

next build 生成纯静态 HTML/CSS/JS 到 out/ 目录,可部署到任何静态托管服务。

3.2 支持与不支持的功能

支持不支持
Server Components(静态渲染)动态路由(无 generateStaticParams)
Client ComponentsRoute Handlers(依赖请求的)
Image Optimization(自定义 loader)Middleware
CSS/Sass/TailwindISR / 增量静态再生
generateStaticParamscookies() / headers()

3.3 图片优化适配

const nextConfig: NextConfig = {
  output: 'export',
  images: {
    loader: 'custom',
    loaderFile: './image-loader.ts',
  },
}
// image-loader.ts
export default function cloudinaryLoader({
  src, width, quality,
}: { src: string; width: number; quality?: number }) {
  return `https://res.cloudinary.com/demo/image/upload/w_${width},q_${quality || 75}/${src}`
}

四、SPA 模式

静态导出 + 客户端路由 = 单页应用:

// app/layout.tsx
export const dynamic = 'force-static'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>{children}</body>
    </html>
  )
}

所有页面预渲染为静态 HTML,客户端接管路由导航。


五、GitHub Pages 部署

# .github/workflows/deploy.yml
name: Deploy to GitHub Pages
on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npm ci && npm run build
      - uses: actions/upload-pages-artifact@v3
        with:
          path: ./out

  deploy:
    needs: build
    runs-on: ubuntu-latest
    permissions:
      pages: write
      id-token: write
    steps:
      - uses: actions/deploy-pages@v4

注意 basePath 配置:

const nextConfig: NextConfig = {
  output: 'export',
  basePath: '/repo-name',  // GitHub Pages 子路径
}

六、Adapters 概览

适配器状态说明
Vercel已验证原生支持所有功能
Bun已验证兼容 Node.js API
Netlify社区通过 @netlify/next 适配
AWS Lambda社区需 serverless 框架
Cloudflare社区Edge Runtime 限制

6.1 平台功能矩阵

功能Node.jsDocker静态导出Vercel
SSR完整完整不支持完整
ISR完整完整不支持原生
Middleware完整完整不支持Edge
Image Optimization完整完整自定义 loader原生
Streaming完整完整不支持原生
PPR完整完整不支持原生

七、课后练习

练习 1:Node.js 部署(基础)

在本地运行 next build + next start,检查 .next/ 目录结构。

练习 2:Docker 化(中阶)

编写多阶段 Dockerfile,使用 output: 'standalone',对比镜像大小。

练习 3:静态导出(高阶)

将一个动态路由项目改为 output: 'export',处理所有不兼容功能。

练习 4:平台评估(资深)

评估你的目标部署平台,列出功能支持矩阵和性能保真度差异。


八、关键要点总结

  1. Node.js 部署next build + next start,支持所有功能
  2. Dockeroutput: 'standalone' + 多阶段构建,镜像缩小 80%+
  3. 静态导出output: 'export',纯静态但功能受限
  4. SPA 模式:静态导出 + 客户端路由
  5. Adapters:Vercel/Bun 已验证,其他平台通过社区适配器
  6. 选择依据:功能需求 → 基础设施条件 → 性能保真度

下一课:第 32 课:部署(下)