【问题标题】:How to use a string as a module name如何使用字符串作为模块名称
【发布时间】:2019-11-21 16:52:31
【问题描述】:

我正在尝试为我的 node.js CLI 应用程序编写一个插件系统。
应用程序应从 .json 文件中获取描述,并从 .js 文件中获取实际功能,所有这些都设置在特定文件夹中。

应用程序在启动时检查此文件夹并需要每个 .json 文件
根据 json 数据,它会加载一个包含 module.exports = {functions }

的 .js 文件

如何在其他时间(在用户输入后,或在 10 秒计时器后)从主文件访问这些函数)?

function fakeuserinput(x, y) {
  console.log(math.divide(x, y));
  })
}
setTimeout(fakeuserinput(10, 2), 10000); 

(第二个问题:有没有比使用 eval() 更好的方法?)

main.js

//commands is an array of all .json files
commands.forEach(function(cmd){ 
  // eval(cmd.module) = require('./plugins/'+cmd.module+'.js'); doesnt work
  require('./plugins/'+cmd.module+'.js');
  console.log(cmd.name+'\n'+cmd.module);
  // console.log(eval(cmd.module).eval(cmd.name)(10, 2));
  console.log(eval(cmd.name)(10, 2));
})

数学.js

module.exports = {
  multiply: function (x, y) {
    return x * y;
  },
  divide: function (x, y) {
    return x / y;
  },
  add: function (numbers) {
    return numbers.reduce(function(a,b){
      return a + b
    }, 0);
  },
  subtract: function (numbers) {
    return numbers.reduce(function(a,b){
      return a - b
    }, 0);
  },
  round: function (x) {
    return Math.round(x);
  },
  squared: function (x) {
    return x * x;
  },
  root: function (x) {
    return Math.sqrt(x);
  }
}

divide.json

{
  "name": "divide",
  "module": "math",
  "commands": [
    [
      "how much is (integer) / (integer)",
      "how much is (integer) divided by (integer)",
      "what is (integer) / (integer)",
      "what is (integer) divided by (integer)",
      "(integer) / (integer)",
      "(integer) divided by (integer)"
    ]
  ],
  "description": "Divide x by y"
}

我可以在不知道函数名称的情况下加载函数,如下所示:
main.js

//commands is an array of all .json files
commands.forEach(function(cmd){ 
  console.log(cmd.name);
  console.log(eval(cmd.name)(10, 2));
})

function divide(x, y) {
  return x / y;
}
function multiply(x, y) {
  return x * y;
}

但是当它在另一个文件的 module.exports 中时,我被困在试图访问该函数。

json 文件的代码 -> 数组

var folder = './plugins/';
fs.readdir(folder, function (err, files) {
  if (err) {
    console.log('Couldn\'t read folder contents: '+err.message);
    return;
  }

  files.forEach(function (file, index) {
    if (file.substr(-5) == '.json') {
      let path = folder+file;
      fs.readFile(path, 'utf8', function (err, data) {
        if (err) {
          console.log('Couldn\'t read JSON file: '+err.message);
        }
        commands.push(JSON.parse(data));
        console.log('Command added: '+file.substr(0, file.length-5));
      });
    }
  });
});

错误信息: ReferenceError: 数学未定义

【问题讨论】:

  • 是的,不使用eval 肯定有更好的方法来做到这一点
  • 在浏览器上,您可以在服务器上使用window[cmd.name]... 获得该功能,也许在global 上?
  • 不,不要使用global。模块的要点是完全避免使用全局命名空间。我目前正在写一个应该更容易使用的答案。
  • 我试过 global[]() 但据我了解,这不适用于 module.exports。在测试它时无法让它工作。
  • 不是 100% 确定这是否是您想要做的,但请查看 npmjs.com/package/require-dir

标签: javascript node.js node-modules


【解决方案1】:

以下是我修改后的代码,适用于我的用例。 将 foreach 替换为 while 循环(foreach 无法停止) 用新的 RegEx() 变量替换了 eval() 希望它也对其他人有所帮助。

const { promisify } = require('util');
const { resolve } = require('path');
const fs = require('fs');
const readdir = promisify(fs.readdir);

function load (path) {
  return require(resolve(process.cwd(), path));
}

function plugincheck (line) {
  return new Promise(resolve => {
    (async function () {
      var pluginfound = false;
      var argumentarray = [];
      const files = await readdir('plugins');
      const plugins = files
        .filter(file => file.endsWith('.json'))
        .map(file => load(`plugins/${file}`));

      var i = 0;
      var amount = plugins.length;
      while (i < amount) {
        var re = new RegExp(plugins[i]['regex'], 'i');
        var result = re.exec(line);
        if (result) {
          pluginfound = true;
          response.conlog('plugincheck', 'found match: '+plugins[i]['module']+'.'+plugins[i]['name'], 'data');

          const plugin = load('plugins/'+plugins[i]['module']+'.js');
          const fn = plugin[plugins[i]['name']];
          let rslt = fn(result);
          resolve(rslt);
        }

        if (result) {
          i = amount;
        } else {
          i++;
        }
      }

      if (pluginfound == false) {
        response.conlog('pluginloader', 'Couldn\'t find matching plugin for command: '+line, 'error');
      }
    })().catch(err => {
      response.conlog('pluginloader', 'Couldn\'t scan plugins: '+err, 'error');
    });
  })
}

setTimeout(simulate_user_input, 4000); 
function simulate_user_input () {
  plugincheck('root of 10')
}

setTimeout(simulate_user_input_two, 8000); 
function simulate_user_input_two () {
  plugincheck('10 + 2')
}

【讨论】:

    猜你喜欢
    • 2010-09-05
    • 2011-07-13
    • 2019-05-04
    • 1970-01-01
    • 1970-01-01
    • 2019-04-22
    • 2015-09-17
    • 2019-08-20
    • 2021-01-25
    相关资源
    最近更新 更多