I wanted to ask about your way of working when using function nodes. I usually code in function nodes, and since they're JavaScript, I use functions inside the function node. The problem I'm facing is that I don't find an easy way to reuse these functions inside the function node. To avoid confusion, I'm going to call them "intraFunctions".
The issues I'm running into:
If I use the function library, I access all the code of the function node, not only the intraFunction code, so this doesn't suit me.
If I copy-paste the intraFunctions, I need to remember which functions they're in, and if I fix a bug, it's almost impossible to update changes across the rest.
I thought about making a private npm intraFunction bundle so I can install it as a module in my functions, but it's too complex for me.
So, from your experience:
How do you work around this?
How would you recommend I handle it?
Is there any way to create a Node-RED intraFunction pack/library at the Node-RED instance level?
There are 2 different function nodes in different flows. Each of them does its own "data processing". The first one checks for active events and returns only the active ones with the TIMESTAMP variable reformatted to my standardized format. The second one updates the TIMESTAMP_eventDOWN to my standardized datetime format.
Both data sources are different, and the use case and output have nothing to do with each other. Data format and variables I want to transform may also be different, but in both cases, the output format of certain variables matches a defined format.
So what I have here is a JS function, copy-pasted in both function nodes, that's called in my data processing program. (function datetImeFormat_mySTD())
What I would like is to easily reuse this "intraFunction" in other function nodes.
I get it that you like/prefer to only use function nodes and put code in them to do what you want.
Not wanting to put words in your mouth, a different way of looking at it.
Your intrafunctions...... Could they be called subflows?
Then rather than putting ALL the code in one function node, split up what you are doing into parts.
Then when you need your infraFunctions, the message leaves one function node, goes through the subflow (your infraFuntion) then goes into another function node.
Then if/when you do any changes, they are rolled out via the subflow method.
You can use link call and link in and out nodes to call one function or flow in many flows.
You can also store functions in the context data.
You can also create functions in your settings.js
So in this case, I've got 2 different function nodes in different flows. Each of them does its own "data processing". The first one checks for active events and returns only the active ones with the TIMESTAMP variable reformatted to my standardized format. The second one updates the TIMESTAMP_eventDOWN to my standardized datetime format.
Both data sources are different, and the use case and output have nothing to do with each other. Data format and variables I want to transform may also be different, but in both cases, the output format of certain variables matches a defined format.
So what I have here is a JS function, copy-pasted in both function nodes, that's called in my data processing program. (function datetImeFormat_mySTD())
What I would like is to easily reuse this "intraFunction" in other function nodes.
And the reason not to make it a subflow is that:
The data input may be different in form
I don't want to crowd my flows with small operations like data conversion. I prefer to have clear readability of the data processing, though I want to reuse some code inside those data processors.
If you add to settings file, you would need to restart node-red after altering your function.js file. I believe auto complete would not be recognised (never checked though).
I don't recommend doing it that way myself. If you want a set of accessible functions available to your node-red instance, the best approach is to put the functions in a node.js MODULE. Then require the module onto a suitable global variable in settings.js.
I think I'll go with the context data declaration approach. Not a fan of editing settings.js, especially when Node-RED is running on Docker.
Anyway, I'm open to hearing more suggestions and opinions on this. I'm curious how often other Node-RED programmers run into this same issue.
I might open a feature request to discuss it further. I really think it would be super helpful to have a built-in way to create and manage reusable function templates as a library.
Not that uncommon but I don't think it is common either, at least we don't really see any frequent requests in this forum. Just occasionally.
BTW, you should note that assigning your functions from within Node-RED itself, only works for in-memory context variables. It generally will not work with any other type of context (file for example). That's because Functions are not serializable to JSON. That is why the settings.js approach is preferred.
It is easy enough to have a standard settings.js that attempts to require a module but only issues a warning if it can't be found. That way, you can simply use the same settings.js file for all of your Docker instances.
Sorry, don't think this has been covered and I should also have mentioned it.
There IS already another way to do this. Use a runtime PLUGIN that attaches your functions perhaps to the RED.utils object which is accessible from within functions. While not really recommended by the core devs due to the possibility of a name clash, as long as you are very careful about ensuring a unique name (and maybe provide a warning if the plugin cannot attach the functions due to a name clash), you should be safe enough. This is the approach I took with UIBUILDER to provide some common functions.
Of course, having a more "official" way to achieve this would be very welcome.
Agree that this will usually work. But noting that such a flow should go in the first tab in Node-RED which I believe gets run first. All other tabs run in added order I think. And anyone "foolish enough"? to not use the memory context store or not to have it as the default, could get caught out.
Using a node.js module and requiring it to a global in settings.js is "the node.js way". It is robust and the functions will always be guaranteed to be present by the time your flows actually start (barring you doing something really funky in the module anyway).
For most people, probably never an issue but in the forum, we like to make sure that people have access to the information to do troubleshooting should they hit an issue.
It was talked about years ago, may not be true any more, not sure. I'm fairly sure it was whatever tab was at the left end. Anyway, I always put my startup tasks on the first tab.
When the flows file is loaded it gets parsed and “executed” in top to bottom of the file order. If you look at a flow file you will typically see it has global configuration nodes first ( not visible on any page) then tab by tab left to right. So yes the first tab usually gets started earliest.
Nick O'Leary confirmed this in a previous post. Initialization is done tab by tab (left to right), and then node-by node by their creation order.
I my production projects, we always reserved the first tab for initialization stuff, and the last tab for actions which rely on their associated nodes being ready, and for setting a global "isReady" global context var