📖

ウェブアプリをデスクトップアプリに移行する際の三つの選択肢

2022/02/26に公開

背景

現在、「あなたの思考を育てるノート」Suikoのベータテスト を行っています。

その際のフィードバックで、「ノートアプリなんだからDockに常駐していないと書く気がしない」というものをいただきました。その通りだと思います。

ということで、最速でウェブアプリをデスクトップアプリに変換する方法を調べて実践したので、シェアします。

現状のウェブアプリは、Next.jsをVercelで動かし、Firebase Admin SDKでデータの永続化・スマホアプリとの同期をしています。

どうやったか

参考にした記事
https://slack.engineering/interops-labyrinth-sharing-code-between-web-electron-apps/

今回「ブラウザの1タブではなく、常駐したアプリとして見せたい」という明確な動機があったので、それに絞って調べていました。

Slackのデスクトップアプリが、いかに紆余曲折を経て現在の形になったのか、という説明記事があったので、これと公式の(主にセキュリティ周りの)解説を読んで、今回の実装をしました。

まずは、絶対にやってはいけないやり方:バージョン0

まず、Electronをただのウェブアプリの感覚で動かすと、非常に痛い目をみる可能性があります。

Electron上で動くNodeJSは、ファイル管理やShellなどへのアクセス権限があります。なんらかの方法でリモートデータがハックされ、XSSなどが可能になった場合、クライアントマシンに対して大きな損害を与えることが可能です。

nodeIntegration contextIsolation などのこういった実行権限を操作するオプションを理解しないまま「ゆるめる」方向に設定することだけは、絶対に避けてください。

まだましだけど、かなりイケてないやり方:バージョン1

バージョン0と思想は一緒ですが、いわゆる普通のブラウザ上での実行環境と同じように外部のウェブアプリを読み込むことができます。

// main.js
app.enableSandbox()
app.whenReady().then(() => {
  // no need to pass `sandbox: true` since `app.enableSandbox()` was called.
  const win = new BrowserWindow()
  win.loadURL('https://google.com')
})

ウェブアプリをURLから読み込む方針にする場合は、必ず
https://www.electronjs.org/docs/latest/tutorial/security を「端から端まで」読んでください。

アプリ開発が複雑化してきたときなどに、知らず知らずの間に地雷を踏んでしまうことが決してないように。

本当のハイブリッドアプリを目指して:バージョン2

ということで、最後にSlack Desktopがとったやり方は.. JSのコードベース資産を「コンポーネント」という形でモジュール化して両方で使えるようにする、ということでした。

Slack Electron pattern version2.1

これも二段階に分かれていて、そうやって共通化したライブラリをビルド時に読み込むやり方(上記の図)、そして(これをSlackが推しているのですが)ライブラリをService Worker上で、実行時のバックグラウンドで読み込むやり方を紹介しています。

Slack Electoron pattern version2.2

機能追加をビルド・配布時に限定したくないという気持ちはよくわかります。それがウェブアプリ開発での大きな魅力です。

Suikoは今どこなの?

現在は、バージョン1(ウェブアプリをブラウザと同じSandbox環境で読み込む)をして、限定したメンバーに配布しています。

99%ウェブアプリと同じとはいえ、ブラウザ上のナビゲーション(Back button等)に依存していたUXが見つかるので、それを改善している段階です。

これでデスクトップアプリって呼べるの?

つっこみとしては正しいものだと思います。デスクトップアプリでなければいけない理由は今はなく、
Desktop PWA (Progressive Web App) の方が筋が良い選択肢のようにも思えます。

ただ、今後ノートアプリとしてデスクトップネイティブAPIに依存したユースケース(ローカルデータ保存、E2E Encryption)は出てくると思うので、Electronなどのコンパイル環境ベースで探していました。

Electronってそもそもどうなの?

よくある非難として、「重い」というのはその通りだと思います。それはアプリケーションサイズの話と、実行時のメモリ消費の話に大別されます。

アプリケーションサイズに関しては、Chromiumがデカいということなので、結局ブラウザ互換性にどれだけ敏感なUX・UIなのかということかなと。

Rust製のTauriというのも選定中に見つけました。これはブラウザを同梱せずに、実行環境時に存在しているブラウザに依存することで(見せかけっていうと怒られるかもだけど)配布サイズを劇的に小さくしています。

https://www.reddit.com/r/programming/comments/lns5mj/tauri_an_electron_alternative_written_in_rust/

メモリ消費に関しては、どうせChromiumはプロセスベースで各ウィンドウを管理しているので、これもアプリ次第で、ベースラインはそれ以外のウェブアプリの選択肢とそこまで変わらない印象です。

How much Suiko uses memory

間違っていたら指摘ぜひお願いします。

これから参考にしたいと思っている記事

きちんとデスクトップアプリ「だと」アプリの使用感が良くなるということが証明できたら、今後
https://www.reddit.com/r/electronjs/comments/m5gfu2/build_an_electron_app_with_nextjs/ などをみて、PCネイティブAPIならではのユーザ体験を目指します。

Discussion