Library and node in one package

Hello,
I am currently trying to create a Node. To make it easier to work with the resulting data, I wanted to add a NodeJs library to the node. This library should be able to be included in the function node via setup, for example.
But the library is not found by the Node-RED. I always get this message:

Installation of module TestLib.js failed: module not found
Failed to load external modules required by this flow: 
- TestLib.js [404]

In the package.json of the node I specified the library under the entry "main":

{
   ...
   "main": "TestLib.js",
   }, "node-red": {
      ...
   },
   ...
}

The library currently contains only one test function with the following content:

TestLib.js:

function add(){
    console.log("Hello World");
}
module.exports = add()

Is it at all possible to place a library and a node in the same package? If it is possible, what do I have to do to use the library in the function node?

Are you trying to create a contributed node or are you trying to use a function node? I suspect that you are trying to use a function node? If so, you question should be under "General" not "Creating Nodes".

Because you are trying to reference a JavaScript file. To use the function node's module loader, you need to specify a package published on npm.

To use a single file, you should require it to the globals section of your settings.js and then you can global.get it in your function node.

I think the question is fairly clear. They are creating a node and want that module to also provide a library that could be accessed in the function node.

@NetHans what are you putting in the setup tab of the Function node? It should be the name of your module - this error suggests you have entered TestLib.js - the name of the individual file, not the module

I would like to create both. A node and a library. I want to be able to use the library in the function nodes to make it easier to work with the msg data from my node.

I have already tried both ways to register the library in the function node. First I tried to register the library by the name given in the package.json. When that didn't work, I tried it with the filename of the library. From the last try is the excerpt from the log.

My node is located in the directory for nodes, which is defined in settings.js under the property nodesDir

{
   "name": "node-red-contrib-test-node",
   ...
   "main": "TestLib.js",
   }, "node-red": {
      ...
   },
   ...
}

Try 1:
image

Try 2:
image

What you have done with Try 1 should work. If you didn't get any error messages, in what way did it not work? What code do you have in the function node trying to use the library?

I still get the error message 404.

image

In the function node I have stored the following source code:

nodeRedContribTestNode.add();
return msg;

Is node-red-contrib-test-node already installed in your node-red?

OR

Is node-red-contrib-test-node published to npm?

no the whole package has not been installed via npm install. Also the package is not public.

I only created a folder in the nodesDir and put all my files there. The node is also properly recognized by Node-RED and can be used. Only the library is not accessible.

I don't think the function node setup imports check that folder?

Would you be willing to try an NPM install to your source ?

E.g. remove your copy from nodesDir & do npm i /path/to/your/package

See if that works?

Yes, I think that is currently the only way. I tried the other day to install something from GitHub and it didn't like it. But don't think that it strips it from the function node's setup so you probably need to let the auto-install fail and then install the package manually.

That didn't work either. The node can be used again. But I have no access to the library. The error message is the same.

My package can now be found under the Node-RED main directory under node_modules.

Can you share more info about the project (the package.json, the structure etc)
better still, upload it to github & I'll take a look.

To use a module in the function node, you have to have an default exports in the module. You also need to specify the main entry point (in the package.json file) as the module file that you want loaded. Remember that this may well be different to your node's js file, in fact it should be.

All of which is shown in the original post.

I will reduce the package to a minimum to keep the overview. The functionality of the node is irrelevant, because this part of the package works without problems.

I will make the example available here.

Thanks for the tips, I will take them into consideration.

1 Like

I have published the test node on GitHub.

I used the following example as the test flow.

[
    {
        "id": "79e80abe4ac375cb",
        "type": "node-red-contrib-test-node",
        "z": "e8e2da1a3d5d8ace",
        "name": "",
        "x": 270,
        "y": 240,
        "wires": [
            [
                "f079f7b2046c3bc7"
            ]
        ]
    },
    {
        "id": "46e2301134010486",
        "type": "inject",
        "z": "e8e2da1a3d5d8ace",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 120,
        "y": 240,
        "wires": [
            [
                "79e80abe4ac375cb"
            ]
        ]
    },
    {
        "id": "80ad50bf4395e5b8",
        "type": "debug",
        "z": "e8e2da1a3d5d8ace",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 570,
        "y": 240,
        "wires": []
    },
    {
        "id": "f079f7b2046c3bc7",
        "type": "function",
        "z": "e8e2da1a3d5d8ace",
        "name": "",
        "func": "nodeRedContribTestNode.add()\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [
            {
                "var": "nodeRedContribTestNode",
                "module": "node-red-contrib-test-node"
            }
        ],
        "x": 420,
        "y": 240,
        "wires": [
            [
                "80ad50bf4395e5b8"
            ]
        ]
    }
]

OK, so that tries to deliver both a node-red node AND a function? I suspect that may be the issue.

If you want a node.js function that you can share with the function node, write that as a pure node.js module, not a node-red custom node.

If you need to also use the same function inside your node, use a standard require to reference it.

Don't try to do both in a single file.

The library and the node belong together. A node can be installed very easily via the Node-RED GUI. A non-public library is not so easy to install. In the production system the automatic installation of libraries is disabled (functionExternalModules: false).

My goal is to ship the combination of node and library and provide both with one installation. It should be as simple as possible. Ideally without using the command line on the server.

Sorry, I obviously wasn't clear enough.

You can keep both files in the same PACKAGE which is what npm installs to your userDir folder whether for a custom node installation or for the function node. Node-RED loads the right file using the node-red section of package.json, but the default for the function node should be taken from the main property. So you can fulfill both requirements from a single package.

Though you should bear in mind that I've not actually tested this :slight_smile: . However, that I think should work.

The name you put into the function node must be the full npm name though. So you will likely need to change the "Import As" field to what you expect to use in the function code, otherwise you will end up with a very long name in your code.

@TotallyInformation everything you describe there is exactly what they are doing... but it isn't working.

This needs some proper investigation to figure out why it isn't working.