Meld LauncherをElectronに移植してみた
ちまたではNW.jsよりElectronの方がフィーバー(死語)している感じなので、ちょっと触ってみることにしました。
とりあえずHello World的なものをやろうかと思ったのですが、ざっと眺めた感じ、作り方はわりと似ている印象だったので、ここはひとつ、NW.jsで作ったアプリをElectronに移植する方が違いがわかるかもと思い、以前React + NW.jsで作っていたMeld Launcherを移植してみることにしました。
Electronへの移植
Electronプロジェクトの準備
Electronの開発を始めるにあたり、まずはランタイムとなる electron-prebuilt
を導入する必要があります。NW.jsにおける nw
ですね。
グローバルにインストールしてしまうのが手っ取り早そうですが、ここはNW.jsでもやっていた方式に従い、プロジェクトローカルに導入する方法にしました。
そこで、
$ mkdir meld-launcher-electron # プロジェクトディレクトリ作成 $ cd meld-launcher-electron # ディレクトリ内へ移動 $ npm init # package.jsonを生成 $ npm install electron-prebuilt --save-dev
といった感じで、プロジェクトフォルダを作成し、その中に electron-prebuilt
をインストールしました。
合わせて、プロジェクトに必要なnode_modulesをインストール。
$ npm install react --save $ npm install react-tap-event-plugin --save $ npm install react-loading --save $ npm install material-ui --save $ npm install browserify --save-dev $ npm install babelify --save-dev $ npm install watchify --save-dev
これ以外に、NW.jsのときは nw
とパッケージングツールの nw-builder
をインストールしていましたが、Electronのパッケージングツールとして electron-packager
を入れておきます。
$ npm install electron-packager --save-dev
プロジェクトの構造
プロジェクトの構造についても、まずはNW.jsで試していた構造を引き継ぐことにしました。
. ├── app │ ├── css │ ├── index.html │ └── js ├── dist ├── node_modules ├── package.json ├── resources │ └── icon │ └── nw.icns └── src └── jsx
アプリとしての構造は app フォルダ内にあり、変換前のJSXは src フォルダで開発。
最終的に配布用のビルドを dist フォルダへ出力する想定です。
アイコンはそのまま流用したので名前が nw.icns のままです。
移植
元になるNW.js版の umi-uyura/meld-launcher から、必要なものを移植します。
HTML/CSSをコピー
まずは app 内をごそっとコピー。具体的には、JavaScriptは後で生成するため、 index.html と app/css/app.css をコピーしました。
index.htmlからNW.js依存のコードを除去
app/index.html のうち、NW.jsの機能を使っているアプリ終了用のメニュー部分は削除。
<script> var gui = require('nw.gui'); var win = gui.Window.get(); var menubar = new gui.Menu({type: 'menubar'}); menubar.createMacBuiltin('Meld Launcher', {hideEdit: true, hideWindow: true}); win.menu = menubar; </script>
エントリポイントを作成
NW.jsではエントリポイントとしてHTMLを指定しますが、ElectronではJavaScriptを指定します。
そこで、エントリポイントとなる app/main.js を作成します。
中身は Electron公式サイト のQuick Start内にある Write your First Electron App に書かれているものを、ほぼコピペしました。
app/main.js
'use strict'; var app = require('app'); var BrowserWindow = require('browser-window'); require('crash-reporter').start(); var mainWindow = null; app.on('window-all-closed', function() { if (process.platform != 'darwin') { app.quit(); } }); app.on('ready', function() { mainWindow = new BrowserWindow({width: 600, height: 480}); mainWindow.loadUrl('file://' + __dirname + '/index.html'); //mainWindow.openDevTools(); mainWindow.on('closed', function() { mainWindow = null; }); });
package.json のエントリポイントも書き換えておきます。
{ ... "main": "app/main.js", ... }
実行
Electronの実行は electron
コマンドに package.json か、エントリポイントとなるJavaScriptファイルへのパスを指定して実行します。
package.json はプロジェクト直下にあるので、 その場で以下のようにカレントフォルダを指定することで実行できました。
$ $(npm bin)/electron .
パッケージング
最後にパッケージングしてみました。
パッケージングには electron-packager
コマンドを使用。
nw-builder
に比べるとオプションが多い印象ですが、その分細かい制御ができるとも言えるでしょう。
$ $(npm bin)/electron-packager . 'Meld Launcher Electron' --out=dist --ignore='dist|node_modules|resources|src' --icon=resources/icon/nw --platform=darwin --arch=x64 --version=0.32.3 --overwrite
nw-builder
と異なり、 --ignore
オプションでビルドに含めないファイルやフォルダを指定できる点は良いですね。これでパッケージング後には不要となる src フォルダや、開発時のみの node_modules などを除外することができます。(Meld LauncherではBrowserifyで全て結合しているので、 node_modules 自体を除外しています)
NW.js版では同様のことをするために、テンポラリの build フォルダを作って、一度その中にパッケージングするファイルだけをコピーして、それをパッケージングするという一手間をかけていたのですが、それがいらなくなります。
アイコンも --icon
オプションで .icns
へのパスを指定すればOK。
npm run scripts
パッケージングがNW.jsと比べるとシンプルになったので、 npm run scripts
の設定もNW.js版と比べると少なくできました。
... "main": "app/main.js", "scripts": { "start": "electron .", "babelify": "browserify -t babelify src/jsx/index.jsx -o app/js/bundle.js", "watchify": "watchify -t babelify src/jsx/index.jsx -o app/js/bundle.js -v", "dist:mkdir": "mkdir -p dist", "dist:package": "electron-packager . 'Meld Launcher Electron' --out=dist --ignore='dist|node_modules|resources|src' --icon=resources/icon/nw --platform=darwin --arch=x64 --version=0.32.3 --overwrite", "dist": "npm run babelify && npm run dist:mkdir && npm run dist:package", "clean": "rm -rf dist/*", "test": "echo \"Error: no test specified\" && exit 1" }, ...
NW.jsとElectronの比較
環境の差はあるものの、アプリ本体のコードには手を加えずに、Electron版を作ることができました。
また、そもそものアプリが超単機能なこともあり、正直なところ、NW.jsとElectronの差のようなものもわかりませんでした。
今回のアプリのソースコードレベルでは、エントリポイントのJavaScriptがあるかないか、というくらいの違いしかありません。
ただ、なんとなくですが、個人的には以下のような使い分けを想像しました。
NW.js
エントリポイントがHTMLであることから、作ろうとしているものが普通にブラウザ内で完結できそうなものだったり、既存のWebサイトをアプリ化するといった目的ならNW.jsで充分そう。
Node.jsに詳しくなくても、Webのシングルページアプリケーションが作れるのであれば、Electronよりは少ない手順でそれをデスクトップアプリ化できるので、フロントエンドメインの人がアプリ化してみたいということであれば、こちらの方がとっつきやすいのかも。
Electron
Node.jsベースで一からデスクトップアプリを作るという目的なのであれば、Electronを採用しておいたほうが後々良さそう。
エントリポイントがJavaScriptということで、あくまでブラウザ上で動かすものを単独のブラウザに切り出す印象が強いNW.jsに比べると、Node.jsとの親和性という面でもElectronの方が高そうなので、OSとのやり取り(ファイルシステムなど)が重要なアプリになると、こちらの方が力を発揮しそうな感じがしました。
また、Electronの方が開発が活発なようですし、迷うのであればElectron使っておいた方が良いのかもしれないです。
まとめ
というわけで、移植版のソースもGitHubへ。
umi-uyura/meld-launcher-electron
NW.jsとElectronどちらを使うかという点については、作るものにもよりますが、都度使い分けるというよりは、自分に合った方を採用する、という感じでも良いのかな―という感想です。
自分の場合、そこまで複雑なアプリは作っていないので、たぶんどちらでも良いレベルなのだと思いますが、次に何か作るときには改めてElectronで作ってみようかなと思いました。
参考
- Electron
- sindresorhus/awesome-electron - Electron事例集
- 30分で出来る、JavaScript (Electron) でデスクトップアプリを作って配布するまで - Qiita
- Electronでアプリケーションを作ってみよう - Qiita
JS+Node.jsによるWebクローラー/ネットエージェント開発テクニック
- 作者: クジラ飛行机
- 出版社/メーカー: ソシム
- 発売日: 2015/08/31
- メディア: 単行本
- この商品を含むブログ (1件) を見る