# How do Node-RED plugins work?

**URL:** <https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890>\
**Category:** Developing Nodes\
**Created:** [6 April 2022 16:38 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890 "2022-04-06T16:38:32Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![tve](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/tve/32/59475_2.png) [@tve](https://discourse.nodered.org/u/tve)\
**Post date:** [6 April 2022 16:38 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890/1 "2022-04-06T16:38:32Z")

</div>

Is there any documentation for how to write a Node-RED runtime plugin? E.g.,

```auto
RED.plugins.registerPlugin()

```

Or any examples?  
I'm probably using the wrong search keys....

---

<div class="post-metadata">

**Author:** ![tve](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/tve/32/59475_2.png) [@tve](https://discourse.nodered.org/u/tve)\
**Post date:** [6 April 2022 18:07 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890/2 "2022-04-06T18:07:54Z")

</div>

**Update** : never mind, I was missing an essentially empty flexdash-plugin.html file. Awesome error message...

Why can't plugins have nodes? If I try something like this in package.json:

```auto
  "node-red": {
    "plugins": {
      "flexdash": "flexdash-plugin.js"
    },
    "nodes": {
      "flexdash dashboard": "flexdash-dashboard.js"
    }
  }

```

I get:

```auto
6 Apr 11:06:34 - [error] Failed to start server:
6 Apr 11:06:34 - [error] TypeError: Cannot read properties of undefined (reading 'forEach')
    at Object.addModule (/usr/src/node-red/node_modules/@node-red/registry/lib/registry.js:195:27)
    at /usr/src/node-red/node_modules/@node-red/registry/lib/loader.js:138:34

```

at the point of the error, if I print `set` I get:

```auto
set flexdash dashboard: {
  "file": "/usr/src/node-red/node_modules/@flexdash/node-red-flexdash/flexdash-dashboard.js",
  "module": "@flexdash/node-red-flexdash",
  "name": "flexdash dashboard",
  "version": "0.4.3",
  "local": false
}

```

There's no `.id` nor `.type`...

---

<div class="post-metadata">

**Author:** ![tve](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/tve/32/59475_2.png) [@tve](https://discourse.nodered.org/u/tve)\
**Post date:** [7 April 2022 06:32 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890/3 "2022-04-07T06:32:10Z")

</div>

This error keeps plaguing me:

```auto
6 Apr 23:29:24 - [error] TypeError: Cannot read properties of undefined (reading 'forEach')
    at Object.addModule (/usr/src/node-red/node_modules/@node-red/registry/lib/registry.js:195:27)
    at /usr/src/node-red/node_modules/@node-red/registry/lib/loader.js:138:34

```

It seems there is a race condition between loading the plugins and the nodes of a module. I just restarted NR 3x without making any changes whatsoever. The first 2x I got the error, the 3rd it started up. Not sure how to provide troubleshooting info.

---

<div class="post-metadata">

**Author:** ![hardillb](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hardillb/32/12373_2.png) [@hardillb](https://discourse.nodered.org/u/hardillb)\
**Post date:** [7 April 2022 07:59 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890/4 "2022-04-07T07:59:25Z")

</div>

A detailed description of what you are actually doing would probably help. What is your plugin doing?

---

<div class="post-metadata">

**Author:** ![tve](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/tve/32/59475_2.png) [@tve](https://discourse.nodered.org/u/tve)\
**Post date:** [9 April 2022 04:33 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890/5 "2022-04-09T04:33:57Z")

</div>

I can't produce a simple example to reproduce the problem. However, I did spend some time debugging. Here's what I see:

- if I have a package that has plugins and modules, both are loaded asynchronously at the same time: [node-red/loader.js at master · node-red/node-red · GitHub](https://github.com/node-red/node-red/blob/master/packages/node_modules/@node-red/registry/lib/loader.js#L117-L122)
- then the loader waits for the plugins to be done loading on line 129
- and proceeds to process the nodes of the package on line 138
- that's where things fail randomly because the loading of nodes may or may not be complete, it's awaited further down on line 145

I'm now wondering what a work-around might be (other than moving the plugin portion into a separate module).

For reference, the node-red packages.json section is:

```auto
  "node-red": {
    "version": "^2.0.6",
    "plugins": {
      "flexdash": "flexdash-plugin.js"
    },
    "nodes": {
      "flexdash dashboard": "flexdash-dashboard.js",
      "flexdash container": "flexdash-container.js",
      "flexdash tab": "flexdash-tab.js",
      "flexdash dev server": "flexdash-dev-server.js"
    }
  },

```

---

<div class="post-metadata">

**Author:** ![hardillb](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hardillb/32/12373_2.png) [@hardillb](https://discourse.nodered.org/u/hardillb)\
**Post date:** [9 April 2022 07:58 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890/6 "2022-04-09T07:58:33Z")

</div>

I didn't ask for a test case/example, just an overview of what you are trying to achieve here.

How do the nodes/plugin interact?

From the symptoms you've described, I assume there is some interaction between the too where one expects the other to have finished loading before it tries to do something. If you can describe what that it is then we may be able to offer an alternative or maybe come up with a fix for the core.

Plugins are a relatively new feature, so it is always possible that there will be code paths that have not been exercised enough to shake out all the possible errors. This might be the first tightly coupled set of plugin/nodes.

---

<div class="post-metadata">

**Author:** ![tve](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/tve/32/59475_2.png) [@tve](https://discourse.nodered.org/u/tve)\
**Post date:** [9 April 2022 14:42 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890/7 "2022-04-09T14:42:32Z")

</div>

> [@hardillb](#):
>
> I didn't ask for a test case/example, just an overview of what you are trying to achieve here.

The use-case is the FlexDash dashboard. I have a number of config nodes (grids, panels, tabs, dashboard) and I want a simple way for users to initialize dashboard nodes (similar to UI nodes). For that, I'd like a global so the code reads something like

```auto
<global>.initDashboardNode(this, config)

```

and by creating a plugin this can indeed be done and looks like

```auto
RED.plugins.get('flexdash').initDashboardNode(this, config)

```

In initDashboardNode I can then work out which dashboard config node this belongs to based on the config (unlike the UI dashboard, FlexDash supports multiple dashboards).

> [@hardillb](#):
>
> From the symptoms you've described, I assume there is some interaction between the too where one expects the other to have finished loading before it tries to do something. If you can describe what that it is then we may be able to offer an alternative or maybe come up with a fix for the core.

❓ I described the bug in detail in my previous message. All that happens _before_ any of my code executes. It's all in the loader when it's just reading files and concocting some metadata about them, it's not executing any of them.

---

<div class="post-metadata">

**Author:** ![hardillb](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hardillb/32/12373_2.png) [@hardillb](https://discourse.nodered.org/u/hardillb)\
**Post date:** [10 April 2022 11:09 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890/8 "2022-04-10T11:09:07Z")

</div>

Just calling `require` on the `.js` runs code (which is happening here), and it's not uncommon for nodes/plugins to do some initialisation upfront before the `module.exports` of the Node-RED initialisation function for nodes/plugins (and will become relevant a little later on).

But anyway, I have managed to write a simple test case with a basically empty plugin and node bundled together in the same `package.json` that triggers the error, your earlier analysis of a race condition looks to be correct. It is an intermittent failure but I think I can force the window wider, so it fails more often making it easier to test potential fixes, in a number of ways

1. Having more nodes in the `node-red.nodes` section of the `package.json`, Just repeating the node with id changes so it doesn't clash with it's self
2. Having the loading of any given `node` in the `node-red.node` section take longer, adding a bunch of extra `require` statements at the beginning of the a node's `.js` file should force the initial load to take longer.

Now we have a test case we can open an issue ([Race condition when loading module with both Plugin and Nodes · Issue #3523 · node-red/node-red · GitHub](https://github.com/node-red/node-red/issues/3523)) to try and get this fixed.

But as I mentioned earlier it appears you are the first person to try and bundle a plugin and a set of nodes in a single package.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [10 April 2022 11:15 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890/9 "2022-04-10T11:15:22Z")

</div>

Hi Ben, do you have a rough idea of where the problem lies? I can (try to) pick this up next week but won't if you are going to work on it.

---

<div class="post-metadata">

**Author:** ![tve](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/tve/32/59475_2.png) [@tve](https://discourse.nodered.org/u/tve)\
**Post date:** [10 April 2022 15:12 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890/10 "2022-04-10T15:12:04Z")

</div>

> [@hardillb](#):
>
> Just calling `require` on the `.js` runs code (which is happening here),

As far as I can tell, the relevant requires are in loadPlugin and loadModule, which are called from loadNodeSetList, which is called after the bug happens.

> [@hardillb](#):
>
> Having more nodes in the `node-red.nodes` section of the `package.json` , Just repeating the node with id changes so it doesn't clash with it's self

Yup, that should do it.

> [@hardillb](#):
>
> But as I mentioned earlier it appears you are the first person to try and bundle a plugin and a set of nodes in a single package.

That's very surprising given the ample documentation about plugins! /end-sarcasm 😉

---

<div class="post-metadata">

**Author:** ![tve](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/tve/32/59475_2.png) [@tve](https://discourse.nodered.org/u/tve)\
**Post date:** [10 April 2022 16:18 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890/11 "2022-04-10T16:18:37Z")

</div>

> [@Steve-Mcl](#):
>
> Hi Ben, do you have a rough idea of where the problem lies?

I can't speak for Ben, but I thought my description made it pretty obvious. You can't call addModule [node-red/packages/node\_modules/@node-red/registry/lib/loader.js at master · node-red/node-red · GitHub](https://github.com/node-red/node-red/blob/master/packages/node_modules/@node-red/registry/lib/loader.js#L138) before awaiting the promise [node-red/packages/node\_modules/@node-red/registry/lib/loader.js at master · node-red/node-red · GitHub](https://github.com/node-red/node-red/blob/master/packages/node_modules/@node-red/registry/lib/loader.js#L145) that signals that the data needed by addModule is available.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [9 June 2022 16:19 UTC](https://discourse.nodered.org/t/how-do-node-red-plugins-work/60890/12 "2022-06-09T16:19:12Z")

</div>

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.
