Tauri デスクトップモード
スタンドアロンのオフラインリーダー(モード1)と設定可能な開発ラッパー(モード2)の使い分け、それぞれのビルド方法、モード2の設定ファイルについて。
zudo-doc には 2 種類の独立した Tauri デスクトップアプリ が用意されています。どちらも Web コンテンツをネイティブウィンドウに表示する点は似ていますが、想定する利用者がまったく異なり、それぞれ別のクレートからビルドされます。
| モード1 — オフラインリーダー | モード2 — 開発ラッパー | |
|---|---|---|
| ディレクトリ | src-tauri/ | src-tauri-dev/ |
| 表示する内容 | ビルド済みサイトのスナップショット | HMR つきの pnpm dev サーバー |
| 想定する利用者 | ドキュメントを読む人(オフライン閲覧) | プロジェクトを開発する人 |
| コンテンツの供給元 | 埋め込んだ静的な dist/ | 起動時に立ち上げる開発サーバー |
| 設定方法 | なし(このリポジトリに固定) | ユーザーごとの config.json |
モード1 — スタンドアロンのオフラインリーダー
モード1 は、zudo-doc 自身のビルド済み dist/ を埋め込んだ 自己完結型のデスクトップアプリを生成します。サーバーを動かすことなく、ネットワークにも繋がずに、ドキュメントをオフラインで閲覧できます。
モード1 のビルド
まず静的サイトをビルドし、続いてアプリをビルドします。
pnpm build
cargo tauri buildcargo tauri build は、src- の frontendDist 設定を通じて . を埋め込みます。WebView は WebviewUrl::App を読み込み、これが埋め込まれたファイルに直接対応します。出力は .app(macOS)、.exe(Windows)、AppImage(Linux)です。
Warning
src-tauri/ には cargo tauri dev も存在しますが、これは コントリビューター向けの便宜的なコマンド です。ローカルの zfb 開発サーバー(http:)に対して WebView を開くため、Tauri シェルとサイトコンテンツを同時に編集できます。これは配布する成果物ではありません。モード1 を配布する際は cargo tauri build のみを使ってください。
完成して変更されないドキュメントのコピーを誰かに渡したいとき — リリース成果物、オフラインのキオスク端末、同梱するヘルプアプリなど — にはモード1 を選びます。
モード2 — 設定可能な開発ラッパー
モード2 は、zudo-doc 形式のあらゆるプロジェクトがデスクトップ開発環境として使える スタンドアロンアプリです。固定された dist/ を埋め込む代わりに、プロジェクトの pnpm dev 開発サーバーを子プロセスとして起動し、その URL に WebView を向けます。コンテンツを編集すると、ブラウザとまったく同じように HMR で即座に再読み込みされます。違いは、それがネイティブウィンドウの中で起こることだけです。
モード1 と異なり、モード2 はプロジェクトに関する情報を一切ハードコードしません。プロジェクトのパスと開発サーバーの URL は、ユーザーごとの設定ファイルから読み取ります。
モード2 のビルド
モード2 は独自の Cargo.toml を持つ専用クレートです。クレートのディレクトリに移動してビルドします。
cd src-tauri-dev && cargo tauri buildリポジトリルートに Cargo ワークスペースは存在しません。モード1 とモード2 は、それぞれ独立した target/ ディレクトリを持つ独立したクレートです。リポジトリルートで cargo を実行しても、どちらもビルドされません。これはエラーではなく想定どおりの挙動です。
Note
モード2 は 稼働中の開発サーバー を包むだけなので、バイナリにサイトコンテンツは埋め込まれません。包む対象のプロジェクトがどれだけ大きくても、生成されるアプリは数 MB 程度の小ささに収まります。
モード2 の設定ファイル
初回起動の前に、プラットフォームのアプリケーションデータディレクトリに config.json を作成します。macOS では次の場所です。
~/ Library/ Application Support/ com. takazudo. zudo- doc- dev/ config. jsonファイルの形式は次のとおりです。
{
"version": 1,
"projectDir": "/Users/foo/repos/my-doc-project",
"devCommand": "pnpm dev",
"devServerUrl": "http://localhost:4321"
}| フィールド | 必須 | 意味 |
|---|---|---|
version | はい | スキーマのバージョン。1 でなければなりません。それ以外の値は不正とみなされます。 |
projectDir | はい | プロジェクトルートの絶対パス。開発サーバーの作業ディレクトリとして使われます。ディレクトリとして存在している必要があります。 |
devCommand | はい | 実行する開発コマンド(例: "pnpm dev")。先頭のトークンは pnpm である必要があり、残りは引数として渡されます。 |
devServerUrl | はい | 開発サーバーが待ち受けるベース URL。準備状態の確認、最終的な WebView の遷移先、後始末用のポート解析に使われます。 |
ファイルが存在しない、読み取れない、不正な形式である、version が 1 でない、いずれかのフィールドが欠けているか型が不正、といった場合、モード2 は サーバーを起動しません。期待されるファイルパスとこの JSON 形式を表示するエラー画面が出るので、ファイルを修正して再試行できます。
Tip
モード2 の v1 が包めるプロジェクトはちょうど 1 つ です。プロジェクトを切り替えるには、アプリを終了し、config.json を編集してから再起動します。あるいはファイルを編集してメニューの Restart dev server を使います。複数プロジェクトの切り替えは今後の対応予定です。
利用者が目にする挙動
モード2 は一連のプロセスライフサイクル制御を引き継いでいます。これにより、Finder から起動した場合(シェルの PATH が利用できない状況)でも、起動・再起動・終了が確実に動作します。
ローディング画面。 ウィンドウはスピナーを表示してすぐに開きます。開発サーバーの起動を待つことはありません。サーバーが HTTP プローブに応答すると、WebView はそのサーバーへ遷移します。サーバーの起動に時間がかかる場合は、約 20 秒後に「起動に時間がかかっています」というヒントが表示されます。
起動エラーは黙殺されず表示されます。 pnpm が見つからない、設定が不正、開発サーバーがいつまでも準備完了にならない、といった場合、ローディング画面は問題の内容とログファイルの場所を示すエラーパネルに切り替わります。Retry ボタンを押すと、アプリを再起動せずに起動処理をやり直せます。
PATH 不在への対処。 GUI から起動したアプリはシェルの PATH を引き継がないため、pnpm をそのまま探しても失敗します。モード2 はまず既知のインストール先の絶対パス(Homebrew、Volta)を確認し、最後の手段としてのみ / にフォールバックします。Finder から起動しても pnpm を見つけられるのはこのためです。素朴な探索では見つかりません。
プロセスグループの後始末。 開発サーバー(およびそれが起動するすべての子プロセス)は専用のプロセスグループで動きます。アプリを終了したとき、あるいは Restart dev server を使ったとき、そのグループ全体にシグナルが送られて回収されます。node や pnpm のプロセスが取り残されることはありません。
残存ポートの後始末。 モード2 は起動のたびに、開発サーバーのポートをまだ掴んでいるプロセスを終了させてポートを解放します。前回の実行が後始末をせずにクラッシュしていても、次の起動はクリーンに始まります。
.claude/ の開発ウォッチャー
zudo-doc プロジェクトで pnpm dev を実行すると、zfb 開発サーバーや doc-history サーバーと並んで .claude/ ウォッチャーが動きます。.claude/ 配下のファイルを編集すると、対応する MDX ページがその場で再生成されます。
モード2 は本物の pnpm dev コマンドを包むため、このウォッチャーはブラウザの場合とまったく同じようにモード2 のウィンドウ内でも動きます。.claude/ のファイルを編集すれば、手動でビルドし直すことなく描画されたドキュメントが更新されます。
モードの選び方
完成して変更されないオフラインのドキュメントコピーを配布したいなら モード1 を選びます。
プロジェクトを実際に執筆・開発していて、稼働中の開発サーバーをブラウザのタブではなくネイティブウィンドウで使いたいなら モード2 を選びます。
開発コマンドについては 開発ワークフロー を、モード1 が同梱する静的な dist/ の生成方法については デプロイ を参照してください。