Node-REDのversion 1.3が2021年4月8日に公開されました(参照: Version 1.3 released, バージョン1.3がリリースされました)。
この記事では、Node-RED 1.3の新機能の一つである「Plugin framework」について紹介します。
Plugin frameworkとは?
これまで、Node-REDに機能を追加する方法には下記の方法がありました。
- Node-RED本体のコードを直接書き換える
- Node-REDのノードとして新機能を実装し、npmパッケージとしてインストールする
1つめの方法は一番自由度が高く任意の機能を追加可能となりますが、追加した機能を切り出して配布するのは困難です。またNode-RED本体がバージョンアップした際には、更新したコードを改めて新しいバージョンへと適合させる必要があります。
2つめの方法は機能を実装したコードがnpmパッケージとして分離されているため、機能の配布も容易になりますし、新しいバージョンへの追従も、APIの変更にのみ注意すればよいこととなり追従が容易になります。しかし、単にエディタ側に機能を追加したいときなどは、ノードのランタイム側の機能部として空のノード定義をしなければならないなど、不自然な記述が増えてしまいます。
Plugin frameworkでは、これを改善するために下記の特長を持っています。
- エディタ側・ランタイム側のうち、拡張が必要な側のみのコードを記述すればよい。
- プラグインから他のプラグインの機能を利用することができ、プラグイン自体を拡張可能になる。
- プラグイン内の特定のフォルダにいれたファイルを、エディタ側からHTTP APIを介して読み込むことができるため、任意の画像ファイルやJavascriptライブラリをエディタ側に追加するのが容易になる。
Plugin frameworkの機能の詳細
Pluginは、npmパッケージの形で実装します。フォルダの構造は下記のようになります。
|- package.json
|- plugin.js
|- plugin.html
\- resources
|- resourcefile.js
package.json
package.json
には、通常のnpmパッケージとして記述する項目以外に、このモジュールがNode-REDのプラグインであると認識させるための下記の情報を記述します。
"node-red": {
"plugins": {
"sampleplugin": "plugin.js"
}
}
plugins
の値となるオブジェクトは、キーとしてプラグインの名前(この例ではsampleplugin
)、対応する値としてプラグインを実装しているファイル(この例ではplugin.js
)を持ちます。もし、エディタ側のみに拡張が必要な時には.htmlファイルを指定します。
ランタイム側の拡張
ランタイム側のコードでは、プラグインを登録するためにRED.plugins.registerPlugin()
を実行します。
module.exports = function(RED) {
// ...
RED.plugins.registerPlugin("sample-runtime-plugin-identifier", {
type: "sample-runtime-plugin-type",
onadd: function() {
// プラグインが登録されるときに実行される
},
onremove: function() {
// プラグインが登録解除される時に実行される
},
settings: {
// $HOME/.node-red/settings.js から読み込む設定項目と、エディタ側に公開するかのフラグ
sampleSetting: { value: "sample", exportable: true }
}
});
}
上記のコードでは、プラグインの識別子およびタイプの登録と、プラグインが登録/登録解除されたときに実行される関数、およびsettings.js
から読み込む設定項目を指示しています。
これにより、ランタイムにプラグインが組み込まれ、RED.plugins.getPluginsList()
などのランタイムAPIから
プラグインが参照できるようになります。通常、onadd
で定義した関数内で各種イベントに対するハンドラを登録することがプラグイン実装の中心になります。
エディタ側の拡張
エディタ側にもほぼ同様の枠組みが用意されています。ただし、settings.js内の設定項目の参照は
ランタイム側で設定するためエディタ側のコードでは設定がありません。
<script type="text/javascript">
//...
RED.plugins.registerPlugin("sample-editor-plugin-identifier", {
type: "sample-editor-plugin-type",
onadd: function() { /* ... */ },
onremove: function() { /* ... */ }
});
</script>
ランタイムと同様、上記APIの呼び出し以降はRED.plugins.getPluginsList()
などでプラグインを参照することが
できます。
Resources ディレクトリ
エディタ側の機能拡張では、追加の画像ファイルやHTML/CSSファイルを用意することが多くなります。
ノードのプラグインでは、これらのファイルを読み込むためには独自でAPIエンドポイントを用意し、
そのエンドポイントを使ってファイルをエディタ側に読み込むことが必要でした。
Plugin frameworkでは、パッケージのresources
フォルダに格納したファイルが
/resources/<プラグインパッケージの名前>/<resourceフォルダ内のファイル名>
として見えるようになります。
これにより、エディタ側のHTMLファイルで
<img src="/resources/plugin-package-name/foo.svg">
と記述することでresources/foo.svg
を読み込めるようになります。なお、エディタ/ランタイムでRED.plugins.registerPlugin()
を実行しなくても、package.jsonにnode-red.plugins
を記述すれば公開されます。
なお、Plugin frameworkの仕様の詳細は、下記デザインノートに書かれています(注: 2021年4月27日現在、Pull Requestがマージされていないため見つけづらいです。)
Plugin frameworkをつかった機能追加の実例
ここでは、「Node-REDのフローエディタのメニューに新たな項目"Greetings"を作り、それを選ぶとアラートに"Hello, plugin"と表示されるようにする」というシンプルなプラグインを作成します。
フォルダの構成は下記の通りになります。
|- package.json
|- greetings.html
\- resources
|- hello.png
まず、package.jsonを記述します。
{
"name": "node-red-contrib-plugin-greetings",
"version": "1.0.0",
"description": "add greeting menu item",
"author": "Your Name",
"license": "Apache-2.0",
"node-red": {
"plugins": {
"greeting": "greeting.html"
}
}
}
つぎに、プラグインの本体となるgreeting.html
を作成します。
<script type="text/javascript">
RED.plugins.registerPlugin("greeting-menu", {
type: "greeting-menu",
onadd: function() {
RED.actions.add("greeting:selected", function() {
RED.notify('<p><img src="/resources/node-red-contrib-plugin-greeting/hello.png">Hello, plugin!</p>', "success");
});
RED.menu.addItem("red-ui-header-button-sidemenu", {
id: "menu-item-greeting",
label: "Greeting",
onselect: "greeting:selected"
});
}
});
</script>
ここでは、RED.plugins.registerPlugin()
でプラグインを登録し、登録完了時のコールバック関数onadd
内で
メニューを選んだ時に表示される内容の設定(RED.actions.add()
)と、
メニューへの項目の追加(RED.menu.addItem()
)を実行しています。
最後に、通知に表示される画像ファイルをresources/hello.png
に配置します。
これでnpmパッケージが出来上がりましたので、Node-REDのユーザディレクトリ(通常はホームディレクトリの.node-red)にインストールします。(<...>/node-red-contrig-plugin-greeting
には上記パッケージ一式を格納したフォルダのパスが入ります)
% cd ~/.node-red
% npm install <...>/node-red-contrib-plugin-greeting
それでは実行してみましょう。
メニュー最下部に"Greeting"という項目ができているのがわかります。
ここで"Greeting"を選ぶと、下記のように"Hello, plugin!"とかかれた通知画面が表示されます。
ごく簡単な機能ですが、Node-RED本体のコードに手を入れることなくエディタの機能が拡張できることが理解できたのではないでしょうか。
おわりに
これまではNode-REDの拡張には、Node-REDのコアを注意深く改造していく必要がありましたが、このPlugin frameworkやRuntime Editor Split、Pluggable Message Routingなどの形で拡張機能が比較的容易に実装できるようになってきました。Pluginの形で革新的な機能が導入され、成熟した時点でNode-REDに取り込まれる、という形でNode-REDの機能がコミュニティの手で磨かれていく流れができることが楽しみです。
Node-RED 1.3新機能紹介
- Node-RED1.3の新機能: Plugin framework (本記事)
- Node-RED1.3の新機能: Functionノード
- Node-RED1.3の新機能: サブフローのノード化