🗂

ブラウザからローカルファイルを操作するターミナルを作った

2022/05/06に公開

フロントエンド開発はフロントエンドで完結すべき過激派としてのGWの活動で、ブラウザでローカルファイルを読み書きするターミナルのプロトを作ってみました。

https://web-shell.netlify.app/

ローカルファイルをマウントして操作してる風景です。

ソースコード

mizchi/web-shell

仕組み

  • FileSystemAccess API を使って、FS API を実装
  • xterm.js 上で FS を叩く Unix 風のコマンドをいくつか実装
  • monaco-editor で、open <file> した内容を渡して、Cmd-S で保存した内容をFSに書き込む

最初に開いてるのは navigator.storage.getDirectory() の一時的なストレージで、これはブラウザの機嫌次第で揮発します(仕様にそう書いてある)。ローカルファイルを操作するのに mount を使うのがメインの用途です。

FileSystemAccess API が Chrome のみ対応なので、Chrome でしか動きません

https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API

基本的な使い方

Unix風のコマンド: cd ls cp mkdir rm あたりを実装してあります。同一ディレクトリのものに関しては Tab で補完します。深いパスの補完は、気が向いたら作ります。

実装してないもの: |, >, * のようなパイプ処理, 標準入出力, glob pattern による列挙は実装途中です。

WebShell 特有のコマンド

  • mount コマンドで指定したディレクトリを /<dirname> にマウントします。
  • open <file> コマンドで組み込みエディタ上で編集します。
  • bundle <file> で指定したファイルを rollup でビルドします。これはローカルにも反映されます
  • exec <file> でバンドルしつつ webworker 上で実行します。 typescript にも対応してます。

サンプルを置いときます。

# demo bundle on temporal storage
/workspace
# run
$ exec main.ts
# bundle to ./dist
$ bundle main.ts
gen > /workspace/dist/main.js

$ mount
# choose your local directory
# ...now I choose fs-test directory
/fs-test
# create empty file
$ touch test
$ ls
test

# open file on left editor(here)
$ open main.ts
# edit and (Ctrl or Cmd)+S
$ ls
test
main.ts
$ bundle main.ts
> gen > /fs-test/dist/main.ts

今後

webcontainer が OSS になる気配がないので、自分で同コンセプトのものを作ることにしました。

webcontainer とは

というかこれ、 https://wasi.rreverser.com/ を読み解きながらつくったやつで、こちらは wasi ビルドされた coreutils が動いて入出力を wasi に繋いでるんですが、その点 web-shell はそれっぽいだけの偽物です。標準入出力の仕組みは作ってあるけどパイプに回す仕組みを作ってないです…。

本当は wasi の勉強のために触り始めたやつで、今からこれを wasi のアダプタにつなげるつもりです。Rust で作ったコマンドが動くようになるのがゴールではあります。あと手書き wasm text format を試せる場所を作りたかったのがあります。

現状の新規性は、monaco-editor 繋いで open コマンドでつなげたところでしょうか。あと rollup + ts + terser は普通にウェブでも動く部分はそのままコマンドとして実装してあります。

自分としての意義は、スクラッチで組んで構成を理解したので、これからどうとでも拡張できる土台になったのが大きいです。

Discussion