diff --git a/packages/node_modules/@node-red/registry/lib/loader.js b/packages/node_modules/@node-red/registry/lib/loader.js index 27783be7f..929962134 100644 --- a/packages/node_modules/@node-red/registry/lib/loader.js +++ b/packages/node_modules/@node-red/registry/lib/loader.js @@ -350,30 +350,19 @@ function loadNodeSet(node) { } else { } try { - var loadPromise = null; - var r = require(node.file); - r = r.__esModule ? r.default : r - if (typeof r === "function") { - - var red = registryUtil.createNodeApi(node); - var promise = r(red); - if (promise != null && typeof promise.then === "function") { - loadPromise = promise.then(function() { - node.enabled = true; - node.loaded = true; - return node; - }).catch(function(err) { - node.err = err; - return node; - }); - } - } - if (loadPromise == null) { - node.enabled = true; - node.loaded = true; - loadPromise = Promise.resolve(node); - } - return loadPromise; + let importPromise = import(node.file); + return importPromise + .then(function(moduleNamespaceObject) { + // CJS will always have default, ESM might have default. (details in note below) + let r = moduleNamespaceObject.default ? moduleNamespaceObject.default : moduleNamespaceObject; + // Babel related workaround. (references in note below) + r = r.__esModule ? r.default : r; + return createLoadPromise(node, r); + }) + .catch(function(err) { + node.err = err; + return Promise.resolve(node); + }); } catch(err) { node.err = err; var stack = err.stack; @@ -397,6 +386,45 @@ function loadNodeSet(node) { } return Promise.resolve(node); } + + // Notes on default: + // https://nodejs.org/api/esm.html#import-expressions + // "When importing CommonJS modules, the module.exports object is provided as the default export." + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import + // "The module namespace object is a sealed object ... with the default export available as a key called `default`." + + // Notes on __esModule: + // Workaround originally added in commit 326f3469, merged in pull request #3669. + // Related links: + // https://github.com/nodejs/node/issues/40891 + // https://github.com/evanw/esbuild/issues/1591 + // https://babeljs.io/docs/babel-plugin-transform-modules-commonjs + // https://stackoverflow.com/questions/50943704/whats-the-purpose-of-object-definepropertyexports-esmodule-value-0 + + function createLoadPromise(node, r) { + var loadPromise = null; + if (typeof r === "function") { + + var red = registryUtil.createNodeApi(node); + var promise = r(red); + if (promise != null && typeof promise.then === "function") { + loadPromise = promise.then(function () { + node.enabled = true; + node.loaded = true; + return node; + }).catch(function (err) { + node.err = err; + return node; + }); + } + } + if (loadPromise == null) { + node.enabled = true; + node.loaded = true; + loadPromise = Promise.resolve(node); + } + return loadPromise; + } } async function loadPlugin(plugin) { diff --git a/test/unit/@node-red/registry/lib/loader_spec.js b/test/unit/@node-red/registry/lib/loader_spec.js index b9da833c8..aec957b56 100644 --- a/test/unit/@node-red/registry/lib/loader_spec.js +++ b/test/unit/@node-red/registry/lib/loader_spec.js @@ -626,7 +626,7 @@ describe("red/nodes/registry/loader",function() { node.enabled.should.be.true(); nodes.registerType.called.should.be.false(); node.should.have.property('err'); - node.err.toString().should.eql("Error: fail to require (line:1)"); + node.err.toString().should.eql("Error: fail to require"); done(); }).catch(function(err) {