Node temporary npm install done programmatically - node.js

I would like to programmatically npm install a package using a Node app, after the node app has started. Ideally, this package would not file into my node_modules folder, but rather would trash itself after runtime.
npm supports programmatic installs, however it seems to actually save the modules into node_modules. Additionally, making the entirety of npm (a big module) a requirement for this kind of sucks. However, when I looked at the source code, the npm install part uses a ton of modules and isn't something I can easily reproduce.
Is there any other module that anyone knows about that meets this requirement?

Found with NPM you can install to a path, and there's this nifty temp module that helps do that cross platform:
var temp = require('temp')
, npm = require('npm')
;
function use(module, cb) {
npm.load({}, function(){
npm.commands.install(temp.dir, [module], function(err, data){
var dir = data[0][1];
var mod = require(__dirname + '/' + dir);
cb(mod);
});
})
}
use('lodash', function(_){
// ... do things.
});
If you want to, temp has a clean function that can clean up the temp dir later.

Related

Using npm as custom plugin manager?

Think of sublime text, where you can install or uninstall plugins. I want that for my app, and I want to use npm/github to do it.
Maybe I'll require that your package starts with myapp- to be considered a plugin for my app. How can I search npm based on that, and also install/update packages into the folder I want (not node_modules) and ideally it should work even if the person doesn't have npm installed (using an http api?).
Plugins for my app go into plugins/plugin-name folder, all I need to do is download their git source into that folder
I have created a project to solve similar problems. See live-plugin-manager.
You can install, uninstall and load plugins from npm at runtime.
import {PluginManager} from "live-plugin-manager";
import * as path from "path";
const manager = new PluginManager({
pluginsPath: path.join(__dirname, "plugins")
});
async function run() {
await manager.installFromNpm("moment");
const moment = manager.require("moment");
console.log(moment().format());
await manager.uninstall("moment");
}
run();
In the above code I install moment package at runtime, load and execute it. Here I have used typescript, but the same can be written with plain javascript.
Plugins are installed inside the directory specified in the PluginManager constructor or in the plugins directory if not specified.
I just created a great module, for enhancements like your proposal:
https://www.npmjs.com/package/#kawix/core
You can read the README.md, for try understand the usage, i will add a basic example:
> npm install -g #kawix/core
> kwcore "https://raw.githubusercontent.com/voxsoftware/kawix-core/master/example/npmrequire/express.js"
And this is the content of file https://raw.githubusercontent.com/voxsoftware/kawix-core/master/example/npmrequire/express.js
// this will download the npm module and make a local cache
import express from 'npm://express#^4.16.4'
var app = express()
app.get('/', function (req, res) {
res.send('Hello World')
})
app.listen(3000)
console.log("Listening on 3000")
https://api-docs.npms.io/ has an http API for searching npm packages.
Which can be used like this: https://api.npms.io/v2/search?q=keywords:myapp to get all plugins for myapp
To actually download/install an npm package into any folder, I found an npm package called download-npm-package that lets me do it in code

Node global module getting current run directory

I'm trying to create a node module that has the ability to be installed globally using npm install -g mymodulename. I've got everything in the module working fine if I run node index.js in the directory of the module, but now I want to make it so that I can publish it to NPM, and it can be installed and run from any directory.
There is some code in my module that looks at certain files in the directory that it is run in. I'm finding that when I do npm install -g ./ and then go into a different directory for a test, then run my-module-command, the relative path that it is reading is from that of where my module got installed (i.e. /usr/local/bin/my-module), not the directory that I'm running it in.
How can my module that is installed globally know where it is being run from? To give an example, I am trying to read the package.json file in the directory I'm in. And it is reading the package.json file of /usr/local/bin/my-module/package.json
I've tried:
__dirname
process.args[1]
process.cwd()
And just calling straight to require('./package.json') directly and none of those work.
Edit here's some code that's breaking in index.js:
#!/usr/bin/env node
var fs = require('fs');
var path = require('path');
var currentDir = path.dirname(require.main.filename);
fs.exists(`${currentDir}/node_modules`, function(dir) {
if (!dir) throw 'node_modules does not exist';
// do stuff
});
In my package.json:
...
"bin": {
"my-module": "./index.js"
},
...
I try to do npm install -g ./ in the project directory, and then I cd into a different directory called /Users/me/Projects/different-project, where another npm project is, and run my-module, and I get node_modules does not exist. When I log out currentDir, I get /usr/local/lib/node_modules/my-module where I'm expecting is to see /Users/me/Projects/different-project.
Have you tried using ./ at the start of your file path? That should give you the current working directory (or calling process.cwd() would work too).
In your case, your code would look like:
fs.exists(`./node_modules`, function(dir) {
if (!dir) throw 'node_modules does not exist';
// do stuff
});
I can see some comments already mention this. Maybe I'm misunderstanding the question? I just had a case where I needed a global module to get the directory I'm running the script from and what I suggested above worked like a charm.

Can I access locally-installed packages from a globally-installed package?

I don't know if I've worded the question properly, so I apologize if it isn't clear from the title what I mean.
Say I have an NPM package which installs an executable. Presumably I want users to install this package with the -g flag so that they can run it whenever.
In this case, when I call require() from within the executable, it will look for packages installed globally.
But suppose this package provides generic functionality for Node projects. I might want to know which packages the current project has installed locally. Should I just assume:
path.join(process.cwd(), 'node_modules')
Or is there a more "correct" way to set the NODE_PATH in this case? (Or rather than set NODE_PATH, should I just require(absolute_path_to_file)?)
require will not only lookup the package inside $(CWD)\node_modules but also inside all node_modules of parent, grandparent, etc. So you can use resolve on npm to solve this problem
FILE: your_global_command.js
// npm install resolve
var resolve = require('resolve').sync;
// Lookup for local module at current working dir
function require_cwd(name) {
var absolute_path = resolve(name, { basedir: process.cwd() });
return require(absolute_path);
}
// Load local express
// this will throw an error when express is not found as local module
var express = require_cwd('express');
I also create a package to require a package at current-working-dir (instead of __dirname of module):
https://npmjs.org/package/require-cwd

How to install npm package from nodejs script?

How to install npm package from nodejs script?
Question is not about simple installation npm packages via terminal,
it is about installation via nodejs script:
Not about this: npm install express, but about having install.js file with content npm install express, which I will execute like node install.js and after this it will locally install express module in this folder.
Sorry, but Google and DuckDuckGo are not my friends today(
The main problem is in automatic local installation required packages for my small utility, because global packages are not working in windows.
Check out commander.js it allows you to write command line apps using node.
Then you can use the exec module.
Assuming you put the following in install.js, you just have to do: ./install.js and it will run npm install for you.
#!/usr/bin/env node
var program = require('commander');
var exec = require('child_process').exec;
var run = function(cmd){
var child = exec(cmd, function (error, stdout, stderr) {
if (stderr !== null) {
console.log('' + stderr);
}
if (stdout !== null) {
console.log('' + stdout);
}
if (error !== null) {
console.log('' + error);
}
});
};
program
.version('0.1.3')
.option('i, --install ', 'install packages')
.parse(process.argv);
if (program.install) {
run('npm install');
}
var count = 0;
// If parameter is missing or not supported, display help
program.options.filter(function (option) {
if(!(option.short == process.argv[2]))
count++
});
if(count == program.options.length)
program.help();
Hope this helps!
NOTE: I don't think this fulfills all the requirements of your question, because at the end you state that you can't find npm...so maybe your question would be better titled "How to install npm package without npm?"--yikes! But it addresses the title, "How to install npm package from nodejs script?"
I've just been shown another alternative to do this: the module npmi. While this is still another module dependency, it does at least work without a *nix shell script environment, which I think the other answer here (about commander.js) does. And, if you look inside the code for npmi.js, you'll find it's very short and merely uses the npm module directly in the node script--which you can do yourself if you don't want to add the npmi module.
So in our case we needed a way to install modules without requiring a *nix shell script (to support Windows users), and this fits the bill nicely.
That still doesn't help you if you can't require('npm'). Only thing I can think of there is trying likely absolute paths...you can require('C:\Program Files\Node\packages\x)`, I think--or wherever node's global packages are stored (per user?). Wrap a couple of attempts in try/catch or test for the file's existence first and try to require the npm module whenever you find where the global packages are actually installed? You might tick off a malware scanner :-), but it might work.

Determine NPM modules used from a running node.js application

Other than grabbing the package.json file at the project root is there a way to determine the list of dependencies of a running node.js application? Does node keep this meta information available as some var in the global namespace?
If you are just looking for the currently installed npm packages in the application directory, then you can install the npm package (npm install -g npm) and programatically invoke ls to list the installed packages and the dependency trees.
Obviously, this has no bearing on whether the installed packages are actually require'd in the application or not.
Usage is not that well documented but this should get you started.
var npm = require('npm');
npm.load(function(err, npm) {
npm.commands.ls([], true, function(err, data, lite) {
console.log(data); //or lite for simplified output
});
});
e.g.:
{ dependencies:
{ npm: { version: '1.1.18', dependencies: [Object] },
request: { version: '2.9.202' } } }
Otherwise, I believe the only other option is to introspect the module module to get information pertaining to the currently loaded/cached module paths. However this definitely does not look to have been developed as a public API. I'm not sure if there are any alternatives so would be keen to hear if there are e.g.
var req = require('request'); // require some module for demo purposes
var m = require('module');
// properties of m contain current loaded module info, e.g. m._cache
I believe you could use require-analyzer, which sort of works according to Isaacs(could miss some). You could hear this in Nodeup's first podcast from 11:55.
Or you could try James node-detective which probably will find your dependencies better(but not by running code), but because of Javascript dynamic nature(12:46).
detective
Find all calls to require() no matter how crazily nested using a
proper walk of the AST.
P.S: to expose those package.json variables to node.js you could use node-pkginfo

Resources