# Where to define class to use in multiple nodes

**URL:** https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808
**Category:** Developing Nodes
**Created:** [23 September 2019 12:35 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808 "2019-09-23T12:35:29Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![undef](https://avatars.discourse-cdn.com/v4/letter/u/7feea3/32.png) [@undef](https://discourse.nodered.org/u/undef)
#### Post date: [23 September 2019 12:35 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808/1 "2019-09-23T12:35:30Z")

</div>

Hi,

I'm using node-red for some time now and just started to create custom nodes.  
Because of good documentation I was able to get pretty far up till now.  
I created 3 custom nodes so far. These are passing json objects.  
To create these objects I use multiple classes. This works fine as long as the class definition is inside the .js file.  
But I whould like to use these class definitions in multiple nodes. Copying them to the single file seems to be worst idea 😉  
So is there any clever way to do a class definition so multiple nodes are able to use the classes? I was thinking maybe in the global context. but I didn't find anythink usefull on the web.

help appreciated  
Chris

---

<div class="post-metadata">

### Author: ![kuema](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kuema/32/6542_2.png) [@kuema](https://discourse.nodered.org/u/kuema)
#### Post date: [23 September 2019 12:58 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808/2 "2019-09-23T12:58:55Z")

</div>

Just use "plain old" [NodeJS modules](https://nodejs.org/dist/latest-v10.x/docs/api/modules.html).

Put all your classes into one .js file (or one file per class, if you want) and export them. Then use the `require()` function to import them in your nodes.

---

<div class="post-metadata">

### Author: ![afelix](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/afelix/32/9743_2.png) [@afelix](https://discourse.nodered.org/u/afelix)
#### Post date: [23 September 2019 13:35 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808/3 "2019-09-23T13:35:49Z")

</div>

_(moved to the creating nodes category)_  
Thanks Matthias, will definitely use that too 🙂

---

<div class="post-metadata">

### Author: ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)
#### Post date: [23 September 2019 15:46 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808/4 "2019-09-23T15:46:50Z")

</div>

You can see an example in the uibuilder Node. I use two modules there as libraries of code - in my case, mainly to keep each code file to a manageable size but the principle is the same.

If you need to share code across multiple packages (e.g. different entries in npm), you should put the module into its own package and publish that to npm. Then you can make it a dependency in your Node's package.

The `tilib` module in uibuilder is very likely to end up in its own package as I've already used some of it in a second package.

---

<div class="post-metadata">

### Author: ![undef](https://avatars.discourse-cdn.com/v4/letter/u/7feea3/32.png) [@undef](https://discourse.nodered.org/u/undef)
#### Post date: [25 September 2019 10:41 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808/5 "2019-09-25T10:41:45Z")

</div>

Thanks for the advice. This helped me a lot.  
I had some trouble to define multiple classes in one file but I found the solution here:

> <https://stackoverflow.com/questions/41228221/can-you-export-multiple-classes-from-a-single-nodejs-module>

example for documentation:  
class Jack{  
//Member variables, functions, etc  
}  
class John{  
//Member variables, functions, etc  
}  
module.exports = {  
Jack : Jack,  
John : John  
}

access the classes by:

var People = require('./People.js');  
var JackInstance = new People.Jack();  
var JohnInstance = new People.John();

---

<div class="post-metadata">

### Author: ![kuema](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kuema/32/6542_2.png) [@kuema](https://discourse.nodered.org/u/kuema)
#### Post date: [25 September 2019 10:54 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808/6 "2019-09-25T10:54:25Z")

</div>

Thanks for sharing!

One small hint: you don't need to replace the `exports` object (but you _can_, of course)

The following is sufficient and provides better readability:

```auto
module.exports.Jack = Jack;
module.exports.John = John;

```

NOTE: `exports.Jack = Jack;` works too (`module` is not required)

---

<div class="post-metadata">

### Author: ![undef](https://avatars.discourse-cdn.com/v4/letter/u/7feea3/32.png) [@undef](https://discourse.nodered.org/u/undef)
#### Post date: [8 October 2019 19:45 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808/7 "2019-10-08T19:45:28Z")

</div>

after your hints I was able to move my class definition code from a function node to a external file.  
this file (class\_def.js) contains three classes, corresponding constructors and some methods.

I declared this in the node-red settings.js by:  
functionGlobalContext: {  
lodash : require('lodash'),  
class\_def : require('/dataFS/node\_red\_dev/node-red-contrib-deltacon-tradfri/nodes/class\_def.js')  
},  
then I can use it by  
const class\_def = global.get('class\_def');  
So far everything fine, again, thanks to your help 🙂

Now I'm facing two new problems:

1. I used node.warn() and node.error() for debuging purpuses. In the class methods (now located in the external file) the object "node" is no longer known. (as a understand, not in skope)  
Is there any way to use this object in the external defined methods of my class? Or what is the common way of debugging in this scenario?

2. I was using lodash in my function node. This was working fine in my function node after I declared lowdash in settings.js  
But again it's a problem in my external class definition file  
I tried to include it by:  
var \_ = require('lodash')  
var \_ = global.get('lodash')

but none was working. Now I'm at my wit's end.  
How do I have to declare lodash to use it?

---

<div class="post-metadata">

### Author: ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)
#### Post date: [8 October 2019 23:37 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808/8 "2019-10-08T23:37:08Z")

</div>

> [@undef](#):
>
> Is there any way to use this object in the external defined methods of my class? Or what is the common way of debugging in this scenario?

You need to read up on how to use node.js

`console.log` can be used.

> [@undef](#):
>
> var \_ = global.get('lodash')

That is Node-RED, you can't use it in your external code since that runs in a different context and it doesn't know about any of the NR functions like `RED` or `global.get`

`var _ = require('lodash')` should work though. Where have you put your external module file? Do a manual test - comment out most of the code and run the file manually - can it find lodash? If not, then you need to sort that first.

---

<div class="post-metadata">

### Author: ![kuema](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kuema/32/6542_2.png) [@kuema](https://discourse.nodered.org/u/kuema)
#### Post date: [9 October 2019 04:25 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808/9 "2019-10-09T04:25:05Z")

</div>

> `/dataFS/node_red_dev/node-red-contrib-deltacon-tradfri/nodes/class_def.js`

Looking at your filename I see that your module is **not** in your Node-RED workspace (`~/.node-red` or so), where you have probably installed `lodash` as a dependency.

I guessing `node-red-contrib-deltacon-tradfri` is a custom node, so you need to install `lodash` there. Otherwise it cannot be found.

For reference, the NodeJS module loading algorithm is described here: [Modules | Node.js v10.24.1 Documentation](https://nodejs.org/dist/latest-v10.x/docs/api/modules.html#modules_all_together)

---

<div class="post-metadata">

### Author: ![undef](https://avatars.discourse-cdn.com/v4/letter/u/7feea3/32.png) [@undef](https://discourse.nodered.org/u/undef)
#### Post date: [10 October 2019 21:47 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808/10 "2019-10-10T21:47:04Z")

</div>

@kuema, you are right.  
the module was not located in the user dir of node-red (specified by -u on startup)  
I was following the howto "create your first node" from[node-red docs](https://nodered.org/docs/creating-nodes/first-node#testing-your-node-in-node-red)  
so I used npm install

But it's not working this way.  
This method creates a symbolic link in ./node\_modules but this seams not to be enough.  
Declaring my file in settings.js by:

```auto
functionGlobalContext: {
		lodash : require('lodash'),
		class_def	: require('./node_modules/node-red-contrib-deltacon-tradfri/nodes/class_def.js')
    },

```

Is not working with symlink.  
But when I move the module folder to nodes\_modules (and substituting the syslink by the orginal folder) its fine.  
In node-reds function node I can use the global class definitions with

```auto
const class_def = global.get('class_def');
scene0 = new class_def.Scene(); 

```

in module files I declare by

```auto
const class_def = require('./class_def.js');

```

@TotallyInformation I did some reading. Thanks for the hint.  
What I still not completely understand are the loglevels.  
Acording to node.js docs I'm able to set different levels from debug to error.  
But were do I set the level? I guess the node-red setting from settings.js doesn't apply.

---

<div class="post-metadata">

### Author: ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)
#### Post date: [10 October 2019 22:48 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808/11 "2019-10-10T22:48:59Z")

</div>

> [@undef](#):
>
> Acording to node.js docs I'm able to set different levels from debug to error.  
> But were do I set the level? I guess the node-red setting from settings.js doesn't apply.

You set the level of visible logging in settings.js.

To output your own messages, you use `console.xxxx` or, if you have access to the `RED` object, you can use Node-RED's logging. If you are using an external module, you won't have access to `RED` unless you pass it to your module function/class instance.

Really, you should take some time out and create a node.js app from scratch so that you get the basics of how node.js and its module system works first. Then it should click into place. Remember that Node-RED is the node.js app that you are running and _it_ is then loading your code. So when used within NR, you are several layers deep into the app. If you don't understand the basics of the node.js module system, you will likely continue to struggle. It doesn't take long to learn, just choose a tutorial about it and work through that.

> [@undef](#):
>
> But it's not working this way.

You are over complicating things by trying to use a package as well as a module. Put your code file in your userDir for now, it will be much simpler. Later on, when you have the basics working and you understand how modules work, you can choose to move it into its own package.

When you `npm install`, you are installing a package. That is separate to a module and you don't need a package to use a module.

---

<div class="post-metadata">

### Author: ![dekatWin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dekatwin/32/67655_2.png) [@dekatWin](https://discourse.nodered.org/u/dekatWin)
#### Post date: [11 September 2022 21:46 UTC](https://discourse.nodered.org/t/where-to-define-class-to-use-in-multiple-nodes/15808/12 "2022-09-11T21:46:30Z")

</div>

There is a much easier way.

3 Simple steps:

1. put the class into an object
2. put the object into a global variable
3. call the object via the global variable

Since I use Iobroker and the NodeRed adapter on it, direct access to node.red and the files is very complicated, so I simply packed the classes into a new object "Import" and then made that accessible in a single function block via the initialization as global variabel.

that's how I solved the problem.

1. Create the class in the "import" object and then pass that as a global variable to Node.Red.

```auto
const Import = {
    CreateDB: class CreateDB {
        /**
    * @param {string} dbName
    * @param {number} [outputCount]
    */
        constructor(dbName, outputCount) {
            this.dbName = dbName;
            this.outputCount = outputCount;
            //Objekte innerhalb des Objekt erstellen
            this.extern;
            this.intern;
            //Multi Output erstellen
            this.output = [outputCount];
            for (let i = 0; i < outputCount; i++) {
                this.output[i] = {};
            }
            //Kontrolle ob schon Einträge vorhanden sind
            if (context.get("dbInt" + this.dbName) === undefined) {
                this.intern = {};
            }
            else {
                this.intern = context.get("dbInt" + this.dbName);
            }
            if (global.get("dbExt" + this.dbName) === undefined) {
                this.extern = {};
            }
            else {
                this.extern = global.get("dbExt" + this.dbName);
            }
        }
        SaveDBintern() {
            context.set("dbInt" + this.dbName, this.intern);
        }
        SaveDBextern() {
            global.set("dbExt" + this.dbName, this.extern);
        }
        LoadDBintern() {
            let obj = context.get("dbInt" + this.dbName);
            return obj;
        }
        LoadDBextern() {
            let obj = global.get("dbExt" + this.dbName);
            return obj;
        }
        ResetDB() {
            this.extern = {};
            this.intern = {};
            global.set("dbExt" + this.dbName, this.extern);
            context.set("dbInt" + this.dbName, this.intern);
        }
        FormatOutput() {
            for (let i = 0; i < this.outputCount; i++) {
                if (this.output[i].hasOwnProperty("payload") || this.output[i].hasOwnProperty("topic")) {
                    if (this.output[i].payload === undefined || this.output[i].payload === null) {
                        this.output[i] = null;
                    }
                }
                else {
                    this.output[i] = null;
                }
            }
        }
    }
}

//Objekt als Globale Variabel anlegen
global.set("Import",Import);

```

1. Call the import object inside any function block you want and use the class to create your own objects as often as you want.

```auto
//Importieren der Klasse über ein Objekt
const Import = global.get("Import");
//Erstellen des neuen Objekts über eine Klasse aus Import
let TestDB = new Import.CreateDB("test",3);

//Anwendung Beispiel

//TestDB.extern.essen = "Bifi";
//TestDB.SaveDBextern();

TestDB.ResetDB();
node.warn("--> "+TestDB.LoadDBextern().essen);

TestDB.output[0].payload = "lecker";
TestDB.output[0].topic = "Kekse";
TestDB.output[2].payload = "hunger";
TestDB.output[2].topic = null;

TestDB.FormatOutput();
node.done();
return(TestDB.output);

```

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/7/7/77ae5850401fe7f07e70a4dbf7729cb110e5d718.png)  
This is how it should look in the function block that is not actively used, it is important that you put the code in the initialization so that it is run again every time you start node.red.  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/c/4/c408b2e666c4119063713ddf48b9d16ba16d7c5f.png)

I know this is not a nice solution but it works for me, you can still use the node.warn debug output inside the class and always quickly adjust the classes if you want to extend something.

Ironically, my example class is a class that manages Global, Context and Temporary objects. So most of the code is not needed, it's just an example of what it could look like in action.
