Installing NPM Modules via the Frontend - node.js

I am working on an app wherein I would like to be able to install NPM modules via the frontend. I have no idea, though, how to do so. That is, I know how to do CRUD actions via the front end, but I don't know how to either interact with the command line or run command line functions via the front end.
Are there packages that can help with this or is this built into Node.js somehow?
In short, how can I connect my front-end to my backend in such a way that I can install an NPM package?

What you want is the child_process module. It's built-in so you don't need to install any additional module.
Mostly what you're looking for is either spawn() or exec().
For example, if you want to run npm install some_module you can do:
const { exec } = require('child_process');
let command = 'npm install some_module';
let options = { cwd: '/path/to/node/project' };
exec(command, options, (error, stdout, stderr) => {
// Do anything you want with program output here:
console.log('output:', stdout, stderr);
});

You may check the documentation for child_process in Node JS:
Child Process
const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
The key difference between exec() and spawn() is how they return the data. As exec() stores all the output in a buffer, it is more memory intensive than spawn(), which streams the output as it comes.
Generally, if you are not expecting large amounts of data to be returned, you can use exec() for simplicity. Good examples of use-cases are creating a folder or getting the status of a file. However, if you are expecting a large amount of output from your command, then you should use spawn()

The easiest way to install an npm package via "the front end" is to have node spawn npm as a child process based off of the package name that the client provides.
var child = require('child_process').exec(`npm i ${package_name}`);
child.on('exit',function(){
//npm finished
});
This should install the module given that package_name is the name of the npm package, in the same directory that the script is running in. In terms of getting the package name from the front end to the back end, there are several different ways to do that.

You cannot run the your backend application without NPM modules installed, one thing that I think you can do is to make a plain nodejs file without any modules, which will receive the args when invoked, and you can use that args to the required modules, because that file will run with just core modules

Related

How to create and manage a npm process in electron

I'm trying to make this little QoL app that can trigger my scripts inside package.json of any project I throw at it (react, polymer, etc.).
So far, it works as it should. At least until I kill the app or want to terminate the specific process (like using ctrl+c while running a npm start in a console).
I'm currently calling the command this way:
const exec = require("child_process").execFile;
...
let ps = exec("command.bat", [path, command], (error, stdout, stderr)=>{}) //command.bat contains only: cd "%1" \n npm "%2"
Previously I've used node-powershell like so:
const Shell = require('node-powershell');
...
let sh = new Shell();
sh.addCommand(`cd ${fs.realpathSync(path)}`);
sh.addCommand(`npm ${command}`);
sh.invoke();
And I've already tried using ps-tree in hopes that this will list all the processes started by my process so I can kill them but no luck and because it creates additional process or two it's getting out of hands really quickly.
const cp = require('child_process');
...
psTree(ps.pid, function (err, children) {
cp.spawn('kill', ['-9'].concat(children.map(function (p) { return p.PID })));
});
So if there is some solution I would be really grateful. I'm also open to any different solution if there is any.
Thanks in advance.

Node.js ChildProcess#kill() does not kill Node.js processes created by npm.cmd on Windows

I am trying to kill child processes created by command npm.cmd (spawned using Node.js API) on Windows.
It executes something like npm.cmd run build. Using process.kill() seems to be able to end the npm.cmd command successfully, but not the Node.js processes created by the npm command.
let cp = spawn('npm.cmd', ['run', 'build']);
cp.on('exit', code => {
// It will log after 5 seconds.
// But Node.js process created by `npm run build` will not end.
console.log(`Exited with code ${code}.`);
});
setTimeout(() => cp.kill(), 5000);
I tried to replace process.kill() to something like spawn('taskkill', ['/f', '/t', '/pid', process.pid]) and it worked well. How can I achieve the same thing using Node.js API?

Npm child process live feed

I am writing a CLI tool for a node.js app. Some of the commands have to run npm and show the results. This is what I have so far:
import {spawn} from 'child_process';
let projectRoot = '...';
let npm = (process.platform === "win32" ? "npm.cmd" : "npm"),
childProcess = spawn(npm, ["install"], { cwd: projectRoot });
childProcess.stdout.pipe(process.stdout);
childProcess.stderr.pipe(process.stderr);
childProcess.on('close', (code) => {
// Continue the remaining operations
});
The command does run fine and outputs the results (or errors). However, it doesn't give me a live feed with the progress bar, etc. It waits until the entire operation is over and then dumps the output into the console.
I've tried different variations of the spawn configuration but I can't get it to show me the live feed.
I am on Windows 10 and use node.js 4 and npm 3.
As discussed in the comments: Run the spawn with { stdio: 'inherit' }.
However, good question is why the 'manual piping' does not do the same. I think that's because npm uses the 'fancy progress bar'. It probably uses some special way how to deal with stdout that does not play well with process.stdout. If you try some other long-running command (such as 'find ./'), your way of piping works fine.

Progmatically using npm from nodejs build script

I have a large project which contains multiple node application endpoints, each with their own package.json file.
I have a main build script (written in jake) which sets up a given environment, runs tests, packages apps etc.
So is there a way for the root build script to run "npm install" on the given directories.
I expect psudo code would be:
var npm = require("npm");
var package1Directory = "some-directory";
npm.install(packageDirectory);
Cannot find any documentation around this though so not sure if it is possible... so is it?
Yes, have a look at the docs:
var npm = require("npm")
npm.load(myConfigObject, function (er) {
if (er) return handlError(er)
npm.commands.install(["some", "args"], function (er, data) {
if (er) return commandFailed(er)
// command succeeded, and data might have some info
})
npm.on("log", function (message) { .... })
})
Also have a look at this example, which gives some more insights on how to use npm programmatically.

Is it possible to run PhantomJS from node.js as a command line argument

I was recently going to test out running phantomJS from python as a commandline argument, I haven't got round to it yet but have seen examples. Because PhantomJS is run from the command line this seems to be possible. The result that PhantomJS would spit out would go straight into a variable.
Before I go down that path, making this work in node.js would actually be more useful for me and it got me thinking, can i just use to node to run PhantomJS as a program gets run from the commandline and store the data result that PhantomJS would normally spit out into a variable?
I would rather not use phantomjs-node because it seems to be using too many tricks.
The reason for all of this is to be able to run PhantomJS at the same time as another action the program takes and use the resulting data its recorded for some other stuff.
Simply put, you can run system command line stuff in python, can I do the same in node.js?
Cheers :)
Edit: I understand that node and phantom use different js environments, that's cool because I just want to run phantom as its own process and catch all that output data into a node.js variable (the data will be a array of a pair, string and floating point.) I don't want to 'drive' with phantom, I will craft the loaded javascript files todo what I want. All I want is phantom output. :)
From NPM: https://npmjs.org/package/phantomjs
var path = require('path')
var childProcess = require('child_process')
var phantomjs = require('phantomjs')
var binPath = phantomjs.path
var childArgs = [
path.join(__dirname, 'phantomjs-script.js'),
'some other argument (passed to phantomjs script)'
]
childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) {
// handle results
})
I suppose you can make a simple script for Node.js to run; in that script phantomjs script will be run as a child process. You can see the working example (and links for some documentation) in this answer. I suppose this discussion might be helpful for you as well.
As an alternative to Donald Derek's answer, you can use the spawn function. It will allow you to read the child process's output as soon as it's produced rather than the output being buffered and returned to you all at once.
You can read more about it here.
An example from the documentation.
var spawn = require('child_process').spawn,
ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
ls.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
ls.on('close', function (code) {
console.log('child process exited with code ' + code);
});

Resources