Heroku 用に Node-RED をプロジェクトフォルダ配下で Node-RED エディタ画面でノードの追加インストールも動くようにするメモ

Heroku 用に Node-RED をプロジェクトフォルダ配下で Node-RED エディタ画面でノードの追加インストールも動くようにするメモです。

やりたいこと

Node-RED をあるローカルのフォルダだけで動くようにプロジェクトを作るメモ

個人的には、こちらのプロジェクトフォルダにある node-red_dir 内で Node-RED の挙動が閉じれるのが好みだったんですが、ちょっと Heroku のために修正したほうがいいところが出てきたので対応します。

どういう不都合が起きたか

プロジェクトフォルダ直下に集約した Node-RED 環境を Heroku で動かすメモ

こちらを動かしていた時です。

ローカルで動かす分にはいいんですけどね。Heroku だと今回の node-red_dir フォルダに封じ込める仕組みでやってしまうと、Node-RED エディタ画面でノードの追加インストールしたものが自動で更新されないので困りました。

標準ノードだけでノードを手元で組んでアップロードする分には問題ないです。

それもそのはず、 Heroku はアプリ更新時にプロジェクトフォルダ直下の package.json だけをみて、もしそこに、新しいライブラリがインストールされていれば追加インストールされるという仕様でした。プロジェクトフォルダ直下の package.json のみです。

なので、もし、Node-RED エディタ画面でノードの追加インストールを行った場合、プロジェクトフォルダ直下の package.json ではなくて node-red_dir 内の package.json に追加インストールされても、Heroku 更新時に反映されないということになります。

たとえば、node-red-dashboard をインストールした時の node-red_dir/package.json 様子です。

{
    "name": "node-red-project",
    "description": "A Node-RED Project",
    "version": "0.0.1",
    "private": true,
    "dependencies": {
        "node-red-dashboard": "~3.0.4"
    }
}

これをどうするかというところで、

  • node-red_dir/node_modules を .gitignore から外してコミット時に反映するようにする
  • Heroku 側の起動コマンド Procfile や、それに付随する npm scripts コマンドで node-red_dir/package.json を更新するように頑張ってみる
  • プロジェクトフォルダ配下で動くようにユーザーフォルダと設定ファイルの向き先を変える

の 3 案を検討しましたが、以下の考えで、

  • node-red_dir/node_modules を .gitignore から外してコミット時に反映するようにする
    • 手元で npm インストール済みの資産が使えるので一見よさげだが、node_modules の中身全部となると大量のファイルを更新することになりGitのコミット大変。
    • Heroku のサーバー内は Linux で動いている。 Windows で成功している node_modules をコミットして反映しても Linux で諸々の事情でちゃんと動くとは限らない。
    • よって、採用しづらい
  • Heroku 側の起動コマンド Procfile や、それに付随する npm scripts コマンドで node-red_dir/package.json を更新するように頑張ってみる
    • たしかに調べれば知見はなくもなさそうだが、悩ましい。
    • 毎度 node-red_dir/package.json 用の追加インストールが走り、その後に Node-RED の起動がされるとなると、追加インストールが遅延したり、何かしらの破損をして、Node-RED 起動が走るなんてことがあると、まあまあ検証しづらそうな気がしている
    • よって、採用しづらい
  • プロジェクトフォルダ配下で動くようにユーザーフォルダと設定ファイルの向き先を変える
    • node-red_dir フォルダに封じ込められないのは不本意だが、まっとうな変更っぽい
    • いまのところ採用

node-red_dir フォルダに封じ込められないのは直下が、ちょっとゴチャッとして不本意ではあるんですが「プロジェクトフォルダ配下で動くようにユーザーフォルダと設定ファイルの向き先を変える」を採用しました。

対応方針

以前のものから、

  • init:mkdir を削除して node-red_dir フォルダ作成しないようにする(プロジェクトフォルダ直下で動作させるため不要)
  • init:get-settings.js で settings.js を Web 上から取得してから配置する場所をプロジェクトフォルダ直下する

参考までに、Node-RED をあるローカルのフォルダだけで動くようにプロジェクトを作るメモ で使っていたプロジェクトフォルダ直下の package.json です。

{
  "name": "sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "node-red": "./node_modules/.bin/node-red -p 18801 -u ./node-red_dir -s ./node-red_dir/settings.js",
    "init":"npm run init:mkdir && npm run init:get-settings.js",
    "init:mkdir":"node -e \"console.log('[START] mkdir-node-red_dir');const fs = require('fs');const path_nodered_dir = './node-red_dir';if (fs.existsSync(path_nodered_dir)) {console.log( '[ALERT] ' + path_nodered_dir + ' has existed!');} else {console.log('[OK] mkdir -> ' + path_nodered_dir );fs.mkdirSync(path_nodered_dir);}\"",
    "init:get-settings.js": "node -e \"const url = 'https://raw.githubusercontent.com/node-red/node-red/master/packages/node_modules/node-red/settings.js';const stream_output_path = './node-red_dir/settings.js';if (fs.existsSync(stream_output_path)) {console.log( '[ALERT] ' + stream_output_path + ' has existed!');} else {console.log('[START] download settings.js ...');const https = require('https');const fs = require('fs');const stream = fs.createWriteStream(stream_output_path);https.get(url, function(res){res.pipe(stream);res.on('end', function () {stream.close();console.log('[OK] got settings.js! -> ' + stream_output_path);});});}\""
  },
  "keywords": [],
  "author": "",
  "license": "MIT"
}

出来上がった package.json がこちら

対応方針を踏まえて出来上がった package.json がこちらです。

{
  "name": "sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "node-red": "./node_modules/.bin/node-red -p 18801 -u ./ -s ./settings.js",
    "init":"npm run init:get-settings.js",
    "init:get-settings.js": "node -e \"const url = 'https://raw.githubusercontent.com/node-red/node-red/master/packages/node_modules/node-red/settings.js';const stream_output_path = './settings.js';if (fs.existsSync(stream_output_path)) {console.log( '[ALERT] ' + stream_output_path + ' has existed!');} else {console.log('[START] download settings.js ...');const https = require('https');const fs = require('fs');const stream = fs.createWriteStream(stream_output_path);https.get(url, function(res){res.pipe(stream);res.on('end', function () {stream.close();console.log('[OK] got settings.js! -> ' + stream_output_path);});});}\""
  },
  "keywords": [],
  "author": "",
  "license": "MIT"
}

scripts で init:mkdirがなくなり init:get-settings.js を修正しています。

こちらで作った仕組みで追加インストールもしてみたところ、うまく更新されました。

今回の仕組みを今までの対応にも加味していこうと思います。前の記事、修正しなきゃ。