I've been writing custom nodes for my own projects for a couple of years, and kept copying the same chunks of code. Every node that did real work needed a worker thread, most of them needed the editor side to talk to the runtime side, and half of them needed an endpoint to serve a script to the editor. I got tired of that and pulled it all into one re-usable package. I'm putting it out here in case my structure is useful to anyone else
It's on npm as @nrutils/node-red-utils and the source is at GitHub - UpDownMe733/node-red-utils: Mixin toolkit for authors of Node-RED custom nodes: editor messaging, worker threads, popups, singletons, resource serving, pub/sub and optional GPU compute. · GitHub
(Disclaimer: the readme's are a lot of AI slop)
So you know what you're looking at, it's not a node, and it doesn't do anything you can't do already. It's a different way to lay out the code, and a way to use some of the harder bits of the Node-RED API (worker threads, admin endpoints, editor-to-runtime messaging) the same way every time instead of reinventing it per node.
You could write node's with this shape without my library, today. You would just need the base class.
With AI you don't really need any library but this gives it ways to do things consistently like worker comms and front-end comms. I'm sure as AI gets better none of this will matter.
The basic shape
You use the base class and declare what functions to use in your node in an array param.
const { NodeRedNodeBase, nodeRedEditorComms } = require('@nrutils/node-red-utils');
module.exports = NodeRedNodeBase.createNode('counter', [nodeRedEditorComms], (RED, thisNode, config) => {
let count = 0;
const show = () => thisNode.status({ text: `${count} messages` });
// the button in counter.html sends this
thisNode.nodeRedEditorComms.subscribe('reset', () => {
count = 0;
show();
});
thisNode.on('input', (msg, send, done) => {
count++;
show();
send(msg);
done();
});
});
Each feature is a mixin. If you put it in the array it's on thisNode, and if you leave it out it isn't. Writing your own mixin is a small function, so if you have your own "I always need this" chunk of code, it fits in the same way.
The mixins I use
nodeRedWorkerruns your node's work in a worker thread. The part I like is that if two worker nodes are wired together in the flow, the messages go from thread to thread without bouncing through the main event loop. That's been handy for anything CPU heavy.nodeRedEditorCommsis pub/sub between the node in the editor and the same node in the runtime. The example above uses it for a reset button. You don't write an admin endpoint and you don't poll.nodeRedPubsubBusis pub/sub between nodes in the runtime without wires. I use it for the stuff that isn't really a message flow, like config changes and shared state.nodeRedResourceEndpointserves your scripts, CSS and images to the editor.nodeRedPopup,nodeRedSingletonandnodeRedGpu(Vulkan compute from a worker) work, but I've marked them experimental because I'm the only one who has used them.
The README has a full counter example and a worker example, and a few snippets here and there. I didn't include full worked nodes bc that's not what this is.
Expectations
I'm one person doing this on the side. I'll keep up with issues and PRs for as long as it holds my interest, which, going by my track record, is a while but not forever. If it's useful to you, fork freely. It's Apache-2.0.
Questions, bug reports and "why on earth did you do it this way" are all welcome, here or on GitHub.
Enjoy!