Node RED v4 : Single File Executable

Afternoon,

It's Back!!
Single File Executable for Node RED v4 (With the option of embedding your flows)


Some History:

A while ago, I posted a guide on how to create an SFE :
See Node-RED Standalone Executable - #12 by marcus-j-davies

This quickly become incompatible shortly after, due to ESM being used and various other changes in the core, so I have spent many many hours in getting this working... and


Today:

I share a new guide:

  • Easier
  • Node RED v4
  • Allows embedding a flow (i.e protecting your IP)
  • Allows hiding your logic

It contains the following routines:

  • Converting the ES Modules to CommonJS (got for example, used by the http-request node)
  • Bundling Node RED to a single file
  • Patching Node RED and other source files, where needed
  • Packing them into an executable
  • You don't need to do the above yourself :grin:

What's more, this new guide has an easier way to embed your flows, that are loaded from within the executable.


Let's Begin


Adjust the Settings "file"

The Node RED settings object, can be found in main-source.js
you will see some hackery here - don't mess with it, such as the userDir redirect

  • Only change flowFile if it is different.

  • You MUST change secret !

  • disableUI should be set to true (IF) embedding the flow.
    The editor security routines, seems to want to write to userDir, so just disable it.

    NOTE: This should be done just before compiling the executable
    (not during design) - see below

you can (I think) treat this like the standard settings.js file


Then

  • If you DON'T want to embed a flow [ userDir : {PWD}/Home ]

    • npm run-script build
    • npm run-script package
  • If you DO want to embed a flow [ userDir : Embedded ]

    • npm run-script design
    • Design your flow, publish, install nodes etc etc
    • Terminate once you're done
    • set disableUI to true (if you want to hide the Editor)
    • npm run-script build
    • npm run-script package

Congratulations!

You now have a Node RED executable in ./build/dist
as well as embedded nodes and the flow being run from the embedded flows file, if you decided to.


Lastly,

I have spent sometime getting this right and working, but I more than happy for contribution here.
I'm sure it can be optimised in areas!

I developed this toolkit on OSX, but can't see why it wouldn't work on other platforms.
And do note: the executable is built for the platform this toolkit is run.

Note : I have favoured Node 20 in these scripts

Please do comment and add your input

Enjoy (now I am off for a gin :grin:)

10 Likes

8 Likes

Update!

You no longer need to install extra nodes via the command line.
you can install them as normal. :smiley:

(I have updated the guide above, and the Gist)

2 Likes

OK - Something for the weekend folks!


This little adventure of mine, has now been morphed into a complete solution!

I am in belief, A Node RED project as an executable, is an extremely powerful tool, and one that has a place, delivering results utilising Node RED!

Introducing : Node RED SFE

Say what!?


Node RED SFE, is a project that is targeted at creating solutions with Node RED, with the end result being a Single File Executable - aka SFE

It's a Framework, Toolkit... to create executables containing solutions in a packaged application, with Node RED at the heart of the operation!

It takes care of everything to achieve an SFE with Node-RED, with a few bells and whistles

Please give the repo a good read, and I am open to comments/slander/abuse - however you want to destroy my work :wink:

Happy Weekend

2 Likes

This might be perfect for my needs. I'm approaching completion of a flow for a project I am intending on packaging with Electron and to target Steam as my distribution platform. Steam has specific requirements.

I am very open to an alternative solutions. Could you describe the advantages that your solution might provide over Electron?

Hi @HaroldPetersInskipp

I don't have much exposure to electron - but isn't it more about a Web UI/HTML wrapped in a native window? - I could be wrong.

I suppose the way I have approached this project, is purely around running a flow (that can expose a web based interface or not - such as D2) <--- which I have tested BTW :smile:

Node RED SFE is to package anything that Node RED can do - into a single executable file.

If that means exposing a dashboard to UA's (Browsers) - then so be it.

1 Like

Also, with the filesystem being read only, if I store variable in my flow like flow.set("example", value, "file") to use the "file" store in my setting.js will they still work correctly? I was under the impression that they are stored in a "context" folder as a "flow.json" file.

Correct!

Node RED SFE uses a Virtual File System (embedded into the executable) - so File based context is still to be investigated & explored

With that said, Node RED SFE - gives you access to the settings file (before build time), so is open for the developer to devise their own storage mechanics.

Node RED SFE works in 2 Ways

  • Embedded Flow (Embedded userDir)
  • SFE with an external userDir

So would flow.set("example", value, "memoryOnly") need to be implemented currently? I don't think I need to store them in the filesystem (TBH it's probably dramatically increases IO operations needlessly and would perform much better).

flow.set("example", value) will work in the same way Node RED does... its held in process Memory I think.

There is no difference in this area - the only difference is in the Disc IO space

Awesome, this sound like exactly what I've been looking for. Thank you a tremendous amount, you have probably saved me a ton of headache/time.

1 Like

Filesystem context does not (by default at least) write to disc every time you update the data. It flushes to disc at a frequency determined by the settings in settings.js. Typically this is set to 30 seconds. There should be no effect on performance unless you have large amounts of data in context.

Good to know. I am running it on a Pi Zero W as well as on Windows so what qualifies as large amounts of data in that scenario? I think I'm storing roughly ~300 variables or less, most are short strings and two are short arrays?

FWIW: As this is a toolkit, you can add any storage mechanism you wish.

Example: This is the built in Log function (exposed as global.get("SFELOG"))

const Log = global.get('SFELOG');
Log('info','My Application','Hello, World')

These principles can be applied in anyway you wish - sky is the limit :nerd_face:

I suppose that on a Pi with an SD card then if one was writing megabytes every 30 seconds then that might be considered undesirable, but a few kBytes is nothing to worry about. As a general rule, though, don't put stuff in file based context unless you need it to be retained over a restart.

@HaroldPetersInskipp

The localfilesystem context store (file) is now fully supported.
This is achieved by re-configuring it, to use the directory the executable is run from.

This is only re-configured, for an embedded flow

flow.set("Foo","Bar")          /* Memory (Default) */
flow.set("Foo","Bar","memory") /* Memory */
flow.set("Foo","Bar","file")   /* File */

see : Add support for file `localfilesystem` context store · marcus-j-davies/Node-RED-SFE@4e961ce · GitHub

1 Like

Maybe a dumb question, but I did not find an answer: is it a Windows exe or an ELF binary for Linux?

Hi @stefan24

It is compiled for the platform it is built/packaged on.

I have tested this on a MAC and a Windows machine

4 Likes

Dude! You are amazing, thank you again.

1 Like

How does serving static files from a relative path work, just put it in the setting.js (I'm coming from absolute paths on linux so I might need an example)?

In my linux instance settings.js I currently have:

httpStatic: {
        path: '/home/raspberry/.node-red/static/',
        root: '/',
        options: {
            maxAge:'1d',
            setHeaders:function(res,path,stat){
                res.set('x-timestamp',Date.now())
                if(path.endsWith("png")){res.setHeader('Cache-Control','public, max-age=86400')}
            }
        }
    },

How can I convert it for portability on Windows?