「せばな」は言わない

綱の上を歩き、岩を登るエンジニア

【Electron】アプリパッケージ後にモジュールが見つからないエラー

f:id:tk_thunder:20210218120512p:plain

3日フルで悩んだ

もうほんとに泣きそうだった。
完璧な解決かは分からないけど記録しておく。

背景

昨年から業務をサポートするアプリを開発する際にElectronを使用することが多くなった。
qiita.com

なんと言っても画面のデザインがしやすい。htmlとcssでサクッと、Vue+Vuetifyも合わせればきれいな画面が作れる。
しかし、当初使用したElectronV6.0.0はレンダラープロセスでもrequireできていたのが、アップデートで非推奨となってしまった。
早い話、安全のためにrequireはメインプロセスでやれやということになったみたいだ。
そしてpreloadというものを使うことになったのだが、その辺は以下の記事を見て欲しい。

qiita.com

結論

悩んだプロセスの前に現状の結論を示しておく

  • app.asarにpreload.jsも含める(vue.config.jsのpreloadプロパティに記載する)

環境

  • Windows10
  • Node V14.15.4
  • npm V7.5.4
  • electron V11.0.0
  • vue-cli-plugin-electron-builder使用(electron-builder V22.9.1)

vue.config.jsは以下のようになっている

module.exports = {
  transpileDependencies: ["vuetify"],
  pluginOptions: {
    electronBuilder: {
      builderOptions: {
        productName: "*****",
        appId: "*****",
        win: {
          icon: "resources/icon.png",
          target: ["nsis"]
        },
        nsis: {
          oneClick: true,
          allowToChangeInstallationDirectory: false
        }
      }
    }
  }
};

はじまり

アプリパッケージ後にモジュールが見つからない

アプリをパッケージング後にアプリをインストールし、起動する。
そして、特定のモジュールの機能を使用すると以下のエラーがコンソールに出る。

f:id:tk_thunder:20210218121159p:plain

これが地獄の始まりだった。
今週の火曜から終わらない悪夢にうなされることになる。
自分のアプリは以下のような機能を持っている。

  • ローカルディレクトリの画像のサイズを取得
  • 取得したサイズでPDFへ変換する

今回問題になったのは上記の2つの機能を提供するモジュールだ。
requireしているのはpreload内。つまり、preloadからモジュールが見つけられていない。
最初はパッケージを入れたり消したり、あてのない作業を繰り返していた。
そんなことで解決するわけもなく…。

preloadを配置する場所

色々試したり唸ったりしたところpreloadがリリース済みのElectronパッケージに同梱されていないのが問題ではないかというところにたどり着いた。

微妙な方法

そしてスタックオーバーフローにはこんな内容が…
stackoverflow.com

app.asarにファイルを同梱するにはどうするのか書かれている。
publicディレクトリに入っているファイルはビルドの際に自動的にasarにコピーされるとのこと。

npm run electron:build

上記でビルドする前にpublicにpreload.jsを手動でぶち込んでみた。
そして、ビルド後にasar.appをアンパックしてみる。

asar extract .\app.asar output

※あらかじめapp.asarが配置されているディレクトリに移動すること
※asarをアンパックする方法
qiita.com

するとどうだろうか…
f:id:tk_thunder:20210218134337p:plain

うおおおおおおおおおおおお、ちゃんと入ってる!!!!
膝から崩れ落ちそうだった。椅子に座ってるけどな

でもおかしくないか。なんでわざわざ手動でファイルをpublicディレクトリに移動せにゃならんのだ。

ベストな方法

本当にこの方法しかないのだろうか。ビルドの段階で入れてくれる方法が絶対にあるだろう。モヤモヤしながら調べ直すこと1時間。
考え始めて既に3日目に入っており呼吸が荒い。

いや、公式に書いてあるやんけ!!!!!!!!!!!!!!

github.com

Preload Files
Preload files allow you to execute JS with Node integration in the context of your Vue App (shared window variable). Create a preload file and update your vue.config.js as so:

module.exports = {
  pluginOptions: {
    electronBuilder: {
      preload: 'src/preload.js',
      // Or, for multiple preload files:
      preload: { preload: 'src/preload.js', otherPreload: 'src/preload2.js' }
    }
  }
}

この情報1日目に出てきてくれ!!!
めっちゃ簡単やんけ!!!
公式を読まない僕が全面的に悪いんだけどね!!!!

とりあえずこれでビルドして、アプリをインストール。そしてasarをアンパックしてみる。

f:id:tk_thunder:20210218150943p:plain

うお(ry

これでpreload内のrequireが無事にモジュールを発見でき、機能が使えるようになった。

最終的にvue.config.jsはこんな感じになった。

module.exports = {
  transpileDependencies: ["vuetify"],
  pluginOptions: {
    electronBuilder: {
      preload: "src/preload.js",
      builderOptions: {
        productName: "*****",
        appId: "*****",
        win: {
          icon: "resources/icon.png",
          target: ["nsis"]
        },
        nsis: {
          oneClick: true,
          allowToChangeInstallationDirectory: false
        }
      }
    }
  }
};

ちなみに、ビルド後にVSCodeやエクスプローラからdist_electron/bundled/node_modules内を見ても何も入っていない。
確認するにはasarをアンパックするしかない。

問題が解決してよかった。分かればなんてことない内容だけど、見る記事はどれもこれも古くてバージョンも乖離していた。最近の記事ってそんなにたくさん無い印象だったなぁ。
とりあえず今日はよく眠れそうだ…。