Reputation: 59501
I am working on a script that runs during our build process in Jenkins right before npm install
. My issue is that I need to download a JavaScript file from an external resource and read a variable from it.
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';
}
});
I know that "eval
is evil", but any suggested alternatives I've found online don't seem to work.
I have tried different variations of new Function(obj)()
, but Node seems to exit the script after (the if
-case never runs).
Ideas?
Upvotes: 2
Views: 6455
Reputation: 59501
This answer is heavily based on @georg's comments, but since it helped me I'll provide it as an alternative answer.
Explanation in the comments.
let content = fs.readFileSync(`${outputDir}/js/en.js`, 'utf8');
content += '; module.exports=obj'; // Export "obj" variable
fs.writeFileSync(`${outputDir}/temp`, content); // Create a temporary file
const obj = require(`${outputDir}/temp`); // Import the variable from the temporary file
fs.unlinkSync(`${outputDir}/temp`); // Remove the temporary file
Upvotes: 1
Reputation: 214949
Since node.js provides the API to talk to the V8 runner directly, it might be a good idea to use it. Basically, it's the API used by node's require
under the hood.
Assuming the js file in question contains the variable obj
we're interested in, we do the following:
; obj
to the code to make sure it's the last expression it evaluatesobj
): const fs = require('fs'),
vm = require('vm');
const code = fs.readFileSync('path-to-js-file', 'utf8');
const obj = vm.runInNewContext(code + ';obj');
Upvotes: 5