【ロボット】Linux+Vue.js+Electron使ったトラブルシューティング【備忘録】

みなさんこんにちは。suginokoです。
[弊社](https://brewus.co.jp/)でElectronの案件がありましたのでその備忘録です。
今回は案件でロボットを動かす（？）ような案件で、結構苦戦することがあり、

普段Web開発を行っていますので、Linux使って案件の対応することがないですし、私としてはチャレンジャーな案件ですが、色々トラブったので今後そんなことがないように備忘録を残そうと思って書きます。

古めのものではありますが、どなたかの役に立てれば幸いです。

## 概要
本件、ロボットを動かすとありますが、これはJetsonNanoのGPIOを使った技術で動いているものですので、実際はLinux案件ということになります。

こちらの案件は既にお客様の方で実装がされているもので、そのソースコードを元に対応しておりました。
少々開発環境、実行環境が古めなので、あしからず。

ロボットを使ってWebとロボットで通話ができる、みたいな案件でした。


## 環境
確認OS
* Linux
    * RasberryPi 4
    * JetsonNano
    * Ubuntu 20.04.5 LTS
* Windows 10

ソース修正などの作業自体をWindows10で行い、アプリ実行、動作確認の殆どはRasberryPi 4で[VNC](https://www.realvnc.com/en/connect/download/viewer/)を使って確認しておりました。8割くらいはLinuxで色々対応してます。
案件的にCUIでは全てを確認できないので、VNC使ってGUI上で確認する必要があったためです。これは同様にJetsonNanoでも使用します。

フロント周り
* Node v16.19.0
* Agora v4
* Vue.js v2.7.0
* Electron v8.2.4
* vue-cli-plugin-electron-builder v1.4.6
* firebase v7.8.2

sassやTypeScriptなどありますが、登場しないためWeb側の細かいことは記載しません。
また、firebaseの記載もありますが、後述する内容で必要なので記載だけしています。


その他
* Python 3.9.0


## 対応目標
* Linux環境（ここではJetsonNano上で動くように）でElectronアプリを動かせること
    * 64Bit(arm64)で
* ちょい古めのVue.jsの書き方でも動かせること
* Electronアプリをインストールして、次OSを起動した時に自動でアプリが立ち上がること
* Electronをv8→v22にアップデートすること
* [Agora.io](https://www.agora.io/en/)を使ってWeb、ロボット間(JetsonNano)で通話できるようにすること

## トラブルシューティング
環境構築や諸々のバージョンアップ対応があったのですが、それらの対応中に起こったトラブルシューティングを記載します。

### npm install時
実はこちらの案件、元はNode v12でした。Node v12は既にサポートされてませんので、こちらをNode v16まで上げる対応を行っておりました。v16に上げたことで起きたnpm install時のエラーについて対処法を記載していきます。

#### gyp ERR! find Python
Node v16に上げたことでエラーを吐きまして、どうやらPythonのバージョンが合わないようでした。本案件でのREADME上ではPython2.7を使用してくださいと記載がありましたが、Node v16では使用できないようで、以下のエラーに遭遇しました。
```JavaScript
gyp ERR! find Python
gyp ERR! find Python Python is not set from command line or npm configuration
gyp ERR! find Python Python is not set from environment variable PYTHON
gyp ERR! find Python checking if "python3" can be used
gyp ERR! find Python - "python3" is not in PATH or produced an error
gyp ERR! find Python checking if "python" can be used
gyp ERR! find Python - executable path is "/usr/bin/python"
gyp ERR! find Python - version is "2.7.18"
gyp ERR! find Python - version is 2.7.18 - should be >=3.6.0
gyp ERR! find Python - THIS VERSION OF PYTHON IS NOT SUPPORTED
gyp ERR! find Python
gyp ERR! find Python **********************************************************
gyp ERR! find Python You need to install the latest version of Python.
gyp ERR! find Python Node-gyp should be able to find and use Python. If not,
gyp ERR! find Python you can try one of the following options:
gyp ERR! find Python - Use the switch --python="/path/to/pythonexecutable"
gyp ERR! find Python   (accepted by both node-gyp and npm)
gyp ERR! find Python - Set the environment variable PYTHON
gyp ERR! find Python - Set the npm configuration variable python:
gyp ERR! find Python   npm config set python "/path/to/pythonexecutable"
gyp ERR! find Python For more information consult the documentation at:
gyp ERR! find Python https://github.com/nodejs/node-gyp#installation
gyp ERR! find Python **********************************************************
gyp ERR! find Python
```
上記の通り、Python v2.7は使えないようでした。エラーの内容通り3.6.0以上が必要なようです。

Pythonを普通にインストールしてしまった（というかUbuntuとかもインストールして使い始める時点で確かPython3系入ってた気がするんだけど、READMEには2.7使ってって書いてあったから2.7入れたんだけど、Nodeのバージョン上げてしまったのでその影響か）ので、バージョンを変えるのが面倒でした。

Pythonは普段あまり触らないので、色々四苦八苦した結果[pyenv](https://github.com/pyenv/pyenv)を使ってPythonのバージョン管理をするようになりました。

これでデフォルトを`3.9.2`にして確認したところ、解決しました。

#### gyp: name 'openssl_fips' is not defined while evaluating condition 'openssl_fips != ""' in binding.gyp while trying to load binding.gyp

タイトルはエラーの一部ですが、実際のエラー内容は
```JavaScript
// 省略
gyp info spawn args   '--generator-output',
gyp info spawn args   'build',
gyp info spawn args   '-Goutput_dir=.'
gyp info spawn args ]
gyp: name 'openssl_fips' is not defined while evaluating condition 'openssl_fips != ""' in binding.gyp while trying to load binding.gyp
gyp ERR! configure error
gyp ERR! stack Error: `gyp` failed with exit code: 1
// 省略
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
```
こんな感じで。どこがしくじってたのか分かりにくかったのですが、エラー文がありました。

`binding.gyp` というファイルを読み込むと、`openssl_fips`が定義されてないぞ！ということで起こったエラーのようです。

binding.gypというファイルに聞き覚えがないので
```bash
$ find -name binding.gyp
./node_modules/grpc/binding.gyp
```
findで調べてみるとnode_modules/grpcの中にありました。これはちょっと難しかったです。
なのであんまりよくないのかもしれませんが、./node_modules/grpc/binding.gypにopenssl_fipsの記述を入れてみます。

最近使い慣れてきたvim(vi)で編集してopenssl_fipsに空文字を足してみます。
```
vi ./node_modules/grpc/binding.gyp
```

binding.gyp
```
'variables' : {
    'openssl_fips': '',
}
```

上記の対応で（案件的には）解決しました。

尚、案件では上記の解決を行ったのですが、おそらく、firebaseがv7.8.2だったことが原因な気がしています。
別のElectronのプロジェクトでテストした時に、こちらをv9に上げるとこの問題は解消してました。ただ案件の都合上firebaseのアップデートを行うと色々あって都合が悪かったので上記の対応になりました。

firebaseのバージョンを上げて影響が出ないで解消するのであればバージョンアップデートをしたほうがいいかと思います。

### ElectronアプリをBuildするとき
Electronアプリでバイナリファイルを生成するときもエラーに遭遇しました。
```
⨯ cannot execute  cause=exit status 1
  errorOut={my home directory}.cache/electron-builder/fpm/fpm-1.9.3-2.3.1-linux-x86/lib/ruby/bin/ruby:
   行 6: {my home directory}.cache/electron-builder/fpm/fpm-1.9.3-2.3.1-linux-x86/lib/ruby/bin.real/ruby: 
   バイナリファイルを実行できません: 実行形式エラー
// 省略
Error: {my home directory}/chicaro-git-e18/node_modules/app-builder-bin/linux/arm64/
app-builder exited with code ERR_ELECTRON_BUILDER_CANNOT_EXECUTE
```

fpmを取得できずにLinux(arm64)では問題が起きるようでエラーになっていました。
色々調べてみると同じようにエラーになっていた[こちら](https://github.com/jordansissel/fpm/issues/1801#issuecomment-919877499)の記事でも同じようなことが海外の方であったので、記事にあります通り
```
export USE_SYSTEM_FPM=true
```
を叩くことで解消しました。

### Electron周り（特にv8→v22にするとき）

#### Uncaught ReferenceError: require is not defined
Electronをv8→v22にアップデートするにあたって、Electron v12の[ブログ](https://www.electronjs.org/ja/docs/latest/breaking-changes#%E7%9C%81%E7%95%A5%E5%80%A4%E5%A4%89%E6%9B%B4-contextisolation-%E3%81%AE%E7%9C%81%E7%95%A5%E5%80%A4%E3%82%92-true-%E3%81%AB)でも表記があるのですが、`require()` がレンダラープロセスで使えなくなります。

対応した案件では、requireの表記がそこそこされておりましたので、できれば使用できる形にしておきたかったので、

ElectronのメインプロセスのJSファイルにて
```JavaScript
hoge = new BrowserWindow({
    width: 1280,
    height: 720,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false // add
    },
    kiosk: kioskMode
  })
```

というような形で`contextIsolation: false`を追記しました。

#### Electronを自動起動させるためのauto-launchのバグ
要件として
* Electronアプリをインストールして、次OSを起動した時に自動でアプリが立ち上がること


という要件がありますが、OS起動をしてElectronを自動起動させるのに、Linuxでも使える[auto-launch](https://github.com/Teamwork/node-auto-launch) が使用されてました。

ただし、Linuxで使用するときだけバグがあり[auto-launchのissue](https://github.com/Teamwork/node-auto-launch/issues/97)でも書かれているのですが、本デスクトップアプリと関係のないElectronアプリがOSの立ち上げのタイミングで一緒に立ち上がるというバグがありました。要は2つアプリが立ち上がるのです。（Windows、Macでは起こりませんし、この現象は本番Buildでは起こりません。開発アプリ起動時のみ起こります。）
こちらはissueでもあるようにまだ解決されていないように思えます。

もらったソースコードでは開発環境、本番環境など、環境分けで色々記載されているものがありましたが、アプリが自動起動する箇所については環境問わず立ち上がるようになっており、開発環境でアプリを起動してしまうと、無駄なElectronアプリが一緒に立ち上がるようになってしまいました。

これが面倒でしたので、Electronアプリの自動起動は本番アプリのみ行われるように対応しました。もしauto-launchをLinuxで使う際には注意していただければと思います。
### Electronをv8→v22にするにあたって出たVue周りのエラー

Electronをv8→v22にした影響でVue.jsにも影響が出ました。

#### Uncaught ReferenceError HOGE is not defined
vue.config.js内で使用していた環境変数が使えない（厳密には`process.env.HOGE`という形ではなく、`HOGE`という変数として使用したい。というか使用している。）ことがありましたので以下の修正をしました。

Vue2系は中身がWebpackだったはずなので、それに合った以下の対応を行っています。
元々は以下の書き方で、
```JavaScript
module.exports = {
  // ...
  configureWebpack: {
    plugins: [
      new webpack.DefinePlugin({
        HOGE: JSON.stringify(process.env.npm_package_version + '/' + hashId),
      }),
      // ...
    ],
}
```

修正は
```JavaScript
module.exports = {
  // ...
  // add
  chainWebpack: config => {
    config.plugin('define').tap(args => {
      args[0].VERSION = JSON.stringify(process.env.npm_package_version + '/' + hashId)
      return args
    })
  },
  configureWebpack: {
    plugins: [
      new webpack.DefinePlugin({
        VERSION: JSON.stringify(process.env.VERSION),
        // VERSION: JSON.stringify(process.env.npm_package_version + '/' + hashId),
      }),
      // ...
    ],
}
```

`chainWebpack`を使用することで解決できます。

#### Uncaught TypeError: process.on is not a function
Electronアプリを立ち上げると起こるエラーでした。
```JavaScript
if (isElectron()) {
  process.on('uncaughtException', err => {
    log.error('electron:event:uncaughtException')
    log.error(err)
    log.error(err.stack)
  })
}
```
みたいな感じで使用しているとElectron v22にすると起こるエラーのようです。（厳密にはv22にしたからではないとは思うけど、バージョン上げた時にどっかでエラーになったんだろうなと）

こちらもvue.config.jsで対応できます。

```JavaScript
module.exports = {
  // ...
  // add
    node: {
      process: true
    }
  // ...
}
```
こちらを追記することで解消しました。

## その他対応
#### Linux環境でWindowsアプリを生成する時に起きたこと
9割方Linux環境で確認していたのですが、お客様に見せる都合上、Windows上でElectronのアプリを動かさないといけないことがありました。

ElectronのBuildを大体Linux環境で行っていたので、ついでのつもりでWindowsアプリを生成しました。

その際に
```
wine is required, please see https://electron.build/multi-platform-build#linux
```
という表示が出ました。
Windows向けアプリケーションをBuildするパッケージがないぞ、ということらしいので、
```
sudo apt install wine
```
で入れて上げることで解消しました。

#### apt-getしたパッケージが壊れてた
ということもありまして。それに関しては先人様の[知恵](https://t-min.hatenablog.com/entry/2017/04/15/113445) をいただきまして直りました。
```
$ sudo dpkg --configure -a
$ sudo apt-get -f install
```

インストールしなおしてもう一度
```
sudo dpkg --configure -a
```
としてみて、何も起きなければ問題ないです。



## まとめ
初めてLinux+Electron（+Vue）対応しましたが、特有のエラーが沢山で大変でした。
普段WebフロントエンドでWebだけ触っていたらわからない領域のエラーが多く、苦戦しましたが、Linuxの対応を勉強していたおかげで対処できました。

WebフロントエンジニアがLinuxで色々するってあまり機会がないかもしれませんが、LinuxでElectronの対応している方で苦労しているようでしたら参考にしてみてください。