0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.jsをVercelにデプロイ — CloudflareとAWSとの違いも比べた

0
Posted at

はじめに

Next.jsのアプリをデプロイする方法を調べた。

選択肢は大きく3つ。Vercel(Next.jsを作った会社のホスティング)、Cloudflare PagesAWS(ECS/Lambda)。それぞれ特徴が違うので、どれを選ぶべきか整理してからVercelで実際にデプロイした。


3つの選択肢の概要

Vercel:
  Next.jsを作ったVercel社のホスティング
  ゼロ設定でデプロイできる
  GitHubにプッシュするだけでCI/CDが動く

Cloudflare Pages:
  エッジネットワークでの配信
  無料枠が充実
  Workers/R2との連携が自然

AWS(ECS / Lambda):
  既存のAWSインフラと統合しやすい
  設定の自由度が高い
  他のAWSサービスとの連携が必要なとき

Vercelへのデプロイ

手順

# Vercel CLIをインストール
npm install -g vercel

# ログイン
vercel login

# デプロイ(初回)
vercel

# 本番デプロイ
vercel --prod

初回のvercelコマンドで対話形式の設定が走る。GitHubと連携するとプッシュのたびに自動デプロイされる。

vercel.json

{
  "buildCommand":  "npm run build",
  "outputDirectory": ".next",
  "installCommand": "npm ci",
  "framework":     "nextjs",
  "regions":       ["hnd1"],
  "env": {
    "NODE_ENV": "production"
  },
  "headers": [
    {
      "source":  "/(.*)",
      "headers": [
        {
          "key":   "X-Content-Type-Options",
          "value": "nosniff"
        },
        {
          "key":   "X-Frame-Options",
          "value": "DENY"
        }
      ]
    }
  ],
  "rewrites": [
    {
      "source":      "/api/backend/:path*",
      "destination": "https://api.example.com/:path*"
    }
  ]
}

regions: ["hnd1"]で東京リージョンを指定。日本向けのサービスは必ず設定する。

環境変数の設定

# CLIで設定
vercel env add FASTAPI_URL production
vercel env add AUTH_SECRET production

# 一覧確認
vercel env ls

VercelのダッシュボードのSettings → Environment Variablesでも設定できる。

環境の種類:
  Production  → main/masterブランチ
  Preview     → PRブランチ(プレビュー環境が自動生成される)
  Development → ローカル開発

PRを作るとプレビューURLが自動生成されるのはVercel特有の機能で便利。


Vercelのプレビューデプロイ

main ブランチにPRを作る
        ↓
Vercelが自動でビルド
        ↓
プレビューURL(https://my-app-git-feature-xxx.vercel.app)が発行される
        ↓
レビューアーがプレビューURLで動作確認
        ↓
マージすると本番に自動デプロイ

PRごとにプレビュー環境が作られる。LaravelをVagrantやDockerで開発していたときは「本番に近い環境での確認」が面倒だったが、Vercelだとブランチを作るだけで確認できる。


Cloudflare Pagesへのデプロイ

# Wranglerをインストール
npm install -g wrangler

# ログイン
wrangler login

# デプロイ
npx wrangler pages deploy .next --project-name my-app
# wrangler.toml
name = "my-app"
compatibility_date = "2024-01-01"
pages_build_output_dir = ".next"

[vars]
NODE_ENV = "production"

Cloudflare PagesのNext.js対応

# @cloudflare/next-on-pagesを使う
npm install -D @cloudflare/next-on-pages
// package.json
{
  "scripts": {
    "pages:build": "npx @cloudflare/next-on-pages",
    "pages:deploy": "wrangler pages deploy .vercel/output/static"
  }
}
// next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
    // Cloudflare Pages用の設定
    experimental: {
        runtime: 'edge',
    },
};

export default nextConfig;

Cloudflare PagesはEdge Runtimeで動くため、Node.js固有のAPIが使えない制約がある。fsモジュールや一部のNode.jsライブラリが使えないので、FastAPIへのAPIコールにnode-fetchを使っている場合は確認が必要。

Cloudflare Pagesの制約

✓ 無料枠が充実(月500ビルド、無制限リクエスト)
✓ エッジで動くので世界中で高速
✓ Workers/D1/R2との連携が自然

✗ Node.js APIが使えない(EdgeランタイムのみサポートでNが出ることがある)
✗ Next.jsのすべての機能に対応していない場合がある
✗ 公式サポートではないためVercelより設定が複雑

AWSへのデプロイ

パターン① ECSでDockerコンテナをデプロイ

# Dockerfile
FROM node:20-slim AS base

FROM base AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci

FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM base AS runner
WORKDIR /app
ENV NODE_ENV production

COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static

RUN useradd -r nextjs
USER nextjs

EXPOSE 3000
CMD ["node", "server.js"]
# compose.yaml(ローカル確認用)
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - FASTAPI_URL=http://backend:8000
// next.config.mjs(standaloneモードを有効化)
const nextConfig = {
    output: 'standalone',  // Dockerに必要な最小構成を出力
};

output: 'standalone'を設定するとDockerイメージを最小化できる。

パターン② Lambda + API Gatewayでサーバーレス

npm install -D serverless serverless-nextjs-plugin
# serverless.yml
myNextApp:
  component: '@sls-next/serverless-component@latest'
  inputs:
    bucketName: my-next-app-bucket
    name:
      defaultLambda: my-next-app
    domain: example.com

3つのプラットフォームの比較

項目 Vercel Cloudflare Pages AWS ECS
設定の手軽さ
プレビュー環境 自動生成 自動生成 自前実装
無料枠 制限あり 充実 従量課金
エッジ配信 設定必要
Node.js対応 △(Edge制約)
既存インフラ統合
カスタムドメイン 無料 無料 別途設定
バンドル料金 高め 安め 使った分

Vercelを選ぶ理由・選ばない理由

Vercelを選ぶ:
  ✓ Next.jsのすべての機能を確実に使いたい
  ✓ プレビュー環境を手軽に使いたい
  ✓ デプロイの設定に時間をかけたくない
  ✓ チームが小さい・個人開発

Vercelを選ばない:
  ✗ AWSにすでに構築済みのインフラがある
  ✗ コスト管理をAWSで一元化したい
  ✗ データを特定リージョンに閉じたい要件がある
  ✗ 大規模トラフィックでコストが高くなる

実際のCI/CDフロー(GitHub Actions + Vercel)

Vercelの自動デプロイではなく、GitHub ActionsからVercelにデプロイする構成。テストを挟みたいときに使う。

# .github/workflows/deploy.yml
name: Deploy to Vercel

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run type check
        run: npm run type-check

      - name: Run lint
        run: npm run lint

      - name: Run tests
        run: npm test

  deploy-preview:
    needs: test
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request'
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to Vercel (Preview)
        uses: amondnet/vercel-action@v25
        with:
          vercel-token:   ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id:  ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}

  deploy-production:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to Vercel (Production)
        uses: amondnet/vercel-action@v25
        with:
          vercel-token:   ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id:  ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args:    '--prod'

カスタムドメインの設定

# Vercel CLIでドメインを追加
vercel domains add example.com

# DNSの確認
vercel domains inspect example.com
DNSの設定(ドメインレジストラ側):

Aレコード:
  @ → 76.76.21.21

CNAMEレコード:
  www → cname.vercel-dns.com

Cloudflareでドメインを管理している場合は、CloudflareのProxyを経由するかどうかを選べる。VercelのSSL証明書とCloudflareのProxyが競合する場合はDNS-onlyにする。


パフォーマンス最適化

画像最適化

import Image from 'next/image';

export default function Hero() {
    return (
        <Image
            src="/hero.jpg"
            alt="ヒーロー画像"
            width={1200}
            height={600}
            priority              // LCPに影響する画像はpriority
            placeholder="blur"    // ぼかしのプレースホルダー
        />
    );
}

フォントの最適化

// app/layout.tsx
import { Noto_Sans_JP } from 'next/font/google';

const notoSansJP = Noto_Sans_JP({
    subsets:  ['latin'],
    weight:   ['400', '500', '700'],
    display:  'swap',
    variable: '--font-noto-sans-jp',
});

export default function RootLayout({
    children,
}: {
    children: React.ReactNode;
}) {
    return (
        <html lang="ja" className={notoSansJP.variable}>
            <body className="font-sans">{children}</body>
        </html>
    );
}

next/fontを使うとGoogleフォントがビルド時にダウンロードされてセルフホストされる。外部フォントのリクエストが不要になってパフォーマンスが上がる。


まとめ

  • Vercelはゼロ設定でNext.jsをデプロイできる。PRごとのプレビュー環境が便利
  • Cloudflare PagesはEdge配信と無料枠が充実。Node.js APIの制約に注意
  • AWSはECSでDockerコンテナをデプロイする方法が既存インフラとの統合に向いている
  • 個人開発・小規模チームはVercelが一番手軽
  • 既存のAWSインフラがある場合はECSが自然な選択

PHPのデプロイ(LaravelをサーバーにSSHしてgit pull + composer install)と比べると、Vercelのデプロイは「GitHubにプッシュするだけ」で別次元に楽だった。プレビュー環境の自動生成はチームレビューを大きく変える機能で、一度使うと戻れない。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?