Continue on CLI after executing file - node.js

Is there anyway to make Nodejs continue to receive input like a general CLI when we called.
$ nodejs
For example: I have an index.js file below
// index.js
var a = 10
goToCLI()
What I expect is when I call $ nodejs ./index.js it will appear a nodejs cli with a variable already declared. Is it possible? If it is, how?

Start the Node.js REPL without your script first. Then, inside the REPL you may load your script.
$ node
> .load index.js
// index.js
var a = 10
undefined
> a
10
>
Alternatively, you can start up a REPLserver inside your script, along the lines of what your goToCLI() implied:
const repl = require('repl');
function initializeContext(context) {
// Initialize the REPL environment here.
// This is where your variable setup would go for instance:
context.a = 10;
}
const r = repl.start({ prompt: '> ' });
initializeContext(r.context);
r.on('reset', initializeContext);
Hope that helps!

You can use the REPL module. It will include any global variables in the scope, but others you need to add to the context. For example:
var repl = require("repl");
b = 20
repl.start("> ").context.a = 10
This will start the repl with both a and b in scope.

Related

Is it possible to run a node JS program in a console-like environment?

What I want is very simple, to run code while typing, just like enter node and run things like this:
% node
Welcome to Node.js v17.0.1.
Type ".help" for more information.
> var a=5; var b=6;
> console.log(a+b);
11
But in this case, I have to copy and paste my code again and again.
Is it possible to "include" the code from an eternal .js file, then let me stay in the console-like environment to run the code?
Store these in the app.js:
var a=5;
var b=6;
function addNumber(x,y){console.log(x+y);}
In node console:
% node
Welcome to Node.js v17.0.1.
Type ".help" for more information.
> include "app.js" //- This is what I'm looking for
> addNumber(a,b);
11
You can require files in the REPL just as easily as you can in a standard Node script.
For example, inside a directory, create a file, foo.js:
module.exports = () => 'foo';
And inside that directory, enter Node:
PS D:\Directory> node
Welcome to Node.js v14.17.6.
Type ".help" for more information.
> const foo = require('./foo');
undefined
> console.log(foo())
foo
undefined
>
require('./foo') will return the exports of the foo file in the same directory.
require('../foo') will return the exports of the foo file in the parent directory.
Absolute paths work too. And so on.

Create a persistent bash shell session in Node.js, know when commands finish, and read and modify sourced/exported variables

Imagine this contrived scenario:
./main.sh
source ./config.sh
SOME_CONFIG="${SOME_CONFIG}bar"
./output.sh
./config.sh
export SOME_CONFIG='foo'
./output.sh
echo "Config is: ${SOME_CONFIG}"
I am trying to replace ./main.sh with a Node.js powered ./main.js WITHOUT replacing the other shell files. The exported ./config.sh functions/variables must also be fully available to ./output.sh
Here is a NON working ./main.js. I have written this for the sole purpose to explain what I want the final code to look like:
const terminal = require('child_process').spawn('bash')
terminal.stdin.write('source ./config.sh\n')
process.env.SOME_CONFIG = `${process.env.SOME_CONFIG}bar` // this must be done in JS
terminal.stdin.write('./output.sh\n') // this must be able to access all exported functions/variables in config.sh, including the JS modified SOME_CONFIG
How can I achieve this? Ideally if there's a library that can do this I'd prefer that.
While this doesn't fully answer my question, it solves the contrived problem I had at hand and could help others if need be.
In general, if bash scripts communicate with each other via environment variables (eg. using export/source), this will allow you to start moving bash code to Node.js.
./main.js
const child_process = require("child_process");
const os = require("os");
// Source config.sh and print the environment variables including SOME_CONFIG
const sourcedConfig = child_process
.execSync(". ./config.sh > /dev/null 2>&1 && env")
.toString();
// Convert ALL sourced environment variables into an object
const sourcedEnvVars = sourcedConfig
.split(os.EOL)
.map((line) => ({
env: `${line.substr(0, line.indexOf("="))}`,
val: `${line.substr(line.indexOf("=") + 1)}`,
}))
.reduce((envVarObject, envVarEntry) => {
envVarObject[envVarEntry.env] = envVarEntry.val;
return envVarObject;
}, {});
// Make changes
sourcedEnvVars["SOME_CONFIG"] = `${sourcedEnvVars["SOME_CONFIG"]}bar`;
// Run output.sh and pass in the environment variables we got from the previous command
child_process.execSync("./output.sh", {
env: sourcedEnvVars,
stdio: "inherit",
});

Is it possible to make all of Node.js Globals available in Node's VM context?

Consider the following code:
vm = require('vm');
context = vm.createContext({});
vm.runInContext("Buffer.from('abc').toString()", context);
Observe that this produces ReferenceError: Buffer is not defined as Buffer is a Node.js specific construct that Node.js has added as a Node Specific Global Object. (Note that other JS globals like Math and Array do not share this problem.) This particular problem can be solved by modifying the above code to
vm = require('vm');
context = vm.createContext({Buffer});
vm.runInContext("Buffer.from('abc').toString()", context);
However, if I want every single Node Specific Global to be imported, then it appears as though I must list them one by one. Given that Node.js adds Global objects relatively frequetly, is there a way I can pass all of Node.JS' global objects to a vm context? Alternatively, is there a programatic way to construct a list of all of Node Globals?
Note: Using global isn't consistent across different node versions: e.g. Buffer is in global for node v8 and v10 but not v12.
I got this.
const cloneGlobal = () => Object.defineProperties(
{...global},
Object.getOwnPropertyDescriptors(global)
)
Test:
> const nG = cloneGlobal()
> nG.myVar = 'a';
'a'
> myVar
Uncaught ReferenceError: myVar is not defined
> 'myVar' in global
false
> 'myVar' in nG
true
> 'Buffer' in nG
true
Edit:
add Example code for the author's example:
vm = require('vm');
const cloneGlobal = () => Object.defineProperties(
{...global},
Object.getOwnPropertyDescriptors(global)
)
context = vm.createContext(cloneGlobal());
const ret = vm.runInContext("Buffer.from('abc').toString()", context);
console.log(ret); // abc
The whole reason to use the "vm" module is to isolate the context of the running program from the code being executed.
If you want to execute arbitrary JavaScript inside the current context you can just use eval. No reason to use vm.createContext.
eval("Buffer.from('abc').toString()");

Combine two json files to give a set of variables to use in Gulp

I have seen lots of posts online about how to use a set of variables defined in a file using a require statement.
I want to know how I can use two files.
For example, in pseudo...
gulp --env=prod
if (env):
defaultConfig = require('./config/default.json')
envConfig = require('./config/prod.json')
config = combine(defaultConfig, envConfig)
else:
config = require('./config/default.json')
// Now i can access everything like so...
console.log(config.name)
console.log(config.minify)
This keeps by config DRY and also means I don't have to create a new file for every environment I have.
I'm new to Gulp but i thought this would be a common requirement however, Google hasn't turned up anything for having defaults merged with env specific settings.
Do i need to write a node module?
You can do it with ES6 function Object.assign:
gulp --env=prod
if (env):
defaultConfig = JSON.parse(require('./config/default.json'))
envConfig = JSON.parse(require('./config/prod.json'))
config = Object.assign(defaultConfig, envConfig)
else:
config = JSON.parse(require('./config/default.json'))
// Now i can access everything like so...
console.log(config.name)
console.log(config.minify)
ES6 is supported in Node so you can use it whenever you want.
EDIT: If you have older versions of Node, you can use extend like Sven Schoenung suggest.
Use yargs to parse command line arguments and extend to combine the two config objects:
var gulp = require('gulp');
var argv = require('yargs').argv;
var extend = require('extend');
var config = extend(
require('./config/default.json'),
(argv.env) ? require('./config/' + argv.env + '.json') : {}
);
gulp.task('default', function() {
console.log(config);
});
Running gulp --env=prod will print the combined config, while simply running gulp will print the default config.
Use the following function :
function combine(a,b){
var temp0 = JSON.stringify(a);
var temp1 = temp0.substring(0, temp0.length-1);
var temp2 = (JSON.stringify(b)).substring(1);
var temp3 = temp1 + "," + temp2;
return JSON.parse(temp3);
}

Exporting a Variable Using Grunt Express in Node/Express

Under this example that I've been using to create my server:
https://github.com/blai/grunt-express#server
grunt-express is triggered through the 'module.exports = app' line.
However, in the same server file, I want to export a variable. I do via the following:
exports.hello = 'hello';
Though when trying to access that variable in another file in the backend, it doesn't work. I realize that this variable is being over-written by the last line 'module.exports = app', so how can I make it such that grunt-express works when the server is started, while allowing a variable to be exported to other files?
Thanks!
Just move module.exports.hello = 'hello'; below module.exports
Like so
module.exports = {some stuff}
module.exports.hello = "hello"

Resources