🔌

[3日目]ElectronでMac用アプリtaskbar.fm を開発して得た知見[みすてむずアドカレ]

2023/12/03に公開

この記事は みすてむず いず みすきーしすてむず (2) Advent Calendar 2023 3日目の記事です。
https://adventar.org/calendars/8601

taskbar.fmというアプリを開発しています。

アプリの内容の宣伝


https://github.com/fruitriin/taskbar

これは、MacでWindowsのタスクバーっぽいのをつけるアプリです。


このtaskbarはWindowsのタスクバーにインスパイアされて作られており、タスクをクリックしてウィンドウを切り替えることができます。
縦タブにすることも可能です。

これは便利なのではないかと思った方はぜひダウンロードしてみてください。
https://github.com/fruitriin/taskbar/releases

ダウンロードしてみたぞ!という方がいたら @fruitriin@misskey.systems になにかを届けてくれるとめちゃくちゃ喜ぶと思います。ということで宣伝終わり。

Electron と Vite と Electron-Vite

さて、今回はこのtaskbar.fmを構成している技術について解説します。

中核になっているのは Electron-viteです。
https://electron-vite.org/

Electronはご存知の通りデスクトップアプリケーションを実行するNodeと、その上のHTML, CSS, JSで構成されたWebっぽいものの組み合わせで動きます。
ただ、このHTML, CSS, JSの組み合わせを作るところを素のElectronを作ると結構面倒です。
Electon-viteは、ElectronとViteを組み合わせていい感じに設定を組んだリポジトリテンプレートです。

ビルドチェーンにViteを使っているので、TypeScriptサポートやHMR(ソースコードを変更したら再起動や更新なしで反映してくれるやつ)などがついてきて開発をめちゃくちゃ助けてくれます。

### なんかディレクトリ構成をいい感じに整理したい

クイックスタートに従って、 Electron-vite npm create @quick-start/electron でVueのプロジェクトを作るとこんなディレクトリ構成になります。

➤ tree
.
├── README.md
├── build
│   ├── entitlements.mac.plist
│   ├── icon.icns
│   ├── icon.ico
│   └── icon.png
├── electron-builder.yml
├── electron.vite.config.ts
├── package.json
├── resources
├── src
│   ├── main
│   │   └── index.ts
│   ├── preload
│   │   ├── index.d.ts
│   │   └── index.ts
│   └── renderer
│       ├── index.html
│       └── src
│           ├── App.vue
│           ├── assets
│           │   ├── css
│           │   │   └── styles.less
│           │   └── icons.svg
│           ├── components
│           │   └── Versions.vue
│           ├── env.d.ts
│           └── main.ts
├── tsconfig.json
├── tsconfig.node.json
└── tsconfig.web.json

このうち、 preload とかいうよくわからないディレクトリがあります。
これはセキュリティ上の都合なのですが、 @electron-toolkit/preload を使うと削除することができます。

あとは完全に好みですが、 renderer/main.tsmain/index.ts は脳がめちゃくちゃ混乱するので renderer/index.htmlmain/main.ts に変更してます。

  • Viteはエントリポイントに htmlファイルを指定するとその中で呼び出されたtsファイルをビルドに含めてよしなにやってくれる

リリースはActionsが便利じゃない?

そうでもなかった。
tagを打ってリリースビルドをするActionsがあるんですが、ビルドしてみたけどもう一回みたいなのがやりにくかったです。
結局手元でガシガシビルドしてリリースページに貼っちゃう方が私は楽でした。

他人に使ってもらうぞ!

Mac用として他の人に使ってもらいたいです。
ビルドして他のマシンに送って……動きません。

これはMacのセキュリティ機構上の理由です。
https://www.npmjs.com/package/electron-builder-notarize

Electron-Builder-Norarize とかを使うと良さそうな感じです。
AppleのDeveloperアカウントが必要になってくると思います。

この辺もActionsが絡んでくるとめんどくさいのでめんどくさいですがローカルならサクッと試してできたやつをそのままポンするだけでいいのでいいですね。

これはApple Silicon向けのビルドではない!

package.json の scripts の build:mac に --universal って付けるとuniversalビルドになります。
実行ファイルを同梱する場合、これが署名のまわりと絡まってめちゃくちゃ厄介なことになります。

私は本物のネイティブAPIを叩きたいのだ

NodejsとElectronはかなりネイティブなAPIを操作するためのAPIが提供されているので、ディスプレイのサイズ等は取得できます。

ですが、ElectronはSandboxモデルに従って他のプロセスの状態を取得することができません。
困りました。

そこで目をつけたのが、Electronは自分自身が他のプロセスを立ち上げることができて、その標準出力を受け取ることができるということです。
ということで作りました。

これを、NodeJS側から定期的に実行し、レスポンスをNodeJSの中で組み立てて活用しています。

いかがでしたか?

taskbar.fmはおよそこういった要素でできています。
ほかにはモニタのサイズを取得してそれをウィンドウサイズと表示座標とすることでタスクバーっぽい感じにしているとか、データの保存は ElectronStore を使うと楽ちんとか、じゃあそれをVue側でどうリアルタイムに読み書きしようかなーとか、細かい工夫はありますが、およそNodeでバックエンドを作り、VueなりReactなりで動くものを作る気持ちでいればElectronでのデスクトップアプリは動きます!!!

というところで、明日の記事はゆんぽんさんです。「カメラ買いなさいカメラ買いなさいカメラ買いなさいカメラ買いなさいカメラ買いなさい」とつよいカメラ圧を感じます。

Discussion