Wave Terminal をカスタム Electron でビルドする備忘録です.
macOS, Windows, Linux で使えるマルチプラットフォームなターミナルの Wave Terminal の Linux 版で x265(HEVCとも言う)動画を再生できるようカスタムビルドしてみた備忘録です.

Wave Terminal
Wave Terminal については,以前の記事,

をご覧ください.また,Wave Terminal で HEVC 再生できるようにするために,Electron のカスタムビルド版が必要ですが,この件については,以前の記事,

をご覧ください(と言うか,この記事は実質的には上の記事の続きです).

準備
公式のビルドについての案内は,
にありますが,Wave Terminal も Electron ど同じくビルドするにはOS 標準パッケージでは間に合いません.このため,環境を崩さないように Wave Terminal ビルド専用のコンテナ環境を準備します.

ビルド用コンテナの準備
前記事の Electron のビルドと同様に,~/src 以下をコンテナにマウントすることにします.
ビルド用のコンテナを以下の通り作成します.
$ cd ~/src $ podman run -it -v $(pwd):/src ubuntu:24.04 bash root@597bca0cfbbd:/#
ここで,597bca0cfbbd はビルド用に起動したコンテナの ID です).このコンテナに Wave Terminal のビルドに必要なパッケージを追加します.

開発用基本パッケージの追加
まず,git と開発に最低限必要なツールをまとめた build-essential 他,それから node を追加します.git は最新版を導入するので,そのための PPA を追加しています(この辺りは Electron の場合と同じです).
root@597bca0cfbbd:/# apt update;apt install software-properties-common -y
root@597bca0cfbbd:/# add-apt-repository ppa:git-core/ppa # 途中 ENTER を入力
root@597bca0cfbbd:/# apt install build-essential clang libdbus-1-dev libgtk-3-dev \
libnotify-dev libasound2-dev libcap-dev \
libcups2-dev libxtst-dev \
libxss1 libnss3-dev gcc-multilib g++-multilib curl \
gperf bison python3-dbusmock openjdk-8-jre \
git npm htop vim zip wget sudo -y

node 24 の導入
Wave Terminal の場合も Electron と同様に OS 標準の node 18 だとビルド時に問題が起きるので,最新安定版の node 24 を入れ,OS 標準の node 18 は削除します.
root@597bca0cfbbd:/# npm install n -g root@597bca0cfbbd:/# n stable root@597bca0cfbbd:/# apt purge -y nodejs npm;apt autoremove -y
念のため,ver. を確認します.
root@597bca0cfbbd:/# git -v git version 2.52.0 root@597bca0cfbbd:/# node -v v24.12.0 root@597bca0cfbbd:/# npm -v 11.6.2

zig の導入
どの部分で使われているのか定かではないですが,Wave Terminal のビルドには zig という静的型付け言語(Rust と同じような感じ?)のコンパイラが入れておく必要があるようです.
公式の案内だと,snap で追加せよとなっていますが,残念ながらコンテナ環境でこれはできません.zig については直接バイナリを展開して追加します.
まず,zig の公式ページからバイナリファイルをダウンロードします.
root@597bca0cfbbd:/# wget https://ziglang.org/builds/zig-x86_64-linux-0.16.0-dev.1859+212968c57.tar.xz
ダウンロードしたファイルを /usr/local/zig 以下に展開します.
root@597bca0cfbbd:/# mkdir /usr/local/zig root@597bca0cfbbd:/# tar -Jxvf zig-x86_64-linux-0.16.0-dev.1859+212968c57.tar.xz -C /usr/local/zig --strip-components 1 root@597bca0cfbbd:/# rm zig-x86_64-linux-0.16.0-dev.1859+212968c57.tar.xz
実際に使うにはパスを通す必要があります.
root@597bca0cfbbd:~# export PATH=/usr/local/zig:$PATH root@597bca0cfbbd:~# zig version 0.16.0-dev.1859+212968c57

Task の導入
Task を導入します.知らなかったんですが,GNU make のシンプル版?のような位置付けのものっぽいです.Taskfile.yml が Makefile 相当っぽいです.
root@597bca0cfbbd:~# curl -1sLf 'https://dl.cloudsmith.io/public/task/task/setup.deb.sh' | sudo -E bash root@597bca0cfbbd:~# apt install task
Go の導入
Google の開発した Go も導入が必要です.
zig と同様にバイナリファイルを直接展開して導入します.
root@597bca0cfbbd:~# wget https://go.dev/dl/go1.25.5.linux-amd64.tar.gz root@597bca0cfbbd:~# tar -xzf go1.25.5.linux-amd64.tar.gz -C /usr/local root@597bca0cfbbd:~# rm go1.25.5.linux-amd64.tar.gz
もちろん実際に使うには PATH を通しておかなければなりません.
root@597bca0cfbbd:~# export PATH=$PATH:/usr/local/go/bin root@597bca0cfbbd:~# go version go version go1.25.5 linux/amd64

パッケージ化に必要なツール群の導入
これは必ずいれないとダメなわけではありませんが,各種パッケージ(rpm とか deb とかの形式のもの)を作成したい場合は,これらに対応するツール群をいれておかないといけません.ただし,今回は podman コンテナ内でビルドするので,snap や LXD パッケージ化は(多分)対応できません.今回は関係パッケージとして以下を導入ておきます.
root@597bca0cfbbd:~# apt install rpm libarchive-tools binutils libopenjp2-tools squashfs-tools -y
一般ユーザーの追加
ここまで,専用のコンテナ環境内の作業でしたので,全て root で作業をしてきましたが,Electron はセキュリティ上の理由から root 権限で実行すると
Running as root without –no-sandbox is not supported
のようなエラーを出し停止します.エラーにある通り –no-sandbox オプションをつけて実行しても良いのですが,一般ユーザーでビルドを実行した方が簡単かつ望ましいので,ここではコンテナ環境に appuser という名前の一般ユーザーを追加して,このユーザーでビルドを実行することにします.
root@597bca0cfbbd:~# useradd -m appuser root@597bca0cfbbd:~# su appuser
Wave Terminal のビルド
リポジトリの複製
まず,Wave Terminal のリポジトリを複製します.権限の問題から,コンテナの root で複製作業を実行してから appuser に所有権を変更していることにご注意ください.
root@597bca0cfbbd:/src# root@597bca0cfbbd:/src# git clone https://github.com/wavetermdev/waveterm.git root@597bca0cfbbd:/src# chown -R appuser:appuser waveterm root@597bca0cfbbd:/src# su appuser $ export PATH=/usr/local/zig:$PATH:/usr/local/go/bin

依存関係の読込
リポジトリを複製したら,以下のコマンドで依存関係の読込を実施しないといけないようです.また,ビルド時に問題が発生した場合にも読み込みが必要とのことです.
$ cd waveterm $ task init $ npm audit fix
package.json の書換
私の環境だからかもしれませんが,ビルド途中にワーキングメモリ不足エラーが出たので,waveterm フォルダ直下にある package.json の “scripts” を以下の内容に書き換えました.
$ vi package.json
.....
"browserslist": [
"Chrome >= 128"
],
"scripts": {
"dev": "node --max-old-space-size=4096 ./node_modules/.bin/electron-vite dev --no-sandbox",
"start": "node --max-old-space-size=4096 ./node_modules/.bin/electron-vite preview",
"build:dev": "node --max-old-space-size=4096 ./node_modules/.bin/electron-vite build --mode development",
"build:prod": "node --max-old-space-size=4096 ./node_modules/.bin/electron-vite build --mode production",
"coverage": "vitest run --coverage",
"test": "vitest",
"postinstall": "electron-builder install-app-deps"
},
"devDependencies": {
"@eslint/js": "^8.57.0",
"@rollup/plugin-node-resolve": "^16.0.3",
.....

カスタム Electron の展開
Wave Term の Electron を,以下の記事でビルドしたカスタム Electron に「すり替え」ます.

やることは,
- waveterm/node_modules/electron の dist ディレクトリの内容をカスタム Electron のものに置き換える
- ホームディレクトリの .cache/electron 以下にあるキャッシュファイルをカスタム Electron のものに置き換える.
- ホームディレクトリの .cache 以下にカスタム Electron パッケージを配置する(ファイル名は正規の Electron パッケージに偽装する).
です.
もっとスマートな方法もあると思って Google の Gemini にも聞いてみましたが,正攻法だとかなり大変そうな感じだったのであきらめました.また,実際には必要のないかった置き換えをしている可能性もあります.少し泥臭いですが,実際の作業は以下のような感じです.
$ mv node_modules/electron/dist node_modules/electron/dist.orig $ mkdir node_modules/electron/dist $ unzip ../dist.zip -d node_modules/electron/dist $ cd ~/.cache/electron $ ls a7a47a0dc6eba89f2dc8bd8ff5e381d3f27b3f046598441d81c96471f6ded33c $ cd a7a47a0dc6eba89f2dc8bd8ff5e381d3f27b3f046598441d81c96471f6ded33c $ ls electron-v38.5.0-linux-x64.zip $ mv electron-v38.5.0-linux-x64.zip electron-v38.5.0-linux-x64.zip.bk $ cp /xxxxxxxxx/dist.zip electron-v38.5.0-linux-x64.zip $ cp electron-v38.5.0-linux-x64.zip ../. $ cd /src/waveterm/
wave terminal のビルド
あとは Wave Terminal をビルドするだけのはずなのですが,なぜか途中で sharp ライブラリが無いと怒られたので,
$ npm install sharp $ task package
としました.また,少し前にビルドした時には出なかったのですが,
# github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient
pkg/wshrpc/wshclient/wshclientutil.go:66:24: cannot use func(ctx context.Context) error {…} (value of type func(ctx context.Context) error) as func() value in assignment
というエラーが出たので,該当部分を,
vi pkg/wshrpc/wshclient/wshclientutil.go
....
rtnErr(respChan, err)
return respChan
}
opts.StreamCancelFn = func() {
_ = reqHandler.SendCancel(context.Background())
}
go func() {
defer func() {
panichandler.PanicHandler("sendRpcRequestResponseStreamHelper", recover())
....
の様に書き換えて,その影響で,
# github.com/wavetermdev/waveterm/pkg/web
pkg/web/web.go:255:59: cannot use rpcOpts.StreamCancelFn (variable of type func()) as func("context".Context) error value in argument to handleRemoteStreamFileFromCh
のようなエラーが出たので,該当部分を,
$ vi pkg/web/web.go
....
func handleRemoteStreamFile(w http.ResponseWriter, req *http.Request, conn string, path string, no404 bool) error {
client := wshserver.GetMainRpcClient()
streamFileData := wshrpc.CommandRemoteStreamFileData{Path: path}
route := wshutil.MakeConnectionRouteId(conn)
rpcOpts := &wshrpc.RpcOpts{Route: route, Timeout: 60 * 1000}
rtnCh := wshclient.RemoteStreamFileCommand(client, streamFileData, rpcOpts)
return handleRemoteStreamFileFromCh(w, req, path, rtnCh, func(ctx context.Context) error{
rpcOpts.StreamCancelFn()
return nil}, no404)
}
....
のように書き換えて,再び
$ task package
無事ビルドを完了させることができました.上の書き換えは自分で考えたのではなくて,Google Gemini 君のアドバイスに従っただけです.Gemini 君賢いなぁ……
作成されたパッケージは,waveterm/make 以下に,
- waveterm-linux-amd64-0.13.1.deb
- waveterm-linux-x64-0.13.1.pacman
- waveterm-linux-x64-0.13.1.zip
- waveterm-linux-x86_64-0.13.1.AppImage
- waveterm-linux-x86_64-0.13.1.rpm
- waveterm_0.13.1_amd64.snap
のように出力されます.Linux 系の代表的なパッケージを全部作ってくれるんですね.実際にビルドした Wave Terminal で HEVC 動画を再生できることも確認できましたが,ちょっと手間がかかりすぎですね.まぁ勉強にはなりましたし,Gemini 君の賢さもよくわかりました.
以上!

