👌

electron-viteで開発する際に考慮すべきRollupのチャンク動作

2023/02/24に公開

electron-vite で Electron アプリの開発をしていて起こった2つの問題について説明します。どちらも Rollup のチャンク(コード分割)に関する内容になります。

1)__dirname の階層がずれる

electron-vite のドキュメントではプリロードスクリプトや resources フォルダにあるファイルのパスを得るためにpath.join(__dirname, 'preload.js')のように解決するコードが書かれています。

この場合の__dirnameは Rollup で生成されるメインスクリプトの位置を前提にしたものなので、下記の条件に当てはまる場合は、該当のスクリプトコード(チャンク)がサブフォルダに出力されてしまうため__dirnameで得られるパスが一階層深くなり、パスの解決に失敗します。

  • メインプロセスのビルド構成に複数のスクリプトエントリがある(主にワーカーを使用している場合は該当するかと思います)
  • それらの複数のスクリプトから import されるファイルに__dirnameを参照するコードが書かれている

electron-vite の Scaffolding で作成される構成を前提とした場合、メインスクリプトは out/main/index.js に作成されますが、チャンクスクリプトは out/main/chunks/lib.js といったようにメインスクリプトから一階層下のサブフォルダに作成されます。

そのためjoin(__dirname, '../../resources/app.ico?asset')のようなコードがチャンクされると__dirnameで得られるパスが一つ深くなるため結果として得られるパスの階層もずれてしまいます。

回避策)チャンクをメインスクリプトと同じ階層に出力するように設定する

チャンクファイルはbuild.assetsDirに出力されます。デフォルトは chunks になっています。この設定にはbuild.outDirからの相対パスを設定できるので''を設定してメインスクリプトと同じ階層に出力するようにできます。具体的には以下の通りです。

electron.vite.config.ts
export default defineConfig({
  main: {
    plugins: [externalizeDepsPlugin()],
    build: {
      // チャンクファイルをメインスクリプトと同じ階層に出力する
      assetsDir: '',
      rollupOptions: {
        input: {
          index: resolve(__dirname, 'src/main/index.ts'),
          worker: resolve(__dirname, 'src/main/worker.ts'),
        },
      },
    },
  },

2)プリロードスクリプトでのチャンク化

現在の Electron のバージョンではプリロードスクリプトの実行環境はデフォルトでサンドボックス化されています。通常の Node.js 環境とは異なり、require は限られた API にしかアクセスできないもの(ポリフィルされた require 関数)になっています。

https://www.electronjs.org/ja/docs/latest/tutorial/tutorial-preload
https://www.electronjs.org/ja/docs/latest/tutorial/sandbox

そのため、下記の条件に該当する場合はプリロードスクリプト内からチャンクスクリプトを require するコードが生成されてしまい、結果としてプリロードスクリプトの実行に失敗します。

  • プリロードスクリプトのビルド構成に2つ以上のエントリがある(2つ以上のプリロードスクリプトが必要な場合は該当すると思います)
  • それらのスクリプトから import される共通のコード(変数や関数)がある

レンダラーの DevTools を開いて確認すると下記のようなエラーメッセージで失敗していることがわかります。

Error: module not found: ./chunks/types-e2a4dd98.js

回避策#1)サンドボックスを無効化する

Electron のドキュメントで説明されている通りですが、サンドボックスを無効化すれば require によるチャンクファイルの読み込みができるようになります。設定の仕方は Electron のドキュメントに委ねます。

回避策#2)チャンク化されないようにコードを整理する

どうしてもサンドボックスを無効化できない(したくない)場合は、コードがチャンクされないようにリファクタリングするしかありません。

この問題が起こる条件にも書きましたが、実行時には JavaScript コードになるので Typescript のコードとして単に interface の定義だけを共通のコードとして参照しているだけならコードのチャンクは起こりません。変数または関数を共通のコードとして扱わないようにすればコードのチャンクを防げます。

プリロードスクリプトはデバッグ実行での確認時にも out フォルダにファイルが生成されるので実際にどのようなコードが生成されるかを確認しながら修正するとよいかと思います。

番外)チャンクの無効化はできない

バンドラーの設定によってチャンク動作を無効化することができれば回避できますが、Rollup にはチャンクを無効化する機能がありません。下記 Issue でこの問題について言及されていますが、そのような機能が追加される見込みは今後もなさそうです。

https://github.com/rollup/rollup/issues/2756

本記事の内容は以上となります。

Discussion