[Node.js] Electron、それは果てしなく「今日は世界!」が続く世界
Electron、それは果てしなく「今日は世界!」が続く世界
0. 作ったもの
1.やりたかったのはWebアプリをWindowsのデスクトップアプリへ移植すること
Node.jsを使い、MyDNSのユーザ情報を管理するWebアプリケーションを作成しました。しかし他人のユーザ情報を管理するのはさすがに怖いので、サービスとしては公開していませんでした。いっそデスクトップアプリにしてしまえば問題ないと思い立ち、Electronを使いパッケージ化することにしました。
2.Electronの利用方法を調べると、みんな挨拶しかしていない
Node.jsをパッケージ化するための方法はいくつかありますが、一番まともそうな方法はElectronを使うことでした。ということで情報を調べていくと、ことごとくが「今日は世界」を表示するところで終わっています。「おまえら、どれだけ挨拶すれば気が済むんだ?」と心の中で叫ぶしかありませんでした。しかも、挨拶ラッシュが起こってからけっこう時代が進んでいるらしく、パッケージ化の情報が新旧入り交じっていました。
3.とにかく簡単に移植したい
Electronをがっつり使いたいわけではありません。実質、ローカルWebServerと専用ブラウザとしての機能が使えれば良いのです。Electronでメインととレンダラを繋ぐためのプロセス間通信モジュールとかありますが、それを使った時点でWebアプリの移植に余計な改変を加えなければなりません。一切使わない方針を決めました。普通にAjaxが使えるんだから、移植だったらそのままいけば良いだけです。欠点があるとすればTCPのポートを一個、起動時に用意しなければならないぐらいです。
4.SQLite3の恐怖
Electronはネイティブのライブラリが含まれているモジュールをそのまま動かしてくれないようです。大半の人が引っかかるであろうモジュールは、SQLite3だと思われます。ということで専用ビルドをかけなければなりません。コンパイルに必要な設定は以下の通りです。
- Python2.7系統にpathを通す(先頭に記述しないとStoreが起動)
- VisualStudioのインストール
- VS2019の場合
- C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin にパスを通す
- インストーラを起動してVS2015のビルドツールの追加
- npm install sqlite3 --build-from-source --save --runtime=electron --target=5.0.1 --dist-url=https://atom.io/download/electron
5. メインプロセスのconsole.logの文字化け
Electronの動作をPowerShellから実行するとそのままではconsole.logで文字化けします。対処法はElectron実行前に、
chcp 65001
で、文字コードをUTF8にすることです。Electron利用時のconsole.logはデバッグ出力をするためなので、実際のところ日本語を出さなければ話は簡単です。
6. パッケージの作成
以下の設定をpackage.jsonに追加し、electron-builderを実行します。electron-packagerの方は設定が不便なので使いません。
{
…
"build": {
"productName": "出力アプリケーション名",
"appId": "hogehoge-hoge",
"directories": {
"output": "build"
},
"files": [
"dist/**/*"
],
"win": {
"target": "nsis"
}
},
…
}
7. Webアプリ移植時に追加するコード
余計な改変を最小限にするためバックエンド起動処理のindex.tsに、Electronのウインドウ表示処理を入れています。本来のWebアプリはバックエンドの処理のみを記述していました。この部分以外、Electron専用のソースは書いていません。
import * as amf from 'active-module-framework'
import * as electron from 'electron'
import * as path from 'path'
const listenPort = 58621
/**
* Electron用起動設定
*/
const app = electron.app
let window: electron.BrowserWindow|null = null
//Electronで実行されているかとUNIXドメインソケットを使用していないか確認
if (app) {
//ウインドウが閉じられた場合の処理
app.on("window-all-closed", async () => {
if (process.platform != "darwin") {
await manager.destory() //バックエンド処理を終了させる
app.quit() //アプリケーション終了
}
})
//ウインドウ表示処理
const init = () => {
window = new electron.BrowserWindow({ width: 1280, height: 720, autoHideMenuBar: true })
//起動メッセージの表示
window.loadURL(`file://${path.resolve(__dirname,'../template/electron.html')}`)
}
//準備完了時に初期化
if (app.isReady()) {
init()
} else {
app.once("ready", () => {
init()
})
}
}
/**
* バックエンドが準備完了になった場合の処理
*/
const listened = (port: number | string|null)=> {
if (window){
if (port === null){
//ポート使用中のエラー表示
window.loadURL(`file://${path.resolve(__dirname, '../template/electron.html')}?cmd=error&port=${listenPort}`)
}
else if(typeof port === 'number'){
window.loadURL(`http://localhost:${port}`)
}
}
}
/**
* バックエンドの設定
*/
const manager = new amf.Manager({
remotePath: '/', //一般コンテンツのリモートパス
execPath: '/', //コマンド実行用リモートパス
indexPath: path.resolve(__dirname, '../template/index.html'),//index.thmlテンプレート
rootPath: path.resolve(__dirname, '../public'), //一般コンテンツのローカルパス
cssPath: ['css'], //自動ロード用CSSパス
jsPath: ['js'], //一般コンテンツのローカルパス
localDBPath: path.resolve(__dirname,'../db/app.db'), //ローカルDBパス
//localDBPath: path.resolve('app.db'), //ローカルDBパス(カレントパスに設定)
modulePath: path.resolve(__dirname, './modules'), //モジュール配置パス
jsPriority: [], //優先JSファイル設定
debug: false, //デバッグ用メッセージ出力
listened, //初期化完了後コールバック
//listen: listenPort //受付ポート/UNIXドメインソケット
listen: path.resolve(__dirname, '../sock/app.sock') //UNIXドメインソケットを使用する場合
})
ウインドウを表示後にバックエンド処理がlisten可能になったらページを切り替えています。Electronから起動していない場合はappにインスタンスが入らないので、Electronがらみの処理を行いません。こうやって書いておけば、通常のNodeプロセスとして起動しても動きます。その場合、通常のWebアプリモードとなります。
8. ビルド手順
package.jsonのscriptが以下のようになっています。フロントエンドはWebPack、バックエンドはtsc、パッケージ化はelectron-builderを利用します。さらにSQLite3のインストールを忘れないように書いておきました。
{
・・・
"scripts": {
"start": "node dist/app/index.js ",
"watch": "tsc -b -w",
"build-app": "tsc -b",
"build-front": "npx webpack",
"build-electron": "npx electron-builder --win",
"install-sqlite": "npm install sqlite3 --build-from-source --save --runtime=electron --target=5.0.1 --dist-url=https://atom.io/download/electron",
"run": "electron ."
},
・・・
}
手数が多いというか、使っているものがどんどん増えていく感じがなんとも言えません。
9. 使っているもの
- フロントエンドフレームワーク (オレオレフレームワーク)
- バックエンドフレームワーク (オレオレフレームワーク)
- パッケージ化
Webアプリを素早く作成するため、オレオレフレームワークで固めました。フロントエンドは有名どころのVue.jsやReactが、私としては使いにくかったので全部自作です。
Webアプリを作るときの理想は、フロントエンド側はJavaScriptを呼び出すための初期ページ以外はHTMLを書かないことです。バックエンド側の理想は、初期ページの吐き出し以外に一切のHTMLを出力せず、データのやりとりのみを記述することです。
10. まとめ
最近のWebプログラムは、エコシステムが発達したおかげで、コマンド一発で便利なライブラリやフレームワークが手に入ります。入門記事を見ながら進めれば、なんとなく雰囲気をつかむところまでは到達できることでしょう。しかし「今日は世界」を卒業しようとすると、途端に情報量が少なくなり、その先は茨の道が待っています。何をやろうにも必要とする技術が多岐に渡り、初学者が始めようとすると、そこそこの地獄を見ているのではないでしょうか?
結局のところ試行錯誤して、自分なりの正解を見つけるしかありません。用意されているものを敢えて使わないという選択肢もあるのです。プログラムはやりたいことを書いていけば、思った通りには動きませんが書いた通りには動きます。「今日は世界」を突破して、新たな世界を開拓しましょう。そこはそもそも挨拶の必要が無い、誰もいない不毛の土地かもしれませんが。
Author And Source
この問題について([Node.js] Electron、それは果てしなく「今日は世界!」が続く世界), 我々は、より多くの情報をここで見つけました https://qiita.com/SoraKumo/items/61b76c83f5bdf869e8d0著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .