Importing function from another node

Hi everyone,
i want to import a function from another node.
For example i have two nodes.
One node e.g. the 'hello-world-node' prints "hello world" to a txt-file.
The other node, 'fake-hello-world-node', should do the same as the 'hello-world-node' but the second node just import the functionality from the first node.

Is this possible?

Have a look on subflows. You can wrap your function in a subflow and then use in different places in your flow. The same functionality will be available.

2 Likes

Thanks! :slight_smile:
Where can i find the file/ source code of the fake-hello-world-sublfow?

You can't. A subflow is a flow that is contained in a wrapper.

Another way to do what you are asking is to define the function to the settings.js file's globals section. Then you can var myfn = global.get('myfn') in any function node.

Alright. Thanks for the quick answer!

I have a similar solution that I often use, calling it the "module pattern". I keep my shared modules on the very first tab, triggered by a trigger node ('Inject once after...' option), so they get initialized first and put into global context.

image

The "module" (an example):

const util = (function () {
    'use strict';
    
    function add(a, b) {
        return a + b;
    }
    
    return {
        add: add
    };
    
}());

global.set('util', util);

It is wrapped in an IIFE so I can use strict mode, something you can't do in the function node itself.

In your function nodes you can use it the same way as yours, but with the benefit of having the code editable in the runtime, no restart required.

2 Likes

Useful, thanks for sharing that.

Generally, I have little need for shared functions though actually I do have a few standard ones that I really should move. However, they are on my original "live" HA system which I am (really I am!) trying to deprecate over time and move across to the new live system - both run in parallel at the moment (:ahem: and have done for a couple of years now :blush:).

I've now started a new package that will contain my standard libraries - these are bits of code that live in their own module - mainly created out of the uibuilder project but they have started to be useful to other projects as well. It is likely that I will, now you've prompted me, move some standard code from my flows to a library in this package as well so that I can simply include it as a dependency and then require it.

Typically, this is code that doesn't change or at least changes very rarely. So it doesn't bother me that I'd have to restart Node-RED if it changed.

1 Like

That 'module' idea came out of necessity from a time with older NodeJS versions (missing newer language features) and where subflows did not have parameters.

And example would be padStart() for strings, one of the first functions I put into a module, as it wasn't available back then. Also, you weren't able to use features like block-scoped variables (let) or classes outside of strict mode (hence the IIFE block).

Now that subflows are a lot more flexible (and with new features of NodeJS >= 8) my modules are actually shrinking. The rest of my common library stuff is put into NodeJS packages, as you handle it too.

It is still useful for problem-specific functions that are only used in one environment or during prototyping, though.

That is one thing I really admire about Node-RED. You can easily move parts around, try out new stuff, but keep the old things running at the same time. Especially if you have built a distributed system with multiple instances and decoupled your components with some kind of broker like MQTT or WAMP. :nerd_face:

1 Like

Here is how it works for me:

1) Function node called 'Global Functions', with 'On Start' code

var glb_func = {
  my_func : function (param) {
  ...
  return result;
  }
};
global.set("glb_func", glb_func);

2) Function node called 'Init lib' (located on any flow), with 'On Start' code

var glb_func = global.get("glb_func");
var res = glb_func.my_func();

That only works if your default context store is the memory store (default). If you set it to something else, it probably wouldn't work since not all stores allow functions.

The most reliable way is to us the globals section of settings.js.