Require libraries in a custom node

Hello there,
I'm trying to set up a bunch of custom nodes that combine p5 library and Mathjs.
Inspired by the nice contrib-example-lower-case https://nodered.org/docs/creating-nodes/first-node I create the building blocks of my node (html, json and js).
I then install with the npm install --verbose D:\mydevfolder from the console pointing to the folder where I keep my new node.

In order to import p5 and mathjs I placed them into the same local folder and used 'require' statements in the javascript.
Similar to what other contrib-libraries' nodes do:


Here is my .js code:

module.exports = function (RED) {
    'use strict';
	const mathjs = require('./mathjs/dist/math');
	const p5 = require('./p5');
	
	
    function p5SynthNode(config) {
        RED.nodes.createNode(this,config);
        var node = this;
		//my nice functions go here
        node.on('input', function(msg) {			
        node.send(msg);
        });
    }
    RED.nodes.registerType("p5synth",p5SynthNode);
}

This is the html:

<script type="text/javascript">
    RED.nodes.registerType('p5synth',{
        category: 'input',
        color: '#AAAA66',
        defaults: {
            name: {value:""}
        },
        inputs:1,
        outputs:1,
        icon: "feed.png",
        label: function() {
            return this.name||"p5Synth";
        }
    });
</script>

<script type="text/x-red" data-template-name="p5synth">
    <div class="form-row">
        <label for="node-input-name"><i class="icon-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Name">
    </div>
</script>

<script type="text/x-red" data-help-name="p5synth">
    <p>A simple node that runs a synth p5</p>
</script>

The problem is that the node does not appear in the palette.
Commenting out the p5 require line solves the problem (local mathjs is correctly imported).
What is the correct way to require libraries when setting up a custom node?

Any help will be appreciated.
Cheers,

The proper way is to include a package.json file in your node that makes it a proper module. In that file you can declare what npm modules your node depends on so that when you run the npm install command, npm will take care of installing those dependencies in the right place.

Then, in your code, you don't use relative paths in your require statements - you use require('p5') and require('mathjs/dist/math').

Thank you very much knolleary.
I figured out that p5 was raising issues due to window reference (usually available when running as usual via an html). I have it commented out, since I need to circumvent this.

The dependency workflow logic you explain makes sense. I do have a package.json. I did not include any dependencies though.
I'm now trying it for mathjs, with the following text:

{
  "name": "p5synth",
  "version": "1.0.0",
  "description": "example syn p5",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "mplux",
  "license": "ISC",
  "node-red" : {
        "nodes": {
            "p5ynth": "p5synth.js"
        }
   },
	"dependencies": {
    "mathjs": "^3.20.2"
  }
}

Unfortunately, when the package is reinstalled and Node-RED relaunched, it doesn't pick up the path.

const mathjs = require('mathjs/dist/math');

Perhaps it is not intended at local development. I'm not sure, but I'll have to dig deeper.
myExample =>


Many thanks.

This is not the correct process for consuming Node.js libraries.

You should install them using npm:

npm install mathjs

Then, as Nick says, you can simply do

const mathjs = require('mathjs')

// or, to use a single function

const { sqrt } = require('mathjs')
console.log(sqrt(-4).toString()) // 2i

These things are shown in the documentation and this isn't really a Node-RED issue.


P5, on the otherhand is a JavaScript version of the Processing language. It is front-end code as it expects and needs a browser as an output medium. I very much doubt it will work in Node.js server environments.

To use it with Node-RED, you need to build a web-page and include the library that way. Node-RED has several methods to do this ranging from the http-in/-out nodes, Dashboard with the Dashboard Template node, or contributed nodes such as my own uibuilder (which would make an excellent platform for working with P5 and Node-RED).

And, to have them immediately end up in that package.json file, use

npm install --save mathjs

That will add mathjs to the dependencies. If instead it is needed as dependency during development only, use npm install --save-dev mathjs instead

Since npm 5.x, the default behaviour is to update the package.json file (if it exists) with or without the flag.

Thank you. I don't consume Node.js libraries that way. I'm sorry that is what it looked like.
I was just trying to circumvent the require statement problem mentioned with relative paths, as the global require does not manage to find the libraries.
The npm install changing the package.json is the way to go.

As per p5, my idea of using it came after noticing its npm https://www.npmjs.com/package/p5
However, I'll need to tests approaches like the http-out and uibuilder you mention.
Thanks

Many thanks to everyone.

So, as indicated by knolleary, package.json is updated also when no flag is given.
I managed to install (within my custom node folder) and use mathjs, no local path :+1:
It modified the package.json and created a local folder with the lib contents.

I'm still puzzled to see that when installing node-red packages like https://www.npmjs.com/package/node-red-contrib-music
no node_modules folder as the one I recently got through npm appears.
The https://github.com/stevenaeola/node-red-contrib-music/blob/master/beat.js I referenced is part of it. I'm trying to understand its behavior. An I think this makes this topic a Node-RED topic.

As regards p5, I'll have to try the suggested approaches.
Thanks

This is really an npm topic :wink: however, it doubtless confuses many people.

You need to understand a little more about how npm works. For more recent versions of npm, it attempts to keep the packages as "flat" as possible. What used to happen is that each package got its own node_modules folder with its dependencies installed. However, as this can add 10's to 100's of thousands of files, it quickly gets unmanagebly large. So now, it tries to keep everything to a single node_modules folder except where there are clashing version requirements.

Here are a couple of links that help you understand:


And from one of my own helper libraries. Here I have a need to manually find where a package is installed (if it is). If have to jump through hoops because this code is, itself buried in a module that is buried several layers deep in Node-RED. So the standard resolve method in the link above doesn't always work. The JSDoc for that function gives a little more explanation.

https://github.com/TotallyInformation/node-red-contrib-uibuilder/blob/95a3e817f098a35b9b634d7fc4fe1e017139d9cc/nodes\tilib.js#L133-L133

1 Like

Was curious to see this (may have borrowed it) but I get a 404 for that link.

Oops, copied from VSCode but it seems to have given me an invalid link.

Here is the correct link (hopefully), sorry about that.