tauri-apps / tauri-apps/plugins-workspace

[feat] Make stdin closable via JS `shell` API

Open
#2,136 2 comments 3 reactions 0 assignees View on GitHub
plugin: shell type: feature request
Dominant language
Rust
Stars
1.8k
Forks
602
Avg merge
4d 14h
Merged PRs (30d)
9

Description

### Describe the problem

@FabianLars asked me to open a feature request, so here we are. As elaborated in #4440, there is an issue when using Tauri's JS API method [`shell.Child.write`](https://tauri.app/v1/api/js/shell/#write): stdin is not being closed. This can make command line interfaces that depend on stdin unusable, for example [`esbuild`](https://esbuild.github.io/api/#transform-api) in this code snippet:
```js
const command = Command.sidecar("../binaries/esbuild", "--loader=ts")
command.stdout.on("data", data => console.log(data))
command.stderr.on("data", data => console.log(data))
command.on("error", data => console.log(data))
command.on("close", data => console.log(data))
const child = await command.spawn()
console.log(child.pid)
await child.write("echo 'let x: number = 1'")
// => Only the pid is logged, nothing else
```

The expected output here would the transformed code or an error, but since stdin is not closed, no stdout/stderr is ever produced.

A workaround (credit to @lanc33llis, who faced the same issue) is this:
```rs
#[tauri::command]
async fn function(text: &str) -> Result {
let (mut rx, mut child) = Command::new_sidecar("my-sidecar")
.expect("failed to create `my-sidecar` binary command")
.spawn()
.expect("Failed to spawn sidecar");

child.write(text.as_bytes()).expect("Failed to write to sidecar");
drop(child);

let mut output = String::new();
while let Some(event) = rx.recv().await {
if let CommandEvent::Stdout(line) = event {
output.push_str(&line);
}
}

Ok(output)
}
```

In my personal opinion, that workaround shouldn't be neccessary, hence this feature request.

### Describe the solution you'd like

Possibly the easiest fix would be adding a `closeAfter` flag to the `shell.Child.write` method. This is backwards compatible and follows a similar pattern to other parts of the API.

**New signature:**
```ts
type WriteOptions = {closeAfter?: boolean}
write(data: string | Uint8Array, options?: WriteOptions): Promise
```

**Semantics:**
If set to true, it would close stdin after writing. This would avoid adding extra methods and still allow usage such as this:
```js
child.write("my first stdin message") // stdin is open
child.write("my second stdin message") // still open...
child.write("my final stdin message", {closeAfter: true}) // stdin is closed
```

### Alternatives considered

A separate method for closing stdin on `shell.Child` would be possible, but this would increase the API surface.

### Additional context

I don't know if this problem would also appear in other parts of the JS API and would need more adjustments.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.