Murasaki
コアコンセプト

プロセスモデル

起動、開発時 reload、graceful shutdown、アプリ所有リソース。

Murasaki はネイティブイベントループと Node のイベントループを分離します。パッケージ 済みアプリでは Rust launcher が同梱 Node 子プロセスを起動・監視し、Node が Main ライフサイクルとローカル HTTP server を開始してから、ホストがレンダラーを読み込み ます。

launch
  → Rust host が per-user app lock を取得
  → host が app-local origin と runtime token を作る
  → Node child が src/main.ts を読み込む
  → main.ready(context) が完了
  → local server が listen を開始
  → cold start 時の登録済み URL / file を main.openRequested() へ配送
  → 宣言済みWebViewが各renderer routeを読み込む

ready() が reject すると、未初期化のバックエンドに UI を接続せず起動に失敗します。 DB の open、migration、アプリ所有 service の起動など、UI より先に必要な処理を置いて ください。

packaged macOS / Windows app では 2 回目の起動は別 backend を開始しません。その argv / working directory は main.secondInstance() に渡され、host が primary window を focus します。開発 mode と Linux には現状この lock がありません。

Open request

packaged macOS / Windows app は、murasaki.config.tsprotocolsfileAssociations で custom URL scheme と document extension を登録できます。 ready() の完了後、一致した activation が normalize されて main.openRequested() へ渡されます。

  • activation: cold-start / second-instance / os-event
  • transport: argv / open-url / open-file
  • targets: { kind: 'url', url, scheme } または { kind: 'file', path }

2 回目の起動では、secondInstance() は raw process argument を引き続き受け取り、 openRequested() には登録済み URL / file だけが渡されます。cross-platform な open 処理は openRequested()、その他の secondary-launch argument は secondInstance() で扱ってください。

URL / file activation は OS から届く untrusted input です。登録は hook に届く input を選ぶだけで、送信元の認証や URL / file content の安全性を保証しません。

終了シーケンス

通常のウィンドウ close / app quit は次の順です。

quit request
  → beforeQuit(context)       false でキャンセル可能 ┐
  → context.signal が abort
  → shutdown(context)                                 ┘ 全体が shutdownTimeoutMs の上限付き
  → Node child が終了
  → native host が終了、または更新を適用

beforeQuit() は未保存ドキュメントがある場合などに通常終了をキャンセルできます。 process signal や開発時 Main reload を含む強制終了ではキャンセルできません。 2つのhook全体の既定上限は10秒です。shutdown()ではまず新規処理の受付を止め、 その後 flush / close してください。

OSのclose controlと appWindow.close() はsecondaryをhideするため、windows.open() で再表示できます。primaryのmainを閉じるとapp quit requestになり、上記sequenceへ 進みます。cancelはapp全体に対するもので、window別close lifecycle eventはありません。 明示的な windows.close(label) はsecondary targetを破棄し、同じprocess内では現在 再生成できません。

開発時の reload

murasaki dev で設定された Main entry を変更すると次が実行されます。

  1. 現在の shutdown({ reason: 'dev-reload' })
  2. Vite による entry module の invalidate
  3. 新しい lifecycle の生成
  4. 新しい ready()

Main が import するコードも Vite module graph に従いますが、現状 lifecycle restart を 開始するのは設定した entry 自体の変更だけです。module top-level で timer / socket を 作らず、ready() で作成し shutdown() で閉じると reload 時の leak を防げます。

アプリケーションパス

MainContext.pathsappId ごとに安定した OS 標準パスを返します。

Path用途
dataDB、アプリ所有のユーザードキュメント、永続 state
cache再生成可能な cache
logsアプリログ
temp一時 staging file

実行ファイルの隣には書き込まないでください。パッケージ済み resource は read-only の 場合があり、OS ごとに配置が異なり、更新時には app bundle 自体が置換されます。

プロセス障害

ホストが Node 子プロセスの lifetime を所有します。macOS / Linux では server が孤児に なると終了し、Windows では launcher と共に閉じる Job Object に割り当てられます。 crash restart policy、health check hook、複数 worker の監視 API はまだ公開されて いません。Main から worker / child process を生成する場合、その終了処理はアプリ側の 責務です。

次へ

On this page