🔥

【Remix】キャッシュ周りを理解する

2024/12/29に公開

Remixのキャッシュ

Remixではキャッシュを制御するために何個か機能が搭載されています。
それぞれどのような役割があるのかまとめました。

目次

  1. Remixのキャッシュの基本
  2. ローダーでのキャッシュ制御
  3. Cache-Controlヘッダーの活用
  4. CDNキャッシュの最適化
  5. セッションデータのキャッシュ

Remixのキャッシュの基本

Remixでは、主に以下の3つのレベルでキャッシュを制御できます。

  • ブラウザキャッシュ
  • CDNキャッシュ
  • サーバーサイドキャッシュ

これらのキャッシュを組み合わせて最適なキャッシュ戦略を組み立てていきます。

ローダーでのキャッシュ制御

Remixのローダーでは、レスポンスヘッダーを使用してキャッシュを制御できます。

export const loader = async ({ request }) => {
  const data = await fetchData();
  return json(data, {
    headers: {
      "Cache-Control": "max-age=300, s-maxage=3600",
    },
  });
};

主要なCache-Controlディレクティブ

  • max-age: ブラウザキャッシュの有効期間(秒)
  • s-maxage: CDNキャッシュの有効期間(秒)
  • private: ブラウザのみにキャッシュを許可
  • public: 共有キャッシュ(CDN等)を許可
  • no-cache: 再検証が必要
  • no-store: キャッシュを完全に無効化

キャッシュのユースケース

1. 静的データのキャッシュ

※86400は24時間

頻繁に更新されないデータの場合

export const loader = async ({ request }) => {
  const staticData = await fetchStaticContent();
  return json(staticData, {
    headers: {
      "Cache-Control": "public, max-age=3600, s-maxage=86400",
    },
  });
};

2. 動的データの再検証

頻繁に更新される可能性があるデータの場合

export const loader = async ({ request }) => {
  const dynamicData = await fetchDynamicContent();
  return json(dynamicData, {
    headers: {
      "Cache-Control": "public, max-age=0, s-maxage=60, stale-while-revalidate=30",
    },
  });
};

3. プライベートデータの制御

ユーザー固有のデータの場合

export const loader = async ({ request }) => {
  const userData = await fetchUserData();
  return json(userData, {
    headers: {
      "Cache-Control": "private, max-age=0, no-store",
    },
  });
};

CDNキャッシュの最適化

※CDNにキャッシュを保持することでオリジンサーバーへアクセスする必要がなくなるので時間短縮になる。

CDNを効果的に活用する

  1. 適切なキャッシュ時間の設定

    • 静的アセット: 長期キャッシュ
    • API応答: 状況に応じて短期キャッシュ
  2. Surrogate-Control ヘッダーの使用

export const loader = async ({ request }) => {
  return json(data, {
    headers: {
      "Surrogate-Control": "max-age=86400",
      "Cache-Control": "public, max-age=300",
    },
  });
};

セッションデータのキャッシュ

セッションデータを扱う際の注意点

export const loader = async ({ request }) => {
  const session = await getSession(request.headers.get("Cookie"));
  if (session.has("userId")) {
    return json(
      { data: await getUserData(session.get("userId")) },
      {
        headers: {
          "Cache-Control": "private, max-age=0, no-store",
          "Set-Cookie": await commitSession(session),
        },
      }
    );
  }
  return redirect("/login");
};

キャッシュの無効化

特定の状況でキャッシュを無効化する方法

  1. 明示的な無効化
export const action = async ({ request }) => {
  await updateData();
  return json(
    { success: true },
    {
      headers: {
        "Cache-Control": "no-store",
        "Clear-Site-Data": "cache",
      },
    }
  );
};
  1. 条件付きキャッシュ
export const loader = async ({ request }) => {
  const data = await fetchData();
  return json(data, {
    headers: {
      "Cache-Control": shouldCache ? "public, max-age=300" : "no-store",
    },
  });
};

まとめ

Remixでのキャッシュ戦略は、アプリケーションのパフォーマンスに大きな影響を与えます。
下記のポイントを押さえることが大切になります。

  1. データの特性に応じた適切なキャッシュ戦略の選択
  2. セキュリティを考慮したプライベートデータの取り扱い
  3. CDNを効果的に活用するための設定
  4. 適切なキャッシュ無効化の実装

これらの要素を適切に組み合わせることで、高速で信頼性の高いアプリケーションを構築することができます。

参考リンク

Discussion