Inheritance of custom nodes

Hey there,

im writing currently a lot of custom nodes for my company and im interested in a general concept of custom node inheritance.
Im dividing my functionality from the ui part. that allows me to use another node as dependency and using its library functions in my new node.
But apparently i also want to use some core node functionalities. Like the Schema-Validation of the json node and i do not want to reimplement always functionality into my new node!

Does it make sense to you to setup a best practice guideline for reusage of nodes or do you think its better to completly divide the nodes to avoid clashes if one node updates it's functionality and breaks a node which is using it as dependency?

As with all things with dependencies it will depend on your attitude to risk. There will always be a risk that some dependency may change and break things. Indeed the schema-validation has just changed in the core json node to drop some old versions that you may have needed...
So if you plan to actively maintain your nodes on an ongoing basis then you can monitor and keep up with dependency changes then you may be ok. If you plan to just release your nodes and only fix them when broken then they may be more stable if you rely on fewer dependencies... up to you.

Hey dceejay,

thanks for the reply. I think for me and my nodes it makes sense because i will maintain them actively.
But my question was more focused on the core nodes. Currently there is no option to make an inheritance of a node right? Because the .js file is to closely coupled with the node red node functions like

this.on("input", function(msg,send,done) {
...

or am i missing something here how to extend the functionality of an existing node?
Lets say i would like to use the validation function of the json core node in my custom node.

is it possible to include the complete module and use the node.on... functions ?

No, we do not have any established pattern for node inheritance.

Would it make sense to you to do it in the future?

Here is the way im currently doing it.
Im used to build a lib.js for my nodes.
Example:

const commonLib = require('../common-lib')

class Thing {

    validateSomething(object){
       // function code
    }

    onCreate(RED, node, config) {                   
    }

    onInput(RED, node, msg, send, done) {
        this.validateSomething(msg.something)
        done()
    }

    onClose(RED, node, done) {
        done()
    }


}

module.exports = { Thing }

in my actual node.js im including this lib.js like

module.exports = function (RED) {
    "use strict";
    const lib = require('./lib')

    function ThingNode(config) {
        RED.nodes.createNode(this, config);
        const node = this;
        if (config.once === undefined) { config.once = true; }
        if (config.showOnlyTabId === undefined) { config.showOnlyTabId = true; }

        node.showOnlyTabId = config.showOnlyTabId
        node.once = config.once;
        node.onceDelay = (config.onceDelay || 0.1) * 1000;

        let thing = new lib.Thing()

        // creates
        thing.onCreate(RED, node, config)

        node.on('input', function (msg, send, done) {
            thing.onInput(RED, node, msg, send, done)
        });
             
        node.on('close', function (done) {
            thing.onClose(RED, node, done)
        });
    }

    RED.nodes.registerType("thing", ThingNode);
}

then im able to use this node as a dependency in another node and use it's lib functionality
like the validateSomething(object)

Hi @H3llsing,
I have recently put some of the shared logic of two of my nodes into npm package nr-msg-statistics. It is added as a dependency e.g. in my node-red-contrib-msg-speed as a dependency, where I create a subclass.
Perhaps not the best way to do it, but it now saves me a lot of work...
Bart

1 Like

hey @BartButenaers,
thanks for sharing. Looks like the same concept. Outsourcing functionality and including it in other nodes.
With one difference, you made an extra npm package out of it which is great if someone wants to use your functionality without node-red.

I think it would be great if we could make a guideline for this => Inheritance of nodes and how to create them.

I think this comes down as well to the usual development dilemma. Whether to split something into its own module/library or not. In uibuilder, I have a couple of modules. One contains generic utilities that I might want to reuse called tilib.js and indeed I have reused that in another of my nodes, but only a manual copy. At some point I might well convert that single .js module into a package though so that it can be easily reused.

For the core nodes, there might well be code that could benefit by being split into a separate module file which could then be used in multiple places and in other contrib nodes - but how does anyone know? And, as always, who is on hand to do the work?

I would imagine that, with a bit of confirming discussion, Nick might be more than happy if someone were prepared to learn enough about the core code to split something into a separate module file :grinning: Particularly if that someone also reworked some tests and perhaps even suggested some improvements or bug fixes!

Of course, some documentation would also be needed, especially if that module were to be used by contrib nodes.

Just an idea. But hopefully you can see that it would take a bit of effort and that has to be balanced against all of the other priorities.

@H3llsing,
How do you share your lib.js file between your nodes, which are located in separate npm modules? Is a copy of your lib.js file somehow included in every npm module of every of your nodes?

Just put it and publish it in its own package Bart, then make it a dependency of your node packages.

Hi Julian,
That is indeed how I have done it. But @H3llsing seems to share his lib.js between his nodes, without using a separate npm package for lib.js (if I understood him correctly). So I was wondering how he has achieved that...

If you bundle all your related nodes in one package, then you can place the shared routines in a file in the package of nodes and require it using a relative path.

3 Likes

in the parent node which is using the dependency node you can do something like this:

const paramCheck = require('mynode-contrib-param-check/lib')
paramCheck.doCheck(msg, paramsToCheck)

in the parent node package file:

  "dependencies": {
    "mynode-contrib-param-check": "1.0.6",

so they do not need to be bundles into one package :slight_smile:
i think thats because they will install these dependencies into a sub node-modules folder.

.node-red/node_modules/your-package/node_modules

1 Like

yes of course 2.0 has prio and maybe with this step and the growing knowledge of Typescript the core nodes could be refactored.
i've took a deep look over the last month into some core nodes but as all of us i got just a little bit of freetime and there are other construction sites that need to be finished :slight_smile:

I would like to rework some nodes,but apparently my company do not have a concept for working on open source yet. So i only my afterwork time can be used for this but it's in discussion.

You can even create data that is shared between instances of your nodes as I've now done in uibuilder with all of the ExpressJS code. I moved it to a separate module as a class. The class operates as a "singleton" which means that it is instantiated in the module and therefore (thanks to the mechanics of require) only once no matter how many times you require it. See web.js in uibuilder. I did the same for all of the Socket.IO processing (socket.js).

Because all code in Node-RED runs in the same Node.js instance, that also means that other nodes could reference the ExpressJS and Socket.io class instance created by uibuilder.

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.