FlowFuse / FlowFuse/node-red-dashboard

External Components: Exporting multiple widgets in UMD format seems to be broken

Open
#1,926 0 comments 0 reactions 0 assignees View on GitHub
needs-triage type:bug
Dominant language
HTML
Stars
355
Forks
82
Avg merge
4d 20h
Merged PRs (30d)
24

Description

### Current Behavior

It seems that currently, we can only export one Widget in a third party component.

### Expected Behavior

We should be able to have two. Or three. Maybe even more?

### Steps To Reproduce

### package.json
```json
{
"name": "@flowfuse/node-red-dashboard-2-my-fancy-component",
... lines omitted ...
"node-red-dashboard-2": {
"version": "1.0.0",
"widgets": {
"first-widget": {
"output": "my-widget-library.umd.js",
"component": "Hans"
},
"second-widget" {
"output": "my-widget-library.umd.js",
"component": "Peter"
}
}
}
}
```

The problem seems to be that when `my-widget-library.umd.js` is loaded, it is expected that the UMD module registers itself under
- `window['first-widget']['FirstComponent']` and
- `window['second-widget']['SecondComponent']`,
respectively.

However, when using the [vite.config.mjs from the example project](https://github.com/FlowFuse/node-red-dashboard-2-ui-example/blob/3c81dd7e1cd2ef9ea148dc989158ac6dbc290eed/vite.config.mjs#L10), the module registers itself under the name denoted by:
`const LIBRARY_NAME = 'my-widget-library`

So with above config, the correct place to look for the widgets would be:
- `window['my-widget-library']['FirstComponent']`
- `window['my-widget-library']['SecondComponent']`

This could be fixed by adding a new configuration option (`package-name`?) to package.json:

```json
"node-red-dashboard-2": {
"version": "1.0.0",
"package-name": "my-widget-library",
"widgets": {
... lines omitted ...
```

The following fix works on my machine™:

```diff
diff --git i/nodes/utils/index.js w/nodes/utils/index.js
index f12865c7..d3058220 100644
--- i/nodes/utils/index.js
+++ w/nodes/utils/index.js
@@ -91,9 +91,11 @@ function getThirdPartyWidgets (directory) {
const getWidgets = (packageJson) => {
if (packageJson?.['node-red-dashboard-2']) {
// loop over object of widgets & add to contribs object
+ const packageName = packageJson['node-red-dashboard-2']['package-name'];
Object.entries(packageJson['node-red-dashboard-2'].widgets).forEach(([widgetName, widgetConfig]) => {
contribs[widgetName] = {
package: packageJson.name,
+ packageName: packageName || widgetName,
name: widgetName,
src: widgetConfig.output,
path: path.resolve(directory),
diff --git i/ui/src/App.vue w/ui/src/App.vue
index d73d79fe..8b42b5cb 100644
--- i/ui/src/App.vue
+++ w/ui/src/App.vue
@@ -265,7 +265,7 @@ export default {
} else if (widget.src) {
// Third Party Widgets
const resource = `${widget.src.package}/${widget.src.src}`
- widget.component = markRaw(importExternalComponent(resource, widget.src.name, widget.src.component))
+ widget.component = markRaw(importExternalComponent(resource, widget.src.packageName, widget.src.component))
} else {
// Old Third Party Widgets - of which there shouldn't be any in the wild
console.warn('No Vue component found for ', widget.type, ' - falling back to ui-template')
```

When `package-name` is not given, this will fall back to the old behavior by using the `widgetName`.

My apologies if I got this wrong or if this has already been reported / discussed. Otherwise, I'm happy to create a PR for this.

### Environment

_No response_

### Have you provided an initial effort estimate for this issue?

No

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in nodes/utils/index.js at getThirdPartyWidgets and then inspect the third-party component loading path in ui/src/App.vue. Compare the package.json widget configuration with the UMD library name, and verify that multiple widgets from one UMD output load under the configured package name while the existing fallback still works.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
full-stack
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.