Astro SSR(サーバーサイドレンダリング)

作成日:
Astro SSR frontend

AstroはデフォルトでSSG(静的サイト生成)ですが、アダプターを使用することでSSR(サーバーサイドレンダリング)やハイブリッドレンダリングに対応できます。

SSRとは

SSR(Server-Side Rendering)では、ページをリクエスト時にサーバーでレンダリングします。

SSRのメリット:

  • リクエストごとに動的なコンテンツを生成
  • ユーザー認証に基づくパーソナライズ
  • APIからのリアルタイムデータ取得
  • Cookie、セッション、ヘッダーへのアクセス

SSRのデメリット:

  • サーバーが必要(静的ホスティング不可)
  • レスポンス時間がSSGより遅い
  • サーバーコストがかかる

出力モード

static(デフォルト)

すべてのページを事前に生成。

// astro.config.mjs
export default defineConfig({
  output: 'static',
});

server

すべてのページをリクエスト時に生成。

// astro.config.mjs
export default defineConfig({
  output: 'server',
  adapter: node({ mode: 'standalone' }),
});

hybrid

デフォルトは静的、必要なページのみSSR。

// astro.config.mjs
export default defineConfig({
  output: 'hybrid',
  adapter: node({ mode: 'standalone' }),
});

アダプター

SSRを有効にするには、ホスティング環境に対応したアダプターが必要です。

Node.js

npx astro add node
// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';

export default defineConfig({
  output: 'server',
  adapter: node({
    mode: 'standalone',  // または 'middleware'
  }),
});

mode オプション:

  • standalone: 独立したNode.jsサーバーとして動作
  • middleware: Express等のミドルウェアとして動作

Vercel

npx astro add vercel
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';

export default defineConfig({
  output: 'server',
  adapter: vercel(),
});

Netlify

npx astro add netlify
// astro.config.mjs
import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify';

export default defineConfig({
  output: 'server',
  adapter: netlify(),
});

Cloudflare

npx astro add cloudflare
// astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';

export default defineConfig({
  output: 'server',
  adapter: cloudflare(),
});

ハイブリッドレンダリング

output: 'hybrid'では、デフォルトは静的生成で、必要なページのみSSRにできます。

静的ページ(デフォルト)

---
// このページは静的に生成される(デフォルト)
const posts = await getCollection('blog');
---
<h1>ブログ一覧</h1>

SSRページ

---
// このページはリクエスト時に生成
export const prerender = false;

const user = await getUser(Astro.cookies.get('session'));
---
<h1>ダッシュボード: {user.name}</h1>

server モードでの静的化

output: 'server'の場合、特定のページを静的にするには:

---
export const prerender = true;
---

Astroオブジェクト

SSRモードでは、Astroオブジェクトから追加の情報にアクセスできます。

リクエスト情報

---
// リクエストURL
const url = Astro.url;
const pathname = Astro.url.pathname;
const searchParams = Astro.url.searchParams;

// クエリパラメータ
const page = Astro.url.searchParams.get('page');

// リクエストヘッダー
const userAgent = Astro.request.headers.get('user-agent');
---
---
// Cookieの読み取り
const sessionId = Astro.cookies.get('session')?.value;

// Cookieの設定
Astro.cookies.set('visited', 'true', {
  httpOnly: true,
  secure: true,
  maxAge: 60 * 60 * 24 * 7,  // 1週間
});

// Cookieの削除
Astro.cookies.delete('session');
---

リダイレクト

---
const user = await getUser(Astro.cookies.get('session'));

if (!user) {
  return Astro.redirect('/login');
}
---

レスポンスヘッダー

---
// キャッシュ制御
Astro.response.headers.set('Cache-Control', 'public, max-age=3600');
---

APIエンドポイント

SSRモードでは、動的なAPIエンドポイントを作成できます。

src/pages/api/user.ts:

import type { APIRoute } from 'astro';

export const GET: APIRoute = async ({ cookies }) => {
  const sessionId = cookies.get('session')?.value;
  
  if (!sessionId) {
    return new Response(JSON.stringify({ error: 'Unauthorized' }), {
      status: 401,
      headers: { 'Content-Type': 'application/json' },
    });
  }
  
  const user = await getUser(sessionId);
  return new Response(JSON.stringify(user), {
    headers: { 'Content-Type': 'application/json' },
  });
};

export const POST: APIRoute = async ({ request }) => {
  const data = await request.json();
  // データ処理...
  return new Response(JSON.stringify({ success: true }), {
    headers: { 'Content-Type': 'application/json' },
  });
};

Node.jsでの実行

# ビルド
npm run build

# 実行
node ./dist/server/entry.mjs

環境変数

HOSTPORTでサーバー設定を制御:

HOST=0.0.0.0 PORT=3000 node ./dist/server/entry.mjs

参考