ReactとElectronでアプリケーションをすぐに作るやり方
Origami Mar 5 Updated on Jun 05, 2018
こんにちは。前置きは抜きにすぐ作ります。
Create Application
01: create-react-app
まずはcreate-react-appです。なかったらnpm install -g create-react-app
してください。
うまくいったらyarn start
で起動しましょう。しましたか?うまくいってるのを確認したら即刻ジョブ止めましょう。もう二度とyarn start
を実行することはありません。
02: install Some Package
以下のパッケージをインストールしてください。最新ので問題はないはずです。すべてインストール時に--dev-dependencies
を付けることを忘れないでください。まあ忘れてもいいです。
- electron
- foreman
03: setting up Electron
こちらのgistを参照してください。
まずProcfile
です。これはプロジェクトのルートディレクトリに置いてください。
次にelectron-starter.js
、electron-wait-react.js
、application.js
をsrc/
以下に配置してください。色々書いてありますが後ほど説明します。
04: package.json
package.json
にmainとhomepage、そしてscriptsに追記します。以下のようになればいいです。
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"main": "src/electron-starter.js",
"homepage": "./",
"dependencies": {
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-scripts": "1.1.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"electron": "electron .",
"dev": "nf start"
},
"devDependencies": {
"electron": "^1.8.2",
"foreman": "^2.0.0"
}
}
いくつか興味深いところはありますが、後ほど解説します。今はこれをただ受け入れてください。でも名前は好きに変えてもいいのよ。
05 start!
ではいよいよ動かす時が来ました。yarn dev
あるいはnpm run dev
を実行し、ブラウザとElectronが立ち上がって、同じ画面が映っていることを確かめてください。
また、もう既にこの時点でElectron側にもホットロードが機能していることも試してみましょう。src/App.js
の構文をわざと間違えて、ブラウザとElectronの両方の画面がエラーになることを確認するのです。
ホットロードまで確認したら、おめでとうございます!あなたはReactでElectronアプリケーションを作ることに成功しました。
さて、いくつか気になる所があったはずです。それらは次の項で説明します。
Explanation Create Application
Structure
今回のElectronアプリケーションの構造は比較的単純です。react-scripts
によって起動したWebサーバに、Electronがアクセスして表示しているだけです。本当にこれだけです!図にするまでもありませんが、図にしてみましょう。
ところで、react-scripts
とelectron
はforemanによってそれぞれ起動されます。この設定はProcfile
に記述されています。
Security Warning?
まず、あなたが最新のElectronで開発している場合、yarn dev
あるいはnpm run dev
を実行した場合にconsoleに次のような警告が出ているはずです。
Electron Security Warning This renderer process has Node.js integration enabled and attempted to load remote content. This exposes users of this app to severe security risks.
For more information and help, consult https://electronjs.org/docs/tutorial/security
これは要するに「なんかWebページをElectronで見てるけどここに悪意あるコード仕込まれてたらすごいやばいことが起きるぞ!」という警告です。
なぜ、この警告が出たかは自明ですね?今回の(開発時の)設定では、静的なHTMLやJavascriptファイルではない、localhostに立ち上がっているWebサーバ localhost:[port number]
をElectronでアクセスしているために、このエラーが発生しています。
勿論ビルド時にはWebサーバーではなく、ビルドした静的なhtml, css, javascriptファイルをElectronに読ませるため、このセキュリティ警告は発生しません。安心してください。あなたのElectronアプリケーションは(今のところ)安全です!
package.json
私は先程、何も言わずにしれっとpackage.json
に、以下の項目を追加していました。
"homepage": "./"
もしあなたがこの項目をpackage.json
に追加していないのならば、すぐに追加すべきです。この項目は開発時には効果をまったく発揮しませんが、ビルド時にはとても重要な項目となります。
ネタバレをしてしまうと、react-scripts build
を実行した際、出力されたindex.html
がpackage.json
のあるディレクトリをベースに、同じくビルドされたJavascriptファイルやCSSファイルへアクセスするために設定されています。
少しわかりづらいですか?まあ要するにこの設定がないとreact-scripts build
の実行時にうまくファイルたちが関係を持てない、という具合に覚えておけばいいです。
Build and Release
01 setup
さて、いよいよ時が来て、あなたのElectronアプリケーションをリリースしたい時がやってきました。
今回はだるいのでautoupdater等の解説はしません。しかし、npmでelectron-packager
とasar
をdevDependenciesとしてインストールしておいてください。
かつ、これはかなり大切なことなのですが、今あなたのpackage.json
の"dependencies"
にはreact
、react-dom
、react-scripts
の3つが入っているはずです。(何も手を加えていないのであれば)
それをすべて、"devDependencies"
に黙って移動させてしまいましょう!なに、バレませんよ。
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"main": "src/electron-starter.js",
"homepage": "./",
"dependencies": {
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"electron": "electron .",
"dev": "nf start"
},
"devDependencies": {
"electron": "^1.8.2",
"foreman": "^2.0.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-scripts": "1.1.1"
}
}
ああ、なんてこと…"dependencies"
が空っぽになってしまいました。しかしご安心ください。これはこの後に効いてくる、とても効果的な、最高の設定です。
02 build
npm run build
あるいはyarn build
を実行してください。
03 packager
さて、electron-packager
の設定を忘れていました。追加しましょう。package.json
のscriptsに以下の一文を追加します。
"package": "electron-packager . my-app --platform=all --arch=x64 --prune --out=release --overwrite"
さて、実行してみましょう。yarn package
あるいはnpm run package
の出番です。
時間がかかります。3分ぐらいから5分とか。気長に待ちましょう。
04 run!
パッケージングがうまくいっていれば、release
ディレクトリの中に各種バイナリが発生しているはずです!
ただし、macOSとlinuxの場合、wineがないとwin32向けビルドが発生しません。同様に、Windowsでは管理者権限のあるコンソールでないとmas(macOS)向けビルドが発生しません。(darwin向けビルドはなぜかできません)
この記事を見ているみなさんのOSは仮定しません。自分の環境で動きそうなバイナリを探してください。
わはー!動きましたね!そして、http://localhost:5000 にアクセスしても、Webサーバーが立ち上がっていないので何も表示されませんし、consoleでSecurity Warningが発生していないことを確認しましょう。静的なファイルを読み込んでいる証拠です。
…さて、これでビルドは終わりではありません。もう少しだけ、先に進んでみましょう。
05 delete unnecessary files
release
ディレクトリにぶちまけられた各種バイナリには、無駄なファイルが潜んでいます。特に、あなたがエディタに使っているのがVisual Studio Codeだった場合、.vscode
などがそのままバイナリに入っています。
…バイナリという言葉に少々語弊がありますが。とにかく、以下のディレクトリに注目してください。
windows : /release/[app-name]-win32-x64/resources/app
darwin : /release/[app-name]-darwin-x64/[app-name].app/Contents/Resources/app
mas : /release/[app-name]-mas-x64/[app-name].app/Contents/Resources/app
linux : /release/[app-name]-linux-x64/
appディレクトリの中です。.gitignore
や、あろうことかsrc
ディレクトリまでそのまま入ってしまっています…これは問題です!消してしまいましょう。ただし、srcディレクトリには注意してください。electron-starter.js
とelectron-starter.js
は消してはいけません。これらは開発時と同じく、ビルド後のElectronもアクセスするファイルです。それ以外は消してしまいましょう。
app
│ package.json
│
├─build
├─node_modules
└─src
│ application.js
└ electron-starter.js
掃除後のディレクトリ構造はこのような状態になっているはずです。おっと、build
とnode_modules
には基本的に手を出してはいけませんよ。それからpackage.json
を消すのもダメです。
(補足:buildディレクトリには各種mapファイルが出力されてもいます。もし実際に配布するのであれば、~.js.map
と~.css.map
ファイルを消すのが無難でしょう)
これで実質的な最小の状態になりました。この状態でもアプリケーションが問題なく起動することを確かめておきましょう。
06 asar
さて、先程のrelease以下のそれぞれのappディレクトリはこのままでもいいですが、Electronはasarでappディレクトリを圧縮することを推奨しています。一つ前のディレクトリにまでコマンドラインで戻り、appをasarで圧縮します。
> asar pack app app.asar
のち、appディレクトリを削除します。
この状態でアプリケーションが問題なく起動することを確かめてください。
07 zipping application
あとは、releaseディレクトリ以下のそれぞれのディレクトリをZIPかなにかで圧縮すれば、もう配布可能なバイナリになりました。おめでとうございます!
ただし、darwin(mas)にはアプリに署名をするという大切な工程もありますが、今回は無視しています。各位で調べてください。
Explanation Build and Release
Why moved all package from dependencies to devDependencies?(it's important!)
これはかなり奇妙な行動に思えたはずです。なぜすべてのパッケージをdevDependenciesに移動したか?それは配布後のパッケージのサイズに関係してきます。
まず大前提をお話しましょう。今回特に、react-scripts
はかなり大きなパッケージであるということが関係してきます。react-scripts
の関係するパッケージはまとめて100MBを超えています。このパッケージを配布バイナリに含めるとなると、それだけで数百MBもサイズが膨れ上がってしまいます。
ところで、アプリケーションとして配布する時、パッケージング前にreact-scripts build
を実行したことを覚えていますか?build実行時にreact
やreact-dom
それらをすべてまとめてbuildディレクトリ以下のファイルにまとめて梱包して出力してくれるのです。これらは裏でwebpack
が動いてくれているからなのですが。
まあそれはさておいて、この時点でbuildディレクトリの中のファイルはnode_modulesとは(ほぼ)関係なしに動いてくれるようになりました。
つまり、electron-packager
を使ってElectronアプリを梱包する時、もうreact-scripts
は必要ないのです!また、それはreact
とreact-dom
に対しても言えることです。今後導入するであろうredux
、react-redux
、redux-saga
などのパッケージに対しても同様です。開発時とビルド時にのみ必要なパッケージは、すべてdevDependencies(開発時の依存関係)に入れてしまいましょう。
devDependenciesに突っ込んだパッケージは、electron-packager
がすべて取り除いてくれます。
ただし、例外もあります。Electronではrenderプロセス――つまりsrc/index.js以下のどこかのタイミング――でNode.jsとそれらを使用したパッケージにアクセスできることをご存知でしょうか?electron.remote.require()のことです。
もしあなたがNode.jsを使用したパッケージをelectron.remote.requireを使用して呼び出していた場合、そのパッケージはdevDependenciesに入れてはなりません。
なぜならば、そのパッケージは実行時にnode_modules
から呼び出されるからです。
同様に、今回で言えばapplication.js
など、Electronが直接読むスクリプトの中で呼び出しているパッケージも同様にdevDependenciesに入れてはいけません。たとえば、electron-about-window
などです。
以上のことはかなり注意すべきことです。覚えておきましょう。
Why don't use --ignore
option in electron-packager?
…これは本当に私もわからないのですが、Windowsから--ignore
オプションを使おうとすると、どうしてもエラーが起きてしまって、パッケージングできないという問題があります…未だに不明なのですが、linuxやmacOSをお使いの皆さんなら使えるはずです。都度使ってみてください。正規表現パターンを使用してパッケージング時に不要なファイルを削除できます。また、不要なファイルを全て削除できるなら--asar
オプションでasarに圧縮するところまで自動でやってくれます。
私はそれがどうしてもできないので、自分でビルドスクリプトを書きました。みなさんも勝手に書くべきです。
Conclusion
今回、webpackの設定ファイルを一切書いてないことに気付きましたか?かなり込み入ったことをしない限り(ejectを必要としない限り)は、webpackの設定ファイルを一切書くことなくElectronアプリを書けることがわかりましたね。さらにcreate-react-appでは型チェックツールであるFlowもそのまま使うこともできます。
宣伝ではありますが、これとほぼ同様のやり方でTsuruも開発されています。
この記事はHow to build an Electron app using create-react-app. No webpack configuration or “ejecting” necessary.
をベースに、さらに踏み込んだ所まで解説した記事です。