FlowFuse / FlowFuse/node-red-dashboard
External Components: Exporting multiple widgets in UMD format seems to be broken
- 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