Zenn
🧞‍♀️

Next.jsのサーバーコンポーネントでrenderToStaticMarkupを使用する方法

に公開

はじめに

Next.jsのApp Routerでサーバーコンポーネントを使用している際に、Reactコンポーネントを静的なHTML文字列に変換したいケースがあります。

例えば、動的な文書生成やメール本文の作成などの用途です。

renderToStaticMarkupとは

renderToStaticMarkupは、React DOMのreact-dom/serverモジュールが提供する関数で、Reactコンポーネントを純粋なHTML文字列に変換します。

通常のReactレンダリングで生成されるDOM属性(data-reactrootなど)を含まない、軽量なHTMLを生成するために使用されます。

renderToStringとの違いは、renderToStaticMarkupがReact固有の属性を含まないため、サイズが小さく、クライアントでのハイドレーションが不要な場合に適しています。

問題: サーバーコンポーネントでの直接インポートはエラーになる

サーバーコンポーネントでは、react-dom/serverモジュールを直接インポートすることができません。

例えば、以下のようなコードはエラーになります。

// ❌ これはエラーになる
import { renderToStaticMarkup } from 'react-dom/server';

export default function MyServerComponent() {
  const html = renderToStaticMarkup(<div>Hello World</div>);
  return <div>{html}</div>;
}

実行すると、次のようなエラーが表示されます。

Error: You're importing a component that imports react-dom/server. To fix it, render or return the content directly as a Server Component instead for perf and security.
Learn more: https://nextjs.org/docs/app/building-your-application/rendering

react-dom/serverをインポートするコンポーネントをインポートしています。これを修正するには、パフォーマンスとセキュリティのために、コンテンツを直接Server Componentとしてレンダリングまたは返すようにしてください。詳細はこちら:https://nextjs.org/docs/app/building-your-application/rendering

解決策: 動的インポートを使用する

この問題を解決するために、動的インポートを使用する方法があります。

// test-render.tsx
export const renderToHTML = async (): Promise<string> => {
  const ReactDOMServer = await import("react-dom/server");
  const html = ReactDOMServer.renderToStaticMarkup(<button>hello</button>);
  return html;
};

この動的インポートを使用した関数は、Next.jsのServer ActionsやAPIルートなど、サーバーサイドで実行される様々な場所から呼び出すことができます。

解説

この解決策が機能する理由は以下のとおりです。

  • サーバーコンポーネントの制約: Next.jsのサーバーコンポーネントでは特定のモジュール(この場合はreact-dom/server)に直接アクセスできない制限があるようです。
  • 動的インポート: await import()を使うことで、実行時にモジュールをロードでき、静的な依存関係チェックを回避できます。

注意点

  • この方法はサーバーサイドでのみ動作します(ブラウザでは動作しません)
  • 実行時のパフォーマンスを考慮する必要があります(動的インポートにはオーバーヘッドがあります)
  • Next.jsのバージョンアップによって動作が変わる可能性があるため、最新の公式ドキュメントも参照してください

まとめ

Next.jsのサーバーコンポーネントでrenderToStaticMarkupを使用したい場合は、動的インポートを使用することで実現できます。この方法を使うことで、Reactコンポーネントをサーバーサイドで静的なHTMLに変換し、さまざまな用途に活用することができます。

参考

Unable to import react-dom/server in a server component #43810

Discussion

ログインするとコメントできます