1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Add RED.import to support importing ES6 modules

This commit is contained in:
Nick O'Leary 2021-07-14 19:18:39 +01:00
parent 65081767bf
commit 7fd17b4ec0
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
3 changed files with 211 additions and 175 deletions

View File

@ -290,6 +290,7 @@ module.exports = function(RED) {
}; };
sandbox.promisify = util.promisify; sandbox.promisify = util.promisify;
} }
const moduleLoadPromises = [];
if (node.hasOwnProperty("libs")) { if (node.hasOwnProperty("libs")) {
let moduleErrors = false; let moduleErrors = false;
@ -303,25 +304,20 @@ module.exports = function(RED) {
return; return;
} }
sandbox[vname] = null; sandbox[vname] = null;
try {
var spec = module.module; var spec = module.module;
if (spec && (spec !== "")) { if (spec && (spec !== "")) {
var lib = RED.require(module.module); RED.import(module.module).then(lib => {
sandbox[vname] = lib; sandbox[vname] = lib;
} }).catch(err => {
} catch (e) { node.error(RED._("function.error.moduleLoadError",{module:module.spec, error:err.toString()}))
//TODO: NLS error message
node.error(RED._("function.error.moduleLoadError",{module:module.spec, error:e.toString()}))
moduleErrors = true; moduleErrors = true;
throw err;
});
} }
} }
}); });
if (moduleErrors) {
throw new Error(RED._("function.error.externalModuleLoadError"));
} }
} Promise.all(moduleLoadPromises).then(() => {
const RESOLVING = 0; const RESOLVING = 0;
const RESOLVED = 1; const RESOLVED = 1;
const ERROR = 2; const ERROR = 2;
@ -496,6 +492,9 @@ module.exports = function(RED) {
updateErrorInfo(err); updateErrorInfo(err);
node.error(err); node.error(err);
} }
}).catch(err => {
throw new Error(RED._("function.error.externalModuleLoadError"));
});
} }
RED.nodes.registerType("function",FunctionNode, { RED.nodes.registerType("function",FunctionNode, {
dynamicModuleList: "libs", dynamicModuleList: "libs",

View File

@ -48,7 +48,7 @@ async function refreshExternalModules() {
const externalModuleDir = getInstallDir(); const externalModuleDir = getInstallDir();
try { try {
const pkgFile = JSON.parse(await fs.readFile(path.join(externalModuleDir,"package.json"),"utf-8")); const pkgFile = JSON.parse(await fs.readFile(path.join(externalModuleDir,"package.json"),"utf-8"));
knownExternalModules = pkgFile.dependencies; knownExternalModules = pkgFile.dependencies || {};
} catch(err) { } catch(err) {
knownExternalModules = {}; knownExternalModules = {};
} }
@ -101,6 +101,31 @@ function requireModule(module) {
const moduleDir = path.join(externalModuleDir,"node_modules",module); const moduleDir = path.join(externalModuleDir,"node_modules",module);
return require(moduleDir); return require(moduleDir);
} }
function importModule(module) {
if (!registryUtil.checkModuleAllowed( module, null,installAllowList,installDenyList)) {
const e = new Error("Module not allowed");
e.code = "module_not_allowed";
throw e;
}
const parsedModule = parseModuleName(module);
if (BUILTIN_MODULES.indexOf(parsedModule.module) !== -1) {
return import(parsedModule.module);
}
if (!knownExternalModules[parsedModule.module]) {
const e = new Error("Module not allowed");
e.code = "module_not_allowed";
throw e;
}
const externalModuleDir = getInstallDir();
const moduleDir = path.join(externalModuleDir,"node_modules",module);
// Import needs the full path to the module's main .js file
const moduleFile = require.resolve(moduleDir);
return import(moduleFile);
}
function parseModuleName(module) { function parseModuleName(module) {
var match = /((?:@[^/]+\/)?[^/@]+)(?:@([\s\S]+))?/.exec(module); var match = /((?:@[^/]+\/)?[^/@]+)(?:@([\s\S]+))?/.exec(module);
@ -254,5 +279,6 @@ module.exports = {
register: register, register: register,
registerSubflow: registerSubflow, registerSubflow: registerSubflow,
checkFlowDependencies: checkFlowDependencies, checkFlowDependencies: checkFlowDependencies,
require: requireModule require: requireModule,
import: importModule
} }

View File

@ -50,6 +50,16 @@ function requireModule(name) {
return require("./externalModules").require(name); return require("./externalModules").require(name);
} }
} }
function importModule(name) {
var moduleInfo = require("./index").getModuleInfo(name);
if (moduleInfo && moduleInfo.path) {
var relPath = path.relative(__dirname, moduleInfo.path);
return import(relPath);
} else {
// Require it here to avoid the circular dependency
return require("./externalModules").import(name);
}
}
function createNodeApi(node) { function createNodeApi(node) {
var red = { var red = {
@ -61,6 +71,7 @@ function createNodeApi(node) {
util: runtime.util, util: runtime.util,
version: runtime.version, version: runtime.version,
require: requireModule, require: requireModule,
import: importModule,
comms: { comms: {
publish: function(topic,data,retain) { publish: function(topic,data,retain) {
events.emit("comms",{ events.emit("comms",{