Share functionality between nodes

Hi folks,

I developed a long time ago the node-red-contrib-msg-speed node. But I need to develop another node, which needs the reuse most of the internals as the speed node. I would like to share the functionality between both nodes, to avoid having to maintain it twice...

What is the best way to deal which such a situation:

  1. Extract that functionality from the speed node and isolate it into a new separate npm package (and let both nodes use that package as a dependency).
  2. Other solutions?

Thanks!
Bart

Hi Bart,

Publish the "speed code" as an NPM package and include it in your 2 other projects. NPM will deduplicate under the hood.

Thanks Steve!

And do you have any good practices for such a common NPM package?
My simplified speed-node package contains this:

module.exports = function(RED) {
    "use strict";
    var CircularBuffer = require("circular-buffer");
    var Math = require("mathjs");

    function speed(config) {
        RED.nodes.createNode(this, config);
        // Initialization code

        this.on("input", function(msg) {
            // Message handling code
        });
        
        this.on("close",function() {   
            // Cleanup code
        });
    }

    RED.nodes.registerType("msg-speed", speed);
};

Do you have any advise on how such a common NPM package could look like (and how I can call it both my nodes)?
Because most of the code in the 3 code blocks would be common for both nodes, but each node also needs to execute some dedicated code in each block ...

So which bit is common ? Just the requires ? If so I wouldn’t worry. Just duplicate it and let npm take care of it.

In fact I mean that every of the 3 blocks (initialization, message handling, cleanup) contain shared code, which should be part of the common npm package. But my both nodes - which depend on this package - should be able to execute their own code in each block.

Probably there is a very simple solution, but I don't see it at the moment ...

Well if they are related functions (ie also to do with speed) - such that you would ship them both as one package then you can define them both in the same files. If not then not easily no.

Ok, thanks guys!

I have now extracted the core functionality from the node-red-contrib-msg-speed, and moved it to a new nr-msg-statistics package.

For anybody who needs to do something similar in the future, below you can find how I did it. Although there might be many ways to get to Rome ... But since I have a background as object oriented developer, I really wanted to use ES6 classes to accomplish this. So no callback functions for me this time :roll_eyes:

  1. In the new Github repository, I encapsulated all the shared functionality into a class (which will be exported):

    module.exports = class MessageAnalyzer {
       constructor (config) {
         // Do some initialization, and store the Node-RED node config into this instance
         this.someProperty = config.someProperty;
         ...
       }
     
       someMethod(someParameter) {
          ...
          this.doSomething();
          ...
          this.doSomethingElse();
          ...
       };
    
       doSomething() {
       }
    
       doSomethingElse() {
       }
    }
    
  2. The someMethod contains my old logic (of the speed node), which I want to reuse in other nodes.
    But at some points in the code I call the (e.g. empty) methods doSomething and doSomethingElse.

  3. I added the new npm package as a dependency in the package.json file of my speed node:

     "dependencies": {
         "nr-msg-statistics": "^1.0.0"
     },
    
  4. The speed node now imports this class, and creates a subclass of it. That subclass will override the methods doSomething and doSomethingElse to do stuff that is specific to this speed node:

    module.exports = function(RED) {
       function speedNode(config) {
          RED.nodes.createNode(this, config);
         
          var node = this;
         
          const MessageAnalyzer = require('nr-msg-statistics');
         
          class MessageSpeedAnalyzer extends MessageAnalyzer {
             doSomething() {
                 // Do some speed related stuff
             }
     
             doSomethingElse() {
                 // Do some other speed related stuff
             }
         }
         
         // Create an intance of the subclass
         var messageSpeedAnalyzer = new MessageSpeedAnalyzer(config);
    
         // By calling this method, underneath the doSomething and doSomethingElse will be called.
         messageSpeedAnalyzer.someMethod(...);
       }
    }
    

So I can reuse the code (in the MessageAnalyzer class) to share it between multiple Node-RED nodes, and each node can overwrite the methods to do stuff that is specific to that node ...

Damn it was fun working with classes after a long time :clinking_glasses:

1 Like