Next.js App Router で route 毎に Cache-Control を任意に指定したいときは middleware を使う(今のところ)

App Router でトラディショナルな動的 SSR

既存〜今後のコンポーネントの互換性を踏まえて React を前提とし、フレームワークの分散を抑制するため Next.js を選び、多少の冒険ではあったが App Router での開発にトライしています。 今後は現在 Ruby on Rails のモノリシックコードベースで展開されている複数プロダクトを分割し、それぞれを Next.js で水平展開し直していくイメージです。

で、まずは App Router のフルパワー(サバクラに渡る重厚なキャッシュ機構)を要しない、ログインする操作こそあれだページの9割9分が Server Components としてレンダリング可能な領域をリプレース中。 つまり

// app/layout.js

export const fetchCache = 'default-no-store';

export const dynamic = 'force-dynamic';

こう。fetch のキャッシュを封じ、常にダイナミックレンダリングさせるトラディショナルスタイルの強制ですね。

開発対象がイザとなったら引き返せるサイズであり、逃げ道を残しておく意味でも距離感をとってます

next.config.jsheadersCache-Control は対象外

トラディショナルな動的 SSR は CDN などのレイヤーでキャッシュを効かせるのを至高とする派閥なので、Cache-Control をマニュアルで指定したいところですが App Router では Route Segment はおろか next.config.js でも封じられています。

You cannot set Cache-Control headers in next.config.js for pages or assets, as these headers will be overwritten in production to ensure that responses and static assets are cached effectively. next.config.js Options: headers | Next.js

設計意図的にそりゃそうよねぇ... (´—`)

Middleware を設定しましょう

Routing: Middleware | Next.js のとおり、Middleware で設定できます。まさしくミドルウェアという趣で、App Router の外側に位置するものであり app ディレクトリと同階層に middleware.ts を配置します。

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const response = NextResponse.next({
    request: {
      headers: new Headers(request.headers),
    },
  });
  const pathname = request.nextUrl.pathname;

  if (pathname.startsWith('/foo') {
    response.headers.set('cache-control', '任意のキャッシュコントロール');
  }

  return response;
}

export const config = {
  matcher: [
    '/foo/:path*',
  ],
};

今のところはとりあえずこの方法でやりたいことを実現できます。

generateHeaders() ??

シンプルな処理であればミドルウェアで問題なさそうですが、レンダリング対象のデータを交えて込みいった設定が必要になると generateMetadata() のように layout.tsxpage.tsx の中で設定させてくれよ〜、という気にもなってきそうです。

A use case here should convey the following information: - What capability do you want to achieve? (i.e. I'd like my pages to be cached by the browser) - What header or headers are necessary to coordinate this behavior? - What makes Middleware and or static headers insufficient We are aware there is a need for many potential users that isn't yet being met as well as we'd like. App Router Custom Header Use Cases · vercel/next.js · Discussion #58110

そういう機能の追加も検討はしているようでユースケースを募る disucussions もあがっていたので、そのうち何らかの形でニーズに応えるパスも用意されるのではないかと。


Author

ahomuAyumu Sato

overflow, Inc.VPoE

東京資本で生きる名古屋の鳥類

Web 技術、組織開発、趣味など雑多なブログ。技術の話題は zenn にも分散して投稿しています。

Bio: aho.mu
X: @ahomu
Zenn: ahomu
GitHub: ahomu

Related

Latest

Archives

Tags

Search