シェルにも使える!nodemon を使ってコードに変更があった場合にホットリロード(自動再起動)させる
はじめに
Node.js でアプリケーション開発をしている際に、コード変更が行われたら自動的に再起動したいと思いました。
ちょうど GraphQL を使ってアプリケーションを開発していたのですが、 GraphQL のスキーマ変更は( Apollo Server の) 再起動を行わないと変更が反映されません。
nodemon というツールを使うことで簡単に実現できました。
作業環境
$ node --version
v15.12.0
「nodemon」 ってなに?
- 2021-04-09 現在で 1500 万を超えるプロジェクトで利用されているツール
- ソースコードの変更を監視している
- 変更があったら自動定期にサーバプロセスを再起動してくれる
「nodemon」 の使い方は?
とても簡単です。node
コマンドの代わりに nodemon
コマンドを使います。ただそれだけ。
それだけで、コードの変更を検知したら自動的に再起動してくれます。
「nodemon」 コマンドの特徴
ほぼこれを使えば困ることがないぐらい、機能豊富です。
特徴を上げてみます。
- アプリケーションを自動的に再起動してくれます
- いくつかの拡張子に該当するファイルを自動的に探して監視してくれます
.js
.mjs
.coffee
.litcoffee
.json
- デフォルト挙動では
node
コマンド + 監視機能 として動作しますが、python
コマンド + 監視機能 や、ruby
コマンド、make
など、任意のコマンド実行に切替可能です - 指定したファイルやディレクトリを監視対象から外すこともできます
- 指定したディレクトリだけを監視させることができます
- 自作のスクリプトから呼びだあすことも可能
インストール方法
npm
コマンドが使えれば簡単にインストールできます。
$ npm install -g nodemon
「システムのグローバル領域にインストールしたくない!」、「バージョン依存の問題を回避するためプロジェクトディレクトリにインストールしたい」といった場合は以下のコマンドでも OK。
$ npm install --save-dev nodemon
プロジェクトディレクトリにインストールされた nodemon
を使いたい場合、 npx nodemon
コマンドを実行するのが良いでしょう。
使い方
nodemon
コマンドは node
コマンドのラッパーです。node
コマンドで利用できる引数はそのまま利用できます。
例えば node -c
でコードチェックを行えますが、 nodemon -c
でもコードチェックを行えます。
// index.js
console.log("hello1");
console.log("hello2" // ← わざと括弧を閉じていない
# node コマンドでチェック。 括弧が閉じられていないエラーが発生
$ node -c index.js
/private/tmp/work/index.js:3
console.log("hello2"
^^^^^^^^
SyntaxError: missing ) after argument list
at Object.compileFunction (node:vm:355:18)
at wrapSafe (node:internal/modules/cjs/loader:1022:15)
at checkSyntax (node:internal/main/check_syntax:66:3)
at node:internal/main/check_syntax:39:3
# nodemon コマンドでチェック。 括弧が閉じられていないエラーが発生
$ nodemon -c index.js
[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node -c index.js`
/private/tmp/work/index.js:3
console.log("hello2"
^^^^^^^^
SyntaxError: missing ) after argument list
at Object.compileFunction (node:vm:355:18)
at wrapSafe (node:internal/modules/cjs/loader:1022:15)
at checkSyntax (node:internal/main/check_syntax:66:3)
at node:internal/main/check_syntax:39:3
[nodemon] app crashed - waiting for file changes before starting...
nodemon
コマンドはチェックを実行しても、コマンドが終了しません。
この状態で index.js
を正しく修正し保存をすると、再度チェックが実行されます。
今度は以下のように何も表示されません。( コードチェックの結果、問題がなかった )
[nodemon] restarting due to changes...
[nodemon] starting `node -c index.js`
[nodemon] clean exit - waiting for changes before restart
出力されているログの見方
先程実行した nodemon -c
コマンドのログを見てみます。
$ nodemon -c index.js
[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node -c index.js`
/private/tmp/work/index.js:3
console.log("hello2"
^^^^^^^^
SyntaxError: missing ) after argument list
at Object.compileFunction (node:vm:355:18)
at wrapSafe (node:internal/modules/cjs/loader:1022:15)
at checkSyntax (node:internal/main/check_syntax:66:3)
at node:internal/main/check_syntax:39:3
[nodemon]
という文言が前方についている行とついていない行があります。[nodemon]
という文言がついている行は、 nodemon
コマンド自体が出力した情報となります。[nodemon]
という文言がついていない行は、 nodemon
コマンドに指定したスクリプト(ここでは index.js
ですね)が出力したログになります。
これを知っていれば、ログの見方がわかります。
nodemon は CLI ツール開発時にも利用できる
nodemon はもともとハングしたサーバプロセス(例えば Web サーバ)を再起動するために作られたようです。
では、実行したらすぐに終了するようなプログラムの場合は使えないのか?というとそういうわけでは有りません。
試してみます。以下のようなスクリプトを作成します。
// date.js
console.log("---");
console.log(new Date());
console.log("---");
このスクリプトを nodemon
コマンドで実行します。
$ nodemon date.js
[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node date.js`
---
2021-04-08T23:14:25.262Z
---
[nodemon] clean exit - waiting for changes before restart
ここで、スクリプトの内容を変更します。
// date.js
console.log("---");
console.log("*****");
console.log(new Date());
console.log("*****");
console.log("---");
保存するとすぐにスクリプトが自動的に再実行されます。
$ nodemon date.js
[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node date.js`
---
2021-04-08T23:14:25.262Z
---
[nodemon] clean exit - waiting for changes before restart
[nodemon] restarting due to changes...
[nodemon] starting `node date.js`
---
*****
2021-04-08T23:16:09.721Z
*****
---
[nodemon] clean exit - waiting for changes before restart
ちょっとしたスクリプトを開発しているときでもこれは便利です。
nodemon を明示的に再起動する
実行中の nodemon
コマンドですが、再起動したい場合は nodemon の停止 → nodemon の起動 を行う方法とは別の方法も用意されています。
実行中のターミナルで rs
とタイプし、最期に ENTER を入力します。
---
*****
2021-04-08T23:21:11.221Z
*****
---
[nodemon] clean exit - waiting for changes before restart
rs # <<<<< ここでrs<ENTER>を入力している
[nodemon] starting `node date.js`
---
*****
2021-04-08T23:21:13.482Z
*****
---
[nodemon] clean exit - waiting for changes before restart
PHP コードを監視させてみる
PHP でちょっとした CLI ツールを作成してみたりしている時に使えるかもためしてみました。
まずは index.php
を作成します。以下のコード
# phpがインストールされていることを確認
$ php --version
PHP 7.2.34 (cli) (built: Feb 27 2021 17:44:53) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.34, Copyright (c) 1999-2018, by Zend Technologies
# phpスクリプトを作成
cat <<'EOF' >index.php
#!/usr/bin/env php
<?php
echo "Hello, World", PHP_EOL;
EOF
このファイルを nodemon
で実行してみます。
$ nodemon index.php
[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: php,json
[nodemon] starting `node index.php`
/private/tmp/work/index.php:2
<?php
^
SyntaxError: Unexpected token '<'
at Object.compileFunction (node:vm:355:18)
at wrapSafe (node:internal/modules/cjs/loader:1022:15)
at Module._compile (node:internal/modules/cjs/loader:1056:27)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1121:10)
at Module.load (node:internal/modules/cjs/loader:972:32)
at Function.Module._load (node:internal/modules/cjs/loader:813:14)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:76:12)
at node:internal/main/run_main_module:17:47
[nodemon] app crashed - waiting for file changes before starting...
エラーが発生してしまいました。
これは監視対象の index.php スクリプトを node
コマンドで実行しようとしたためです。php
コマンドを使って実行するように指定します。 --exec php
というオプションを付与します。
$ nodemon index.php --exec php
[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: php,json
[nodemon] starting `php index.php`
Hello, World
うまくいきました。
ここで index.php
を少し編集してみます。
#!/usr/bin/env php
<?php
echo "Hello, World", PHP_EOL;
echo "Hello, World again", PHP_EOL;
保存すると即座に再実行されます。
追加されたロジックが反映されていますね。
[nodemon] restarting due to changes...
[nodemon] starting `php index.php`
Hello, World
Hello, World again
[nodemon] clean exit - waiting for changes before restart
実行時オプションを設定ファイルに保存する
毎回実行するようなオプションは設定ファイルに書き出して置くことができます。
特に拡張仕事に実行するコマンドはほぼ決まっていると思いますので、拡張子と実行コマンドのマッピングを事前に行っておくと便利です。
設定ファイルはプロジェクトごとのディレクトリに配置してもいいですし、ユーザのホームディレクトリに配置しても構いませんが、 nodemon.json
という名前にしておく必要があります。
先程の PHP スクリプト実行時に --exec php
オプションを付け忘れてしまいましたが、忘れていても正常に動作するようにしてみます。
nodemon.json
を作成します。
{
"execMap": {
"php": "php"
}
}
たったこれだけです。 "php": "php"
の記述ですが、左がファイルの拡張子を表しています。右がその拡張子のファイルを実行する際に利用するコマンドです。
では先程の index.php
を実行してみます。
$ nodemon index.php
[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: php,json
[nodemon] starting `php index.php`
Hello, World
Hello, World again
[nodemon] clean exit - waiting for changes before restart
正しく実行されました。
シェルスクリプトも自動実行させてみる
シェルスクリプトも自動実行させてみたいと思います。nodemon.json
を修正します。
{
"execMap": {
"php": "php",
"sh": "bash"
}
}
先程のファイルに一行追加しました。
さらに適当なスクリプトを作成し、 nodemon
に監視させます。
$ touch main.sh
$ nodemon main.sh
[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: sh,json
[nodemon] starting `bash main.sh`
[nodemon] clean exit - waiting for changes before restart
main.sh
を修正します。
#!/usr/bin/env bash
echo "*****"
date
echo "*****"
保存すると、 nodemon
実行ログに出力内容が追加されます。
[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: sh,json
[nodemon] starting `bash main.sh`
[nodemon] clean exit - waiting for changes before restart
[nodemon] restarting due to changes...
[nodemon] starting `bash main.sh`
*****
金 4 9 08:40:25 JST 2021
*****
[nodemon] clean exit - waiting for changes before restart
ひとこと
シェルスクリプト開発時に重宝しそうですね。
JavaScript 界隈は進化が早いのでおじさんには生きにくい世界です。 (^_^;)
ディスカッション
コメント一覧
まだ、コメントがありません