首页 > 解决方案 > 替代节点脚本中的 eval()

问题描述

我正在编写一个脚本,该脚本在我们之前在 Jenkins 的构建过程中运行npm install。我的问题是我需要从外部资源下载一个 JavaScript 文件并从中读取一个变量。

unzipper.on('extract', () => { 
  const content = fs.readFileSync(`${outputDir}/js/en.js`, 'utf8');
  eval(content); // Less smellier alternative?

  if (obj) {
    const str = JSON.stringify(obj);
    fs.writeFileSync(`${outputDir}/public/data.json`, str);
  } else {
    throw 'Variable `obj` not found';
  }
});

我知道eval是邪恶的”,但我在网上找到的任何建议的替代方案似乎都不起作用。我尝试了不同的变体new Function(obj)(),但 Node 似乎在之后退出脚本(if-case 永远不会运行)。

想法?

标签: javascriptnode.js

解决方案


由于 node.js 提供了直接与 V8 运行器对话的API,因此使用它可能是一个好主意。基本上,它是节点底层使用的 API require

假设有问题的 js 文件包含我们感兴趣的变量obj,我们执行以下操作:

  • 从文件中读取代码
  • 附加; obj到代码以确保它是它评估的最后一个表达式
  • 将代码传递给 V8 进行评估
  • 获取返回值(这是我们的obj):
    const fs = require('fs'),
        vm = require('vm');

    const code = fs.readFileSync('path-to-js-file', 'utf8');
    const obj = vm.runInNewContext(code + ';obj');

推荐阅读