Remix CLI

@remix-run/dev パッケージから提供される Remix CLI には、コンパイラも含まれています。サーバーにデプロイされないように、package.jsondevDependencies に追加してください。

使用可能なコマンドとフラグの完全なリストについては、以下を実行してください。

npx @remix-run/dev -h

remix vite:build

Remix Vite を使用して、アプリを本番環境用にビルドします。このコマンドは process.env.NODE_ENVproduction に設定し、デプロイ用に出力結果を縮小します。

remix vite:build
フラグ説明タイプデフォルト
--assetsInlineLimit静的アセットのベース64インラインしきい値(バイト単位)number4096
--clearScreenログ出力時に画面をクリアするかどうかboolean
--config, -c指定された設定ファイルを使用するstring
--emptyOutDirルート外の outDir を強制的に空にするboolean
--logLevel, -l指定されたログレベルを使用する"info" | "warn" | "error" | "silent" | string
--minify縮小を有効/無効にする、または使用する縮小器を指定するboolean | "terser" | "esbuild""esbuild"
--mode, -m環境モードを設定するstring
--profile組み込みの Node.js インスペクターを起動する
--sourcemapClientクライアントビルド用のソースマップを出力するboolean | "inline" | "hidden"false
--sourcemapServerサーバービルド用のソースマップを出力するboolean | "inline" | "hidden"false

remix vite:dev

Remix Vite を使用して、アプリを開発モードで実行します。

remix vite:dev
フラグ説明タイプデフォルト
--clearScreenログ出力時に画面をクリアするかどうかboolean
--config, -c指定された設定ファイルを使用するstring
--corsCORS を有効にするboolean
--forceオプティマイザーにキャッシュを無視して再バンドルさせるboolean
--hostホスト名を指定するstring
--logLevel, -l指定されたログレベルを使用する"info" | "warn" | "error" | "silent" | string
--mode, -m環境モードを設定するstring
--open起動時にブラウザを開くboolean | string
--portポートを指定するnumber
--profile組み込みの Node.js インスペクターを起動する
--strictPort指定されたポートが既に使用されている場合、終了するboolean

Classic Remix Compiler コマンド

このドキュメントは、Classic Remix Compiler を使用している場合にのみ関連します。

remix build

Classic Remix Compiler を使用して、アプリを本番環境用にビルドします。このコマンドは process.env.NODE_ENVproduction に設定し、デプロイ用に出力結果を縮小します。

remix build

オプション

オプションフラグ設定デフォルト
本番環境用ビルドでソースマップを生成する--sourcemapN/Afalse

remix dev

Classic Remix Compiler を監視モードで実行し、アプリサーバーを起動します。

Remix コンパイラは、以下を実行します。

  1. NODE_ENVdevelopment に設定します
  2. アプリコードの変更を監視し、再ビルドをトリガーします
  3. 再ビルドが成功すると、アプリサーバーを再起動します
  4. ライブリロードと HMR + ホットデータ再検証を使用して、コードの更新をブラウザに送信します

🎥 Remix の HMR と HDR の紹介と詳細については、以下のビデオをご覧ください。

ホットデータ再検証とは何ですか?

HMR と同様に、HDR は、ページをリフレッシュしなくてもアプリをホットアップデートする方法です。 これにより、編集がアプリに適用されても、アプリの状態を保持できます。 HMR は、アプリのコンポーネント、マークアップ、またはスタイルを変更する場合など、クライアント側のコードの更新を処理します。 同様に、HDR はサーバー側のコードの更新を処理します。

つまり、現在のページの loader(または loader が依存するコード)を変更するたびに、Remix は変更されたローダーからデータを再取得します。 これにより、アプリはクライアント側とサーバー側の両方の最新のコード変更で常に最新の状態になります。

HMR と HDR がどのように連携しているかについては、Pedro の Remix Conf 2023 での講演をご覧ください。

カスタムアプリサーバーを使用する場合

テンプレートを使用して開始した場合、おそらくテンプレートは remix dev とすでに統合されています。 そうでない場合は、以下の手順に従って、プロジェクトを remix dev と統合できます。

  1. package.json の開発スクリプトを置き換え、-c を使用してアプリサーバーコマンドを指定します。

    package.json
    {
      "scripts": {
        "dev": "remix dev -c \"node ./server.js\""
      }
    }
  2. アプリサーバーが実行中のときに、broadcastDevReady が呼び出されるようにします。

    server.ts
    import path from "node:path";
     
    import { broadcastDevReady } from "@remix-run/node";
    import express from "express";
     
    const BUILD_DIR = path.resolve(__dirname, "build");
    const build = require(BUILD_DIR);
     
    const app = express();
     
    // ... express アプリの設定コードをここに記述します ...
     
    app.all("*", createRequestHandler({ build }));
     
    const port = 3000;
    app.listen(port, () => {
      console.log(`👉 http://localhost:${port}`);
     
      if (process.env.NODE_ENV === "development") {
        broadcastDevReady(build);
      }
    });

    CloudFlare の場合は、broadcastDevReady の代わりに logDevReady を使用してください。

    なぜですか? broadcastDevReadyfetch を使用して、Remix コンパイラに準備完了メッセージを送信しますが、CloudFlare はリクエスト処理以外の fetch などの非同期 I/O をサポートしていません。

オプション

オプションの優先順位は、1. フラグ、2. 設定、3. デフォルトです。

オプションフラグ設定デフォルト説明
コマンド-c / --commandcommandremix-serve <server build path>アプリサーバーを実行するために使用されるコマンド
手動--manualmanualfalse手動モードに関するガイド を参照してください
ポート--portport動的に選択された空いているポートホットアップデートのために Remix コンパイラが使用する内部ポート
TLS キー--tls-keytlsKeyN/Aローカル HTTPS を設定するための TLS キー
TLS 証明書--tls-certtlsCertN/Aローカル HTTPS を設定するための TLS 証明書

たとえば、

remix.config.js
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
  dev: {
    // ...設定する他のオプションはここに記述します ...
    manual: true,
    tlsKey: "./key.pem",
    tlsCert: "./cert.pem",
  },
};

カスタムポートの設定

remix dev --port オプションは、ホットアップデートに使用される内部ポートを設定します。 アプリが実行されるポートには影響しません。

アプリサーバーのポートを設定するには、本番環境と同じ方法で設定します。 たとえば、server.js ファイルにハードコードされている場合があります。

remix-serve をアプリサーバーとして使用している場合は、--port フラグを使用してアプリサーバーのポートを設定できます。

remix dev -c "remix-serve --port 8000 ./build/index.js"

一方、remix dev --port オプションは、ネットワークポートを細かく制御する必要があるユーザーのための回避策です。 ほとんどのユーザーは、remix dev --port を使用する必要はありません。

手動モード

デフォルトでは、remix dev は、再ビルドが発生するたびにアプリサーバーを再起動します。 再ビルド間でアプリサーバーを再起動せずに実行し続ける場合は、手動モードに関するガイドをご覧ください。

remix dev によって報告される時間を比較することで、アプリサーバーの再起動がプロジェクトのボトルネックになっているかどうかを確認できます。

  • rebuilt (Xms) 👉 Remix コンパイラがアプリの再ビルドに X ミリ秒かかりました
  • app server ready (Yms) 👉 Remix がアプリサーバーを再起動し、新しいコード変更で起動するまでに Y ミリ秒かかりました

他のパッケージの変更を拾う

モノレポを使用している場合は、アプリコードが変更されたときだけでなく、アプリの依存関係のコードが変更されたときにも、Remix がホットアップデートを実行するようにしたい場合があります。

たとえば、Remix アプリ (packages/app) 内で使用される UI ライブラリパッケージ (packages/ui) があるとします。 packages/ui の変更を拾うには、watchPaths を構成してパッケージを含めることができます。

MSW の統合方法

開発で Mock Service Worker を使用するには、以下を行う必要があります。

  1. MSW をアプリサーバーの一部として実行する
  2. MSW が Remix コンパイラへの内部の「開発準備完了」メッセージを模倣しないように構成する

REMIX_DEV_ORIGIN 環境変数がモックで使用できるように、-c フラグ内でアプリサーバーのモックを設定していることを確認してください。 たとえば、NODE_OPTIONS を使用して、remix-serve を実行するときに Node の --require フラグを設定できます。

package.json
{
  "scripts": {
    "dev": "remix dev -c \"npm run dev:app\"",
    "dev:app": "cross-env NODE_OPTIONS=\"--require ./mocks\" remix-serve ./build"
  }
}

ESM をデフォルトのモジュールシステムとして使用している場合は、--require の代わりに --import フラグを設定する必要があります。

package.json
{
  "scripts": {
    "dev": "remix dev -c \"npm run dev:app\"",
    "dev:app": "cross-env NODE_OPTIONS=\"--import ./mocks/index.js\" remix-serve ./build/index.js"
  }
}

次に、REMIX_DEV_ORIGIN を使用して、MSW が /ping で内部の「開発準備完了」メッセージを転送できるようにします。

import { http, passthrough } from "msw";
 
const REMIX_DEV_PING = new URL(
  process.env.REMIX_DEV_ORIGIN
);
REMIX_DEV_PING.pathname = "/ping";
 
export const server = setupServer(
  http.post(REMIX_DEV_PING.href, () => passthrough())
  // ... 他のリクエストハンドラーをここに記述します ...
);

リバースプロキシとの統合方法

アプリサーバーと Remix コンパイラの両方が同じマシンで実行されているとします。

  • アプリサーバー 👉 http://localhost:1234
  • Remix コンパイラ 👉 http://localhost:5678

次に、アプリサーバーの前にリバースプロキシを設定します。

  • リバースプロキシ 👉 https://myhost

しかし、ホットアップデートをサポートするための内部の HTTP および WebSocket 接続は、引き続きプロキシされていない Remix コンパイラのオリジンに到達しようとします。

  • ホットアップデート 👉 http://localhost:5678 / ws://localhost:5678

内部接続がリバースプロキシを指すようにするには、REMIX_DEV_ORIGIN 環境変数を使用できます。

REMIX_DEV_ORIGIN=https://myhost remix dev

これで、ホットアップデートがプロキシに正しく送信されるようになります。

  • ホットアップデート 👉 https://myhost / wss://myhost

パフォーマンスチューニングとデバッグ

パスインポート

現在、Remix がアプリを再ビルドすると、コンパイラはアプリコードとその依存関係を処理する必要があります。 コンパイラは、使用されていないコードをアプリからツリーシェイクするため、ブラウザに不要なコードを送信せず、サーバーを可能な限りスリムに保ちます。 しかし、コンパイラは、どのコードを保持し、どのコードをツリーシェイクするかを知るために、すべてのコードを クロール する必要があります。

簡単に言えば、これはインポートとエクスポートの方法が、アプリの再ビルドにかかる時間に大きく影響することを意味します。 たとえば、Material UI や AntD などのライブラリを使用している場合は、パスインポート を使用することで、ビルドを高速化できる可能性があります。

- import { Button, TextField } from '@mui/material';
+ import Button from '@mui/material/Button';
+ import TextField from '@mui/material/TextField';

将来的には、Remix は開発時に依存関係を事前にバンドルして、この問題を完全に回避できる可能性があります。 しかし現在では、パスインポートを使用することで、コンパイラを支援できます。

バンドルのデバッグ

アプリと依存関係によっては、アプリに必要な量よりもはるかに多くのコードを処理している可能性があります。 詳細については、バンドル分析ガイドをご覧ください。

トラブルシューティング

HMR

ホットアップデートを期待しているのに、ページ全体がリロードされる場合は、Hot Module Replacement に関する議論で、React Fast Refresh の制限と一般的な問題の回避策について詳しくご覧ください。

HDR: すべてのコード変更で HDR がトリガーされる

ホットデータ再検証は、各ローダーをバンドルし、そのコンテンツのフィンガープリントを作成することで、ローダーの変更を検出します。 ツリーシェイクを使用して、変更が各ローダーに影響するかどうかの判断を行います。

ツリーシェイクがローダーの変更を確実に検出できるようにするには、アプリのパッケージが副作用がないことを宣言する必要があります。

package.json
{
  "sideEffects": false
}
HDR: ローダーデータが削除されたときの無害なコンソールエラー

ローダーを削除したり、そのローダーが返すデータを削除したりすると、アプリは正しくホットアップデートされるはずです。 しかし、ブラウザにコンソールエラーが記録されている場合があります。

React の strict モードと React Suspense は、ホットアップデートが適用されるときに複数のレンダリングを引き起こす可能性があります。 これらのレンダリングのほとんどは、最終的なレンダリング(あなたに表示されるレンダリング)を含む、正しくレンダリングされます。 しかし、中間レンダリングでは、新しいローダーデータと古い React コンポーネントを組み合わせる場合があり、これがエラーの原因となります。

根本的な競合状態を調査して、これを解消できるかどうかを調べています。 今のところ、これらのコンソールエラーが気になる場合は、エラーが発生するたびにページをリフレッシュしてください。

HDR: パフォーマンス

Remix コンパイラがアプリをビルド(および再ビルド)すると、コンパイラが各ローダーの依存関係をクロールする必要があるため、わずかに速度が低下することがあります。 これにより、Remix は再ビルド時にローダーの変更を検出できます。

初期のビルドの速度低下は、本質的に HDR のコストですが、HDR の再ビルドの速度低下が認識できるレベルにならないように、再ビルドを最適化する予定です。