Electron を試す 7 - Electron v1.0 対応
ねんがんの Electron 1.0 をてにいれたぞ!というわけで akabekobeko/examples-electron のプロジェクトを対応させてみた。その過程で得られた知見を記録しておく。
- 2016/5/16 補足 v1.0 からわずか数日で v1.1 がリリースされた。この記事に関係する変更点は Devtron の読み込み改善ぐらいである。examples-electron のプロジェクトは既に v1.1 を参照するように修正済み。
モジュール参照の変更
従来の Electron ではアプリケーション情報となる app やシェル操作に必要な shell などは直に参照していた。
import App from 'app';
console.log( App.getName() );
これらは非推奨モジュールとなっており v1.0 でまとめて削除された。詳しくは Remove deprecated apis by kevinsawicki - Pull Request #5373 - electron/electron を参照のこと。代替 API は electron モジュール配下へ移動されている。ipcMain
や ipcRenderer
と同じ構成へ統一された。
よって
import Electron from 'electron';
console.log( Electron.app.getName() );
のように修正する必要あり。Main プロセスで非推奨モジュールを import/require
した場合は Electron 起動時にエラーとなるので、すぐに修正すること。この変更により Electron の提供するモジュールと Node や外部 npm 由来のものが区別しやすくなった。今後 Electron 関連モジュールが増えたとしても名前競合を気にしなくて済むのはよいことだ。
メニュー対応における混乱
モジュール参照の変更は単純な置換でよいのだけどメニュー関連で混乱した。既存コードでは
import Menu from 'menu';
const menu = Menu.buildFromTemplate( templates );
Menu.setApplicationMenu( menu );
のような感じで処理していたので app
や shell
のように
import Electron from 'electron';
const menu = Electron.menu.buildFromTemplate( templates );
Electron.menu.setApplicationMenu( menu );
と修正したら menu
プロパティの参照が実行時エラー。そこで electron/menu.md を読んでみたら掲載されている 2 種類のサンプルは共に electron.remote
経由で処理していた。ここで
- Main プロセスだと実行時エラーになること
- サンプルの
Menu
参照はelectron.remote
経由のものだけ紹介されていること
から Main プロセス版が廃止されたものと勘違い。そんな感じで困惑していることを Twitter でつぶやいていたら以下のような指摘が。
そして electron-api-demos/application-menu.js をみると Menu は electron.menu
ではなく electron.Menu
だった。
const electron = require('electron')
const BrowserWindow = electron.BrowserWindow
const Menu = electron.Menu
const app = electron.app
// ... 中略
app.on('ready', function () {
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
})
electron/docs にもちゃんと Modules for the Main Process 欄に Menu
や MenuItem
がある。これらや BrowserWindow
のように new
でインスタンス生成可能なものは camelCase でなく PascalCase で命名されているようだ。buildFromTemplate
などは Menu
の static method として提供されている。よって問題の処理は
import Electron from 'electron';
const menu = Electron.Menu.buildFromTemplate( templates );
Electron.Menu.setApplicationMenu( menu );
というように menu
ではなく Menu
で参照すればよかった。ドキュメントのサンプルについては 2016/5/11 夜の話であり、いずれ Main プロセス版が追加されるなどの訂正がおこなわれると思う。
この件における私の反省点。ドキュメントを調べることも大事だが、実行可能なデモがあるならそちらも当たるべきだった。それと自分が API リファレンスを書くときはサンプルとなるコードが単体完結しているか、それが難しければ文章で前提環境について言及するように心がけたい。
Devtron
Electron v1.0 リリースにあわせてアプリ開発の支援ツール Devtron も公開されていたので試す。提供形式は npm。サイズもさほど大きくないため Electron アプリのプロジェクト ローカルにインストールするとよいだろう。
$ npm i -D devtron
npm を追加した後にアプリを起動して Developer Tools を開く。そして Console タブのプロンプトでインストール用コマンドを入力してから Enter キーを押すと
> require('devtron').install()
Installing Devtron from ./node_modules/devtron
というようになる。これで Devtron が有効になるはずなのだけどタブがない。バグか?と思って Electron のリポジトリをチェックしたら Release electron v1.0.1 があった。そして Changelog には
Fix devtools extension not loading.
とある。なるほどね。というわけで v1.0.0 で再試行してみたのだけど、それでもダメだ。devtron/README.md には
You can reload the extension by closing and reopening the dev tools.
とあるのに Developer Tools を開き直しても反映されない。もしかすると BrowserWindow.toggleDevTools
だからなのかも。これはトグル形式の切り替えであり再起動ではなさそうなので。
最後の手段として Developer Tools の General にある Restore defaults and reload ボタンを押してみた。その後に Developr Tools を再表示すると Devtron タブが追加されている!よかった!
実際にこのツールが有効なことを確認するため IPC Monitor を利用してみる。Devtron タブを開いて左のメニューから IPC を選択してパネルを表示。パネルの右上にある Record ボタンが押されている状態で IPC の発生する操作をすると通信内容が出力された。
従来 Main プロセスで IPC の絡む問題調査には console.log
を利用していたけれど Devtron ならばコードに影響を与えず通信を監視可能。なので今後はこちらを利用することにした。
- 2016/5/16 追記 v1.0.2 の更新をみると Developer Tools の Extension 読み込みが改善されたらしく続けて v1.1.0 もリリースされていた。そこで改めて動作確認したところ Console から Devtron を有効化するとタブに即時反映され、かつアプリを再起動してから Developrt Tools を表示しても Devtron タブは維持されていた。つまり以下の問題は修正済みといえる。
問題点がひとつ。
Devtron を有効にした後にアプリを終了して再起動後、改めて Developer Tools を表示すると Devtron タブが消えていた。え?なんで?と困惑しつつ require('devtron').install()
し直したのだが表示されない。もう一度 Restore defaults and reload を押して Developrt Tools を再起動したら Devtron タブが表示された。いろいろ調査してみたところ
- Console からの
require('devtron').install()
は初回だけ実行すればよい - アプリを起動するたびに Developer Tools の Settings - General で Restore defaults and reload ボタンを押す
という条件を満たさなと Devtron タブは有効にならないらしい。他に試した方法は以下。
- Main プロセスの処理冒頭で
require('devtron').install();
を実行する- 実行時エラーになる
- Developer Tools の Console から実行しないとダメらしい
BrowserWindow.addDevToolsExtension
で Devtron を登録- 効果なし
- この方法は node_modules 配下のパス指定が面倒なので、成功したとしても採用したくない
- Developer Tools 表示を
BrowserWindow.toggleDevTools
からopenDevTools
に変更openDevTools
なら Restore defaults and reload 相当になるかも?と考えて試した- ふつうに表示されるが Devtron タブはないのでダメ
- この方法は自前でトグル管理することになり面倒なので、成功したとしても採用したくない
この動作がバグなのか仕様なのかは不明。Main プロセスを修正した場合は反映にアプリの再起動が必要なので仕様だとしたら毎回この操作が必要になって辛い。
タブを常駐させる方法については継続調査する。
パッケージ化におけるバージョン指定の簡略化
Electron v1.0 とは関係ないのだが、私はアプリのパッケージ化を npm-scripts で組んでおり electron-packager CLI を利用している。以下は OS X の定義。
{
"scripts": {
"release:pack-osx": "electron-packager ./dist/src AudioPlayer --out=dist/bin --cache=dist/cache --platform=darwin --arch=x64 --version=1.0.1 --overwrite --asar --icon=res/app.icns"
}
}
Electron のバージョンは --version
に指定。OS X 以外に Windows や Linux 版も対応する場合、変更箇所が増えて面倒でミスの危険も高まる。そこでこれを変数にできないか調べたら package.json
の config
を利用できるとのこと。
{
"config": {
"app": "AudioPlayer",
"electron": "1.0.1"
},
"scripts": {
"release:pack-osx": "electron-packager ./dist/src $npm_package_config_app --out=dist/bin --cache=dist/cache --platform=darwin --arch=x64 --version=$npm_package_config_electron --overwrite --asar --icon=res/app.icns"
}
}
こんな感じで config にプロパティ定義すれば npm-scripts から $npm_package_config_PROPERTYNAME
のように参照できる。接頭語が長すぎて読みにくいけど npm-scripts の定義はそうそう変更するものではないからよしとする。gulp から npm-scripts へ移行したとき、共通設定を変数化できないのが不満だったけど、これで解消された。調べてみるものだ。
config
をうまく利用すると npm-scripts の汎用性が高まる。これまで examples-electron ではプロジェクトごとにアプリ名が異なるためパッケージ指定も個別になっていたのだが、この部分を config
で変数化することにより定義を統一できた。異なるのは config
だけである。
- 2016/5/19 下記の問題を解決するために npm を作成。詳しくは npm-scripts でクロスプラットフォームに環境変数を参照するための npm を作成してみたを参照のこと。
- 2016/5/17 調査結果を npm-scripts で自前の環境変数を利用する方法と問題点という記事にまとめた。結論としては環境変数の展開方法が OS X や Linux の bash と Windows で異なるため標準の npm-scripts だとクロスプラットフォームな
config
の参照指定が無理という話。 - 2016/5/16
package.json
のconfig
による環境変数の定義は Windows 環境だと無効らしい。単純に環境変数をecho
するだけの npm-scripts を実行したら、値ではなく変数名がそのまま出力されてしまった。これが仕様なのかバグなのかは不明。継続調査する。