# Problem loading an external module

**URL:** <https://discourse.nodered.org/t/problem-loading-an-external-module/83143>\
**Category:** General\
**Created:** [24 November 2023 06:14 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143 "2023-11-24T06:14:15Z")\
**Posts on this page:** 17\
**Page:** 2

<div class="post-metadata">

**Author:** ![rozek](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/rozek/32/48594_2.png) [@rozek](https://discourse.nodered.org/u/rozek)\
**Post date:** [24 November 2023 22:17 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/21 "2023-11-24T22:17:34Z")

</div>

sigh, but there MUST be a way to load that library - it's just plain JS...nothing fancy

---

<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:** [24 November 2023 22:19 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/22 "2023-11-24T22:19:03Z")

</div>

If it is has no dependencies, copy the code into a function?

---

<div class="post-metadata">

**Author:** ![rozek](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/rozek/32/48594_2.png) [@rozek](https://discourse.nodered.org/u/rozek)\
**Post date:** [24 November 2023 22:19 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/23 "2023-11-24T22:19:41Z")

</div>

well, it's a lot - and I only need a few functions from it

What I _could_ do - just to be able to continue developing - is to put everything in the "Start" section of a separate function node and define a global in there. Because I need functions from that lib in many of my nodes

Would that work in the sandbox?

---

<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:** [24 November 2023 22:23 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/24 "2023-11-24T22:23:11Z")

</div>

There has been some thought/threads about named exports.

Tho I've not looked into it, I am certain it is possible. The function node uses dynamic import so with a little work, specifying destructured imports _should_ be possible to essentially achieve `const { something, somethingElse} = await import('some-lib')` under the hood.

Need to check see if there is an open issue.

---

<div class="post-metadata">

**Author:** ![ralphwetzel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ralphwetzel/32/53713_2.png) [@ralphwetzel](https://discourse.nodered.org/u/ralphwetzel)\
**Post date:** [24 November 2023 22:24 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/25 "2023-11-24T22:24:11Z")

</div>

> [@rozek](#):
>
> I do not know who wants to add a property `noConflict` to any object - it's definitely neither me nor the library...

This **is** from your module, in `rollup.config.js`.

---

<div class="post-metadata">

**Author:** ![rozek](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/rozek/32/48594_2.png) [@rozek](https://discourse.nodered.org/u/rozek)\
**Post date:** [24 November 2023 22:24 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/26 "2023-11-24T22:24:42Z")

</div>

ok, sorry for bothering you, guys.

But I really have to stop here for today - will continue tomorrow!

Good night from Germany!

---

<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:** [24 November 2023 22:25 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/27 "2023-11-24T22:25:16Z")

</div>

> [@rozek](#):
>
> Would that work in the sandbox?

Yes. But my preference is to make it a bit more visual by utilising link-call (visual subroutines) to make it visually re-usable

---

<div class="post-metadata">

**Author:** ![ralphwetzel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ralphwetzel/32/53713_2.png) [@ralphwetzel](https://discourse.nodered.org/u/ralphwetzel)\
**Post date:** [24 November 2023 22:29 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/28 "2023-11-24T22:29:50Z")

</div>

> [@Steve-Mcl](#):
>
> Tho I've not looked into it, I am certain it is possible. The function node uses dynamic import so with a little work, specifying destructured imports _should_ be possible to essentially achieve `const { something, somethingElse} = await import('some-lib')` under the hood.

I'm not sure this is necessary - but anyway.  
As it seems yet, the dynamic import currently only forwards the `default` export - and "fails" if this isn't present. That's a bit too focused - from my perspective. 😉

I'm quite surprised, that none else had commented on this behavior before...

---

<div class="post-metadata">

**Author:** ![rozek](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/rozek/32/48594_2.png) [@rozek](https://discourse.nodered.org/u/rozek)\
**Post date:** [24 November 2023 22:36 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/29 "2023-11-24T22:36:18Z")

</div>

well, I have to admit that this is typical for me: whatever I'll touch will break...sorry!

---

<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:** [24 November 2023 22:38 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/30 "2023-11-24T22:38:46Z")

</div>

> [@ralphwetzel](#):
>
> I'm quite surprised, that none else had commented on this behavior before

I'm pretty sure it has. On the forum.

> [@ralphwetzel](#):
>
> As it seems yet, the dynamic import currently only forwards the `default` export - and "fails" if this isn't present. That's a bit too focused - from my perspective

In the previous iteration of module support, it used CJS so you only got npm style imports. It was changed to use dynamic import, but it depends on the module being nice and returning a default.

What would you suggest? (I have gave it little thought that the off-the-top of my head response above)

---

<div class="post-metadata">

**Author:** ![rozek](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/rozek/32/48594_2.png) [@rozek](https://discourse.nodered.org/u/rozek)\
**Post date:** [24 November 2023 22:40 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/31 "2023-11-24T22:40:43Z")

</div>

I see - but that should be a dragon that's easy to kill...(albeit tomorrow)

Thanks for the hint!

---

<div class="post-metadata">

**Author:** ![ralphwetzel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ralphwetzel/32/53713_2.png) [@ralphwetzel](https://discourse.nodered.org/u/ralphwetzel)\
**Post date:** [24 November 2023 23:08 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/32 "2023-11-24T23:08:44Z")

</div>

Ok! 🎉  
Here's what's happening:

The topic roots in the procedure used by Node-RED to determine the file to be imported for a given module.

> <https://github.com/node-red/node-red/blob/a55554193bac2ee4997948c6a15dd752844cace4/packages/node_modules/%40node-red/registry/lib/externalModules.js#L141-L151>

In `line 147`, the `require` function (returned by `createRequire`) is asked to `resolve(module)` in the given `moduleDir`.  
`require` - obviously - returns the CJS (`require`) file - not the ESM (`import`).

`package.json` states

> <https://github.com/rozek/javascript-interface-library/blob/4b1f78add4edb13f7b0642943308c8c8a7088ec8/package.json#L10-L15>

`require` thus returns `./dist/javascript-interface-library.js`.  
`import("./dist/javascript-interface-library.js")` finally returns the empty namespace object already discovered earlier.

---

<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:** [24 November 2023 23:19 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/33 "2023-11-24T23:19:06Z")

</div>

Yep, just been looking at that - however, that suggests the lib is _supposed_ to support CJS, but has failed to export anything!

Am I missing something obvious?

* * *

EDIT

though i do acknowledge that even if we import the ESM, the fact Node-RED adds `.default` to the Function VM, it would _still_ be `undefined`

---

<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:** [25 November 2023 02:28 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/34 "2023-11-25T02:28:46Z")

</div>

> [@rozek](#):
>
> I can `npm install javascript-interface-library` without any problems.

That means nothing. It fails when you try to use it in a node.js app.

> [@rozek](#):
>
> I do not add it to the `settings.js` file but to the list of modules needed for a function node (`functionExternalModules` is `true` in my `settings.js`)

This is not a node-red issue but the fact that the library isn't working correctly with node.js

> [@rozek](#):
>
> THAT's interesting! So Node-RED requires importable libraries to define a default export!? I never knew that - and it also does not seem to be documented.

The feature for the function node is a convenience. If you need something more complex or different, add the library as a global in settings.js

> [@rozek](#):
>
> By the way: dynamic imports do not work in Node-RED

:sigh: you seem to be making unwarranted assumptions about node-red. If you want more complex requirements than would be sensible and secure to allow in a function node - which uses node.js's virtual environment for security - you need to make use of the settings.js file or wrap the library in your own module so that it can be included. It is not the fault of Node-RED that javascript-interface-library is not using best practice for node.js modules.

---

<div class="post-metadata">

**Author:** ![rozek](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/rozek/32/48594_2.png) [@rozek](https://discourse.nodered.org/u/rozek)\
**Post date:** [25 November 2023 07:05 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/35 "2023-11-25T07:05:37Z")

</div>

Good morning!

After many experiments and 3 hours of hacking I finally copied all code from the old `javascript-interface-library` into a new package called [node-red-javascript-interface-library](https://github.com/rozek/node-red-javascript-interface-library) which could then successfully be added to my function node's package import list.

While "copying" sounds really ugly, it allows me to proceed with my development, at least. I do not know which change finally led to success (I simply built an UMD, an ESM and an IIFE), but it works without touching the original library.

Thanks to all that helped investigating the problem!

Have a nice weekend!

---

<div class="post-metadata">

**Author:** ![ralphwetzel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ralphwetzel/32/53713_2.png) [@ralphwetzel](https://discourse.nodered.org/u/ralphwetzel)\
**Post date:** [25 November 2023 15:17 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/36 "2023-11-25T15:17:34Z")

</div>

**To conclude** this exchange:

The root cause for this problem stems from the fact that the export of symbols from `javascript-interface-library.js` fails. This is something that would needed to be fixed in the library (action @rozek).

Node-RED yet does a pretty good job importing those modules:  
The file to be imported is resolved via `require.resolve`, which returns a `cjs` type _module_ definition.  
When calling `import()` for a `cjs` type _module_, its [`module.exports` object is provided as the default export](https://nodejs.org/api/esm.html#import-statements). Thus it is **correct** (!) to do

```auto
        sandbox[vname] = lib.default;

```

in [`10-function.js, line 318`](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/12).

What's happening now with [node-red-javascript-interface-library](https://github.com/rozek/node-red-javascript-interface-library) and why does it work?  
The procedure is (of course) the same. `require.resolve` resolves to `node-red-javascript-interface-library.umd.js`, `import()`ing this returns a non-empty namespace object with all `module.exports` put into `default` property. 👍  
NB: This confirms (from my perspective) that there's sth ... to be validated ... for `javascript-interface-library.js`!!

**Final remark** : Node-REDs `import` procedure is only of limited use (can't really say it _fails_) for ESM-only modules - as it's returning just the object defined by `export default`. For those modules, an improvement/fix seems to be necessary...

---

<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:** [24 January 2024 15:17 UTC](https://discourse.nodered.org/t/problem-loading-an-external-module/83143/37 "2024-01-24T15:17:58Z")

</div>

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

[Previous page](https://discourse.nodered.org/t/problem-loading-an-external-module/83143.md?page=1)
