Menu

Next.jsとマルチゾーンを使用したマイクロフロントエンドの構築方法

マルチゾーンはマイクロフロントエンドへのアプローチであり、ドメイン上の大規模なアプリケーションを、それぞれがパスのセットを提供する複数のNext.jsアプリケーションに分離します。これは、アプリケーション内の他のページと関連のないページのコレクションがある場合に便利です。これらのページを別のゾーン(つまり、別のアプリケーション)に移動することで、各アプリケーションのサイズを削減でき、ビルド時間が向上し、ゾーンの1つにのみ必要なコードが削除されます。アプリケーションは分離されているため、マルチゾーンではドメイン上の他のアプリケーションが独自のフレームワークを選択できるようにもなります。

たとえば、分割したい以下のページセットがあるとしましょう。

  • /blog/* すべてのブログ投稿用
  • /dashboard/* ユーザーがダッシュボードにログインしたときのすべてのページ用
  • /* 他のゾーンでカバーされていない残りのウェブサイト用

マルチゾーンサポートを使用することで、3つのアプリケーションを作成できます。これらはすべて同じドメインで提供され、ユーザーには同じに見えますが、各アプリケーションを独立して開発およびデプロイできます。

3つのゾーン:A、B、C。異なるゾーンのルート間のハード遷移と、同じゾーン内のルート間のソフト遷移を示しています。

同じゾーン内のページ間をナビゲートすると、ソフトナビゲーションが実行されます。これはページの再読み込みを必要としないナビゲーションです。たとえば、このダイアグラムでは、/から/productsへの遷移がソフトナビゲーションになります。

1つのゾーン内のページから別のゾーン内のページへのナビゲーション(例:/から/dashboardへ)では、ハードナビゲーションが実行されます。これは現在のページのリソースをアンロードし、新しいページのリソースを読み込みます。頻繁に一緒にアクセスされるページは、ハードナビゲーションを回避するために同じゾーンに配置する必要があります。

ゾーンの定義方法

ゾーンは、他のゾーンのページおよび静的ファイルとの競合を回避するためにassetPrefixも構成する通常のNext.jsアプリケーションです。

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  assetPrefix: '/blog-static',
}

JavaScriptやCSSなどのNext.jsアセットは、他のゾーンのアセットと競合しないようにassetPrefixでプレフィックスが付けられます。これらのアセットは、各ゾーンの/assetPrefix/_next/...の下で提供されます。

別のより具体的なゾーンにルーティングされていないすべてのパスを処理するデフォルトアプリケーションは、assetPrefixを必要としません。

Next.js 15より前のバージョンでは、静的アセットを処理するための追加のリライトが必要な場合もあります。これはNext.js 15では不要になりました。

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  assetPrefix: '/blog-static',
  async rewrites() {
    return {
      beforeFiles: [
        {
          source: '/blog-static/_next/:path+',
          destination: '/_next/:path+',
        },
      ],
    }
  },
}

リクエストを適切なゾーンにルーティングする方法

マルチゾーンセットアップでは、異なるアプリケーションによって提供されるため、パスを正しいゾーンにルーティングする必要があります。任意のHTTPプロキシを使用できますが、Next.jsアプリケーションの1つを使用して、ドメイン全体のリクエストをルーティングすることもできます。

Next.jsアプリケーションを使用して正しいゾーンにルーティングするには、rewritesを使用できます。別のゾーンで提供される各パスに対して、そのパスを他のゾーンのドメインに送信するリライトルールを追加します。また、静的アセットのリクエストもリライトする必要があります。例:

next.config.js
async rewrites() {
    return [
        {
            source: '/blog',
            destination: `${process.env.BLOG_DOMAIN}/blog`,
        },
        {
            source: '/blog/:path+',
            destination: `${process.env.BLOG_DOMAIN}/blog/:path+`,
        },
        {
            source: '/blog-static/:path+',
            destination: `${process.env.BLOG_DOMAIN}/blog-static/:path+`,
        }
    ];
}

destinationはスキームとドメインを含む、ゾーンで提供されるURLである必要があります。これはゾーンの本番ドメインを指す必要がありますが、ローカル開発でlocalhostへのリクエストをルーティングするためにも使用できます。

補足:URLパスはゾーンに一意である必要があります。たとえば、2つのゾーンが/blogを提供しようとするとルーティングの競合が発生します。

プロキシを使用したリクエストのルーティング

rewritesを通じたリクエストのルーティングはリクエストのレイテンシーオーバーヘッドを最小化するために推奨されていますが、ルーティング時に動的判断が必要な場合はプロキシも使用できます。たとえば、フィーチャーフラグを使用してパスがルーティングされるべき場所を決定する場合(マイグレーション中など)、プロキシを使用できます。

proxy.js
export async function proxy(request) {
  const { pathname, search } = req.nextUrl;
  if (pathname === '/your-path' && myFeatureFlag.isEnabled()) {
    return NextResponse.rewrite(`${rewriteDomain}${pathname}${search}`);
  }
}

ゾーン間でのリンク

別のゾーン内のパスへのリンクは、Next.jsの<Link>コンポーネントではなく、aタグを使用する必要があります。これはNext.jsが<Link>コンポーネント内のすべての相対パスをプリフェッチしてソフトナビゲートしようとするためで、これはゾーン全体では機能しません。

コードの共有

異なるゾーンを構成するNext.jsアプリケーションはどのリポジトリにでも配置できます。ただし、これらのゾーンをmonorepoに配置して、より簡単にコードを共有することが便利な場合が多いです。異なるリポジトリに配置されたゾーンの場合、コードはパブリックまたはプライベートのNPMパッケージを使用して共有することもできます。

異なるゾーン内のページがリリースされるタイミングが異なる場合があるため、フィーチャーフラグを使用して、異なるゾーン全体で機能を統一的に有効または無効にすることができます。

Server Actions

マルチゾーンでServer Actionsを使用する場合、ユーザー向けドメインが複数のアプリケーションを提供する可能性があるため、ユーザー向けオリジンを明示的に許可する必要があります。next.config.jsファイルに以下の行を追加してください。

next.config.js
const nextConfig = {
  experimental: {
    serverActions: {
      allowedOrigins: ['your-production-domain.com'],
    },
  },
}

詳細はserverActions.allowedOriginsを参照してください。