I have a Node-RED flow where several function nodes contain more than 100 lines of JavaScript code each. Managing and writing unit tests for such large code blocks has become increasingly difficult.
I’m looking for a way to modularize or separate the function node code .
Store the JavaScript code in external files for better maintainability.
Reuse the same code across multiple function nodes wherever required.
Easily write and run unit tests for the extracted code.
"I have created a custom lower-case node to check if it's possible to create a separate node for each functionality instead of using function nodes and linking them together. Is this approach feasible in Node-RED?".
I have more than 100 lines of code inside a Function Node and want to handle that logic outside of the node for unit testing or modularity, i can move the logic into an external JavaScript file (module) or Create a Separate Node for Each Function .
This approach makes it easier to test and maintain.Which approach is better? or any other way?
Both are valid approaches. Depends on how many different custom nodes you'd need to create.
So the first solution might be easier.
You can use the module import of the function node to include your custom code.
Keep in mind that you need to restart Node-RED after making changes for both solutions. You wouldn't need to restart if using the subflow or link-call approach.
Depending on your needs ofcourse; you can create a npm module which doesnt necessarily have to become a node-red node, but it becomes importable for a function node (see the setup tab within a function node).
You could also expose your functions are flow/global context objects and call them when needed.
Personally I like link-call a lot, but as kuema indicated, debugging is more complicated.
Subflows are also an option, but keep in mind that each subflow node becomes an instance (ie, not efficient).
A module is certainly the way to go for this. Alternatively, you can create a plugin instead of a full node. In that case, you could even attach your code to the RED object that gets exposed to function nodes.
IMHO, don't even think about subflows (they introduce many issues). What I do to modularize my code is pack my parameters in the msg and use link calls to call other function nodes as if they were procedures in my code. Note however that calling an external node is an async operation, so beware of race conditions.
I'm just referring to other function nodes, i.e. I extract reusable pieces of code from my function node into independent standalone function nodes, serving as general-purpose modules which I can call from multiple places with call-links.
As functions in stored in global context , when called without async/await (or promise or callback) they will be synchronous.
Functions called by link-call will be async in relation to other flow nodes (but for all intents and purposes when in a single (in series) flow) they will appear to be synchronous from first node input to last node output.
In other words, splitting functions out to reusable subroutines that are graphically called via link-call is in line with the asynchronous advantages of node js and the visual aspect of flow based programming.