@rescript-tauri/plugin-shell¶
Tauri 2.x shell プラグイン の ReScript バインディングです。子プロセスの起動、stdout / stderr のストリーミング、OS デフォルトアプリでのファイル / URL オープンを提供します。
注釈
本パッケージは main で機能完備済みです。初回 npm 公開は他のパッケージと合わせて予定されています。それまでは、ソースリポジトリ経由かワークスペースリンクで利用してください。
インストール¶
pnpm add @rescript-tauri/plugin-shell @tauri-apps/plugin-shell
@rescript-tauri/plugin-shell は @rescript-tauri/core と @tauri-apps/plugin-shell の両方を peerDependencies として宣言しているため、上流側の各バージョンを利用者側で制御できます。
rescript.json の dependencies にパッケージを追加します:
{
"dependencies": [
"@rescript-tauri/core",
"@rescript-tauri/plugin-shell"
]
}
Rust 側では、プラグイン crate を追加して builder に登録します:
# src-tauri/Cargo.toml
[dependencies]
tauri-plugin-shell = "2"
// src-tauri/src/main.rs
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.run(tauri::generate_context!())
.expect("error while running app");
}
Capability 設定¶
Tauri 2.x では、すべての shell 操作に対して capability を付与する必要があります。ls の起動と http(s) URL のオープンに必要な最小構成は以下のとおりです:
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"windows": ["main"],
"permissions": [
"core:default",
"shell:default",
{
"identifier": "shell:allow-execute",
"allow": [{ "name": "ls", "cmd": "ls", "args": true }]
},
{
"identifier": "shell:allow-open",
"allow": [{ "url": "^https?://" }]
}
]
}
起動するプログラムごとに shell:allow-execute の name と一致するエントリを列挙する必要があります。openPath に渡す URL は shell:allow-open の正規表現パターンのいずれかにマッチしなければなりません。完全な文法は上流の scope and permissions リファレンス を参照してください。
最小サンプル¶
open RescriptTauriPluginShell
await PluginShell.openPath("https://tauri.app/")
openPath は promise<unit> を返します。設定された shell:allow-open の正規表現にマッチしない URL を渡すと、内部呼び出しが reject されます。
公開 API¶
シンボル |
戻り値 |
用途 |
|---|---|---|
|
|
OS デフォルトアプリで URL / パスを開く (または |
|
|
UTF-8 のコマンドを構築する |
|
|
バイト列のコマンドを構築する ( |
|
|
完了まで実行し、出力をまとめて収集する |
|
|
コマンドを開始してハンドルを返す |
|
|
ライフサイクルイベントを購読する |
|
|
ストリーミング出力を購読する |
|
|
コマンドレベルのリスナーをすべて解除する |
|
|
内部の event emitter への低レベルアクセス |
|
|
子プロセスのアクセサと操作 |
|
|
9 つの汎用メソッド ( |
関連する record (spawnOptions、childProcess<'o>、terminatedPayload) は PluginShell から再エクスポートされています。完全な doc コメントと対応する上流 URL は packages/plugin-shell/src/PluginShell.resi を参照してください。
コマンド実行¶
ワンショット実行¶
Command.execute は子プロセスが終了したタイミングで resolve され、収集した出力をまとめて返します。短命なコマンドに最適です:
module Shell = RescriptTauriPluginShell.PluginShell
let listFiles = async () => {
let cmd = Shell.Command.create("ls", ~args=["-la"])
let output = await cmd->Shell.Command.execute
Console.log(output.stdout)
}
childProcess<'o> は {code, signal, stdout, stderr} を保持します。code と signal はどちらも Nullable.t<int> で、Unix では相互排他です (シグナルで終了したプロセスは code = null を返します)。
バックグラウンドプロセス¶
Command.spawn は子プロセスを起動して Child.t ハンドルを即座に返し、終了を待ちません。Child.write や Child.kill と組み合わせると対話的に利用できます:
let runRepl = async () => {
let cmd = Shell.Command.create("python3", ~args=["-i"])
let child = await cmd->Shell.Command.spawn
await child->Shell.Child.write("print('hello')\n")
// ... later
await child->Shell.Child.kill
}
Child.pid は OS レベルのプロセス ID を返します。
Raw byte 出力¶
専用のファクトリ関数を使って encoding: "raw" を渡すと、string の代わりに Uint8Array.t を受け取れます:
let readImage = async () => {
let cmd = Shell.Command.createRaw("cat", ~args=["icon.png"])
let output = await cmd->Shell.Command.execute
Console.log("byte count: " ++ Int.toString(TypedArray.length(output.stdout)))
}
上流の Command.create({encoding: 'raw'}) における TypeScript の条件型による戻り値は、ReScript では 4 つの関数 (Command.create / Command.createRaw / Command.sidecar / Command.sidecarRaw) に分割されており、結果型は常に静的に決定されます。
ストリーミング出力¶
長時間動作するコマンドからイベントを stream するには onStdoutData / onStderrData / onClose / onError をチェーンします。各メソッドはコマンド自身を返し、上流の Promise<this> パターンに対応しています:
let tail = async () => {
let cmd =
Shell.Command.create("tail", ~args=["-f", "/var/log/system.log"])
->Shell.Command.onStdoutData(line => Console.log2("stdout:", line))
->Shell.Command.onStderrData(line => Console.log2("stderr:", line))
->Shell.Command.onClose(payload =>
switch (payload.code->Nullable.toOption, payload.signal->Nullable.toOption) {
| (Some(code), _) => Console.log("exited with code " ++ Int.toString(code))
| (_, Some(sig)) => Console.log("killed by signal " ++ Int.toString(sig))
| _ => Console.log("closed")
}
)
->Shell.Command.onError(err => Console.error2("error:", err))
let _child = await cmd->Shell.Command.spawn
}
より高度な購読パターン (once、prependListener、手動の listenerCount など) には Command.stdout / Command.stderr を直接使ってください。どちらも EventEmitter.t<{"data": 'o}> を返すので、EventEmitter モジュールの 9 つの汎用メソッドで操作できます。
Command.removeAllListeners はコマンドレベルのリスナー (close / error) をすべて解除します。stdout / stderr のリスナーを解除するには、対応するアクセサに対して EventEmitter.removeAllListeners を呼び出してください。
Sidecar バイナリ¶
Sidecar は、アプリと一緒に同梱されるバイナリで、PATH ではなく tauri.conf.json > bundle > externalBin から解決されます。Command.sidecar (バイト列を扱う場合は sidecarRaw) を使います:
let runHelper = async () => {
let cmd = Shell.Command.sidecar("my-sidecar", ~args=["--check"])
let output = await cmd->Shell.Command.execute
Console.log(output.stdout)
}
sidecar に渡す文字列は、ターゲットトリプルの接尾辞を含まない externalBin エントリと一致させてください。
パス / URL を開く¶
openPath は引数で渡したパス / URL をシステムのデフォルトアプリケーションで開きます:
await Shell.openPath("https://github.com/tauri-apps/tauri")
await Shell.openPath("/tmp/notes.md")
~openWith を渡すと、特定のオープナー (firefox、chromium、safari、xdg-open など) を強制できます。パスや URL は shell:allow-open の正規表現にマッチする必要があり、マッチしない場合は内部呼び出しが reject されます:
await Shell.openPath("/tmp/notes.md", ~openWith="firefox")
注意点¶
openPath へのリネーム¶
上流ではこの関数を open として公開していますが、ReScript ではこの識別子がモジュールアクセス (open MyModule) のために予約されているため、本パッケージでは openPath として再エクスポートしています:
// ❌ syntax error: ReScript treats `open` as a keyword
await Shell.open("https://tauri.app/")
// ✅
await Shell.openPath("https://tauri.app/")
Uint8Array の長さ取得¶
@rescript/core の Uint8Array.t は TypedArray.t<int> のエイリアスです。長さの getter は親モジュール側にあります:
let output = await cmd->Shell.Command.execute
Console.log("byte count: " ++ Int.toString(TypedArray.length(output.stdout)))
Scope 設定ミス¶
対象が src-tauri/capabilities/ で許可されていない場合、コマンドの起動も openPath の呼び出しも失敗します。shell:allow-execute の name フィールドは、Command.create / Command.sidecar の第 1 引数と完全に一致させる必要があります:
{
"identifier": "shell:allow-execute",
"allow": [{ "name": "git", "cmd": "git", "args": true }]
}
上記の場合 Command.create("git", ...) は成功しますが、Command.create("Git", ...) や Command.create("/usr/bin/git", ...) は reject されます。
互換性¶
項目 |
対応バージョン |
|---|---|
上流 |
|
Rust |
|
|
|
ReScript |
|
|
|
対応 OS |
Linux / macOS / Windows |
関連リンク¶
ライブデモ:
examples/plugin-shell-demo上流ドキュメント: Tauri 2.x shell プラグイン
インストールガイド — まず
@rescript-tauri/coreのセットアップを行ってください