はじめに
みなさんmonaca使ってますか?
巷ではReactNativeやFlutterが流行っていますがmonacaもReactのソースを(ほぼ)そのまま転用出来るので悪くないと思っています。
ただ....
ただ.....!!
ビルドが遅い!!!!
RNやFlutterが実機でもホットリロードで即反映なんて言われていますが、monacaはuploadしてからremote buildするまで結構時間がかかります。
私のプロジェクトでも大体15分くらいかかります。
そのため、1回のビルドに
-
monaca upload
を実行してからQiitaを30分くらい巡回してアップロードの終了に気づく -
monaca remote build
を実行してからQiitaを30分くらい巡回してビルドの終了に気づく
合計1時間くらいかかります
~~ちゃんと見てろって話なんですが、~~なにかと作業効率が悪いのでmonaca-cliの結果を通知してくれるコマンド、monaca-cli-notificationを作りました。
Github: https://github.com/masaki-shinkawa/monaca-cli-notification
npm: https://www.npmjs.com/package/monaca-cli-notification
monaca-cli-notification
動作確認環境:macOS Mojave v10.14.5
Windowsは動作未検証のため動かない可能性があります
使用方法は、グローバルにインストールするか、package.jsonに追加してnpm scriptsから起動するかの2パターンです
(現状npxに対応していません)
npm i -g monaca-cli-notification
npm i -D monaca-cli-notification
"scripts": {
"remote-build": "mcn remote build ios --build-type=debug",
"upload": "mcn upload --delete"
},
基本的にはmonaca-cliをラップしているだけなのでmonacaのコマンドは何でも使えます。
$ mcn
$ mcn upload --delete
$ mcn remote build ios --build-type=debug
コマンド結果によりデスクトップ通知が表示されます。
成功した場合
失敗した場合
実装の話
紹介だけも何なのでどのような構成で作成したか紹介していきます。
開発環境
開発環境は Typescript + Node.js で作成しました。
今回特に型を意識する必要もないのですが、babelを設定しなくていいというだけでTypescriptを使う価値があると思います。
依存関係のパッケージ
実現するために下記のライブラリを使用しました。
対話式コマンドの対応
monaca-cliは随所で対話が発生します。そのため、対話式のcliに対応する必要がありました。
その解決策としてnode-ptyを使用します。
node-ptyはプロセスを仮想端末として扱ってくれるようで、標準出力と標準入力をやり取りすることができます。
使用方法は簡単で、pty.spawn
にコマンドと引数を渡すとインスタンスが生成されので、
そこから生えている.on("data", (e) =>{})
に標準出力内容が流れてきます。
// ptyのインスタンスの生成
const ptyProcess = pty.spawn(command, argv, {
name: "xterm-color",
cols: 80,
rows: 30,
cwd: process.env.PWD,
env: process.env
ptyProcess.on("data", (data: any) => {
process.stdout.write(data); // コマンドの結果がdataに代入されている
});
また、.on("exit", (e) => {})
にはコマンドのexitCodeが設定されるため、
その結果を見て正常終了、異常終了の判定が可能です。
ptyProcess.on("exit", (exitCode: number) => {
if (exitCode === 0) {
// 成功の通知を出す
} else {
// 失敗の通知を出す
}
});
対話が発生した場合は.write(string)
を実行することで入力を送信することができます。
これでmonacaの対話にも対応することが出来ました。
ptyProcess.write(str + "\n");
ユーザーからの入力受付
入力を送信することは出来る様になったのですが、ユーザーからの入力を受け入れれていないのでその対応にreadline
を使用します。
この処理は「Node.jsでの標準入力(コンソール)について」が非常に参考になりました。ありがとうございます。
単純にユーザーからの入力を無限ループで待受続け、入力が合った場合に.write(string)
を呼び出すだけです。
//keypressイベントを使用可能にする
readline.emitKeypressEvents(process.stdin);
//readlineのインスタンスの生成
const rl = readline.createInterface({
input: process.stdin, //標準入力を指定
output: process.stdout, //標準出力を指定
prompt: "", //デフォルトのプロンプトを指定(指定なしで"> ")
terminal: true //process.stdin.setRawModeでエコーバックの切り替えを可能にする
});
(async function() {
while (true) {
const str = await new Promise(res => rl.once("line", res));
ptyProcess.write(str + "\n");
}
})();
注:readlineが生き続けているとプロセスが終了しません。
そのため、ptyの.on("exit", (e) => {})
の最後にreadline
をcloseさせる処理を追加してあげます。
ptyProcess.on("exit", (exitCode: number) => {
if (exitCode === 0) {
// 成功の通知を出す
} else {
// 失敗の通知を出す
}
rl.close(); // readlineをcloseする
});
デスクトップ通知を出す
対話の処理が出来たので後はデスクトップ通知を出すだけです!
デスクトップ通知は非常に簡単で、node-notifierを使用すると簡単に実装できます。
const notifier = require("node-notifier");
module.exports = {
failedNotification: () => {
notifier.notify({
title: "Failed",
message: "コマンドが失敗しました..."
});
},
successfulNotification: () => {
notifier.notify({
title: "Successful",
message: "コマンドが成功しました!"
});
}
};
簡単すぎる・・・!
これだけでこのメソッドが呼ばれた時にデスクトップ通知が行われます。
npmに公開
npmに公開する前にwebpackで圧縮したmcn.js
を実行しようとしましたが下記のようなエラーが発生してコマンドラインから実行できませんでした。
bin/mcn.js: line 1: syntax error near unexpected token `e'
bin/mcn.js: line 1: ...
nodeで実行する分には動くのになぜ・・・?と思いましたが単純にnode.jsで実行する記述がないため、bashで起動されているのが原因でした。
shellやperlでも先頭行によく書く、あれです。
#!/bin/bash
#!/usr/bin/perl
nodejsの場合はこう書きます。
#!/usr/bin/env node
ただし、.tsや.jsにそのまま書くとwebpackに怒られるため、webpack.BannerPlugin
というプラグインを使います。
const webpack = require('webpack');
module.exports = {
:
plugins: [
new webpack.BannerPlugin({ banner: "#!/usr/bin/env node", raw: true }),
]
}
こうすることでビルド後のファイルの先頭に#!/usr/bin/env node
を追記してくれ、無事にコマンドラインから実行することが出来ます。
おわりに
今回1,2時間程度で突貫で作ったツールのため、テスト環境なんかも全く用意していないのですが、よければ使ってみてください。 この記事の方が時間がかかったパターン
monacaはまだまだ戦えるプラットフォームだと思うのですが、実機テストがもう少し簡単になるといいですね・・・
このツールもせっかくなのでオリジナルコマンドとかを追加していければ良いなと思います。
mcn remote build ios --build-type=debug --upload --delete
参考
node-pty
node-notifier
Node.jsでデスクトップ通知(gulpもね)
node-notifier