SPA モード
Remix は当初から、サーバーアーキテクチャはあなた自身のものだと考えてきました。そのため、Remix は Web Fetch API を基盤として構築されており、組み込みの adapter やコミュニティ提供の adapter を介して、あらゆる最新の ランタイム 上で動作します。私たちは、サーバーを持つことは、ほとんどのアプリにとって最高の UX/パフォーマンス/SEO などをもたらすと考えていますが、現実世界では、シングルページアプリケーション (SPA) に適したユースケースが数多く存在することも否定できません。
- サーバーを管理したくない場合、GitHub Pages やその他の CDN 上の静的ファイルを使用してアプリをデプロイしたい場合
- Node.js サーバーを実行したくない場合
- React Router アプリを Remix に移行 したい場合
- サーバーレンダリングできない特殊な埋め込みアプリを開発している場合
- 「あなたのボスは SPA アーキテクチャの UX 上限を気にしておらず、開発チームにアーキテクチャを再構築するための時間/能力を与えてくれない」- Kent C. Dodds
そのため、2.5.0 (RFC) で SPA モード のサポートを追加しました。これは、クライアントデータ API を基盤として構築されています。
SPA モードとは
SPA モードは、createBrowserRouter
/RouterProvider
を使用して独自の React Router + Vite セットアップを行った場合に得られるものとほぼ同じですが、いくつかの Remix の利点も追加されています。
- ファイルベースのルーティング (または
routes()
を使用した構成ベース) route.lazy
を使用した自動ルーティングベースのコード分割- ルートモジュールを事前にフェッチするための
<Link prefetch>
サポート - Remix の
<Meta>
/<Links>
API を使用した<head>
の管理
SPA モードは、実行時に Remix サーバーを実行する予定がなく、ビルド時に静的な index.html
ファイルを生成し、データのロードと変更には クライアントデータ API のみを使用することを Remix に伝えます。
index.html
は、root.tsx
ルートの HydrateFallback
コンポーネントから生成されます。index.html
を生成するための最初の「レンダリング」には、ルートよりも深いルートは含まれません。これにより、index.html
ファイルは、CDN/サーバーで適切に構成されていれば、/
以外のパス (例: /about
) で配信/ハイドレートできます。
使用方法
リポジトリの SPA モードテンプレートを使用して、すぐに使い始めることができます。
または、Remix+Vite アプリで Remix Vite プラグインの構成に ssr: false
を設定することで、手動で SPA モードを有効にすることができます。
開発
SPA モードでは、従来の Remix SSR アプリと同じように開発を行い、実際には実行中の Remix 開発サーバーを使用することで、HMR/HDR を有効にします。
本番環境
SPA モードでアプリをビルドすると、Remix は /
ルートのサーバーハンドラーを呼び出し、レンダリングされた HTML を、クライアント側の資産 (デフォルトでは build/client/index.html
) と一緒に index.html
ファイルに保存します。
プレビュー
vite preview を使用して、ローカルで本番環境のビルドをプレビューできます。
vite preview
は、本番環境サーバーとして使用するためのものではありません。
デプロイメント
デプロイするには、選択した任意の HTTP サーバーからアプリを配信できます。サーバーは、単一のルート /index.html
ファイルから複数のパスを配信するように構成する必要があります (一般的には「SPA フォールバック」と呼ばれます)。サーバーがこの機能を直接サポートしていない場合は、その他のステップが必要になる場合があります。
簡単な例として、sirv-cli を使用できます。
または、express
サーバーで配信する場合 (ただし、その時点で Remix を SSR モードで実行することを検討した方が良いかもしれません 😉)。
ドキュメント全体ではなく、div をハイドレートする
HTML document
全体ではなく、<div id="app">
のようなドキュメントのサブセクションのみをハイドレートする場合は、SPA モードを使用し、いくつかの小さな変更を加えることで実現できます。
1. index.html
ファイルを追加する
Remix は HTML ドキュメントをレンダリングしないため、Remix の外部で HTML を提供する必要があります。最も簡単な方法は、ビルド時に Remix によってレンダリングされた HTML を置き換えることができるプレースホルダーを備えた、app/index.html
ドキュメントを保持することです。これにより、最終的な index.html
を生成できます。
<!-- Remix SPA -->
HTML コメントは、Remix HTML に置き換える部分です。
div
の周りの空白を含めないようにすることが重要です。そうしないと、React のハイドレーションの問題が発生します。
2. root.tsx
を更新する
ルートルートを更新して、<div id="app">
のコンテンツのみをレンダリングします。
3. entry.server.tsx
を更新する
app/entry.server.tsx
ファイルでは、Remix によってレンダリングされた HTML を静的な app/index.html
ファイルのプレースホルダーに挿入する必要があります。また、デフォルトの entry.server.tsx
ファイルのように、<!DOCTYPE html>
宣言を先頭に付けるのをやめる必要があります。これは app/index.html
ファイルに記述する必要があります。
app/entry.server.tsx
ファイルがない場合は、npx remix reveal
を実行する必要があるかもしれません。
4. entry.client.tsx
を更新する
app/entry.client.tsx
を更新して、ドキュメントではなく <div id="app">
をハイドレートします。
app/entry.client.tsx
ファイルがない場合は、npx remix reveal
を実行する必要があるかもしれません。
注意点/警告
-
SPA モードは、Vite と Remix Vite プラグイン を使用する場合にのみ機能します。
-
headers
、loader
、action
などのサーバー API は使用できません。これらの API をエクスポートすると、ビルド時にエラーが発生します。 -
SPA モードでは、
root.tsx
からHydrateFallback
のみエクスポートできます。他のルートからエクスポートすると、ビルド時にエラーが発生します。 -
実行中のサーバーがないため、
clientLoader
/clientAction
メソッドからserverLoader
/serverAction
を呼び出すことはできません。これらのメソッドが呼び出されると、ランタイムエラーが発生します。
サーバービルド
Remix SPA モードは、ビルド時にサーバー上でルートルートの「事前レンダリング」を実行することで、index.html
ファイルを生成することに注意することが重要です。
- つまり、SPA を作成している場合でも、依然として「サーバービルド」と「サーバーレンダリング」のステップがあり、
document
、window
、localStorage
などのクライアント側の側面を参照する依存関係の使用には注意する必要があります。 - 一般的に、これらの問題を解決する方法は、
entry.client.tsx
からブラウザ専用ライブラリをインポートすることです。これにより、これらのライブラリがサーバービルドに含まれるのを防ぐことができます。 - それ以外の場合、一般的に
React.lazy
またはremix-utils
の<ClientOnly>
コンポーネントを使用して、これらの問題を解決できます。
CJS/ESM 依存関係の問題
アプリの依存関係で ESM/CJS の問題が発生している場合は、Vite の ssr.noExternal オプションを使用して、特定の依存関係をサーバーバンドルに含める必要があるかもしれません。
これらの問題は通常、公開されたコードが CJS/ESM に対して正しく構成されていない依存関係が原因です。ssr.noExternal
に特定の依存関係を含めることで、Vite はその依存関係をサーバービルドにバンドルし、サーバーを実行したときにランタイムのインポートの問題を回避するのに役立ちます。
逆のケースで、特定の依存関係をバンドルから外部に保持したい場合は、反対の ssr.external
オプションを使用できます。
React Router からの移行
SPA モードは、既存の React Router アプリを (SPA であるかどうかに関係なく) Remix アプリに移行するのに役立つと期待されています。
この移行の最初のステップは、現在の React Router アプリを vite
で実行することです。これにより、非 JS コード (例: CSS、SVG など) に必要なプラグインがすべて揃います。
現在 BrowserRouter
を使用している場合
vite を使用したら、このガイド の手順に従って、BrowserRouter
アプリを Remix の catch-all ルートにドロップできます。
現在 RouterProvider
を使用している場合
現在 RouterProvider
を使用している場合は、ルートを個別のファイルに移し、route.lazy
を使用してロードするのが最善のアプローチです。
- Remix のファイル規則に従ってこれらのファイルに名前を付けて、Remix (SPA) への移行を容易にします。
- ルートコンポーネントを名前付きの
Component
エクスポート (RR 用) とdefault
エクスポート (最終的に Remix で使用するため) の両方としてエクスポートします。
ルートがすべて個別のファイルに格納されたら、次のようにできます。
- それらのファイルを Remix の
app/
ディレクトリに移動します。 - SPA モードを有効にします。
- すべての
loader
/action
関数をclientLoader
/clientAction
に名前変更します。 - React Router の
index.html
ファイルを、default
コンポーネントとHydrateFallback
をエクスポートするapp/root.tsx
ルートに置き換えます。