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

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

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.

Node temporary npm install done programmatically

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.

node js elementtree required get Cannot find module 'sax'

i am attempting to use elementtree in my node js server
however the following message is genearted on server startup
Cannot find module 'sax'
i had to install elementree from zip, what have i done wrong?
these are my rquire statements
var cache = require('./node_modules/node-cache');
var elementTree = require('./node_modules/node-elementtree');
this is my folder structure
module\node_modules\node-cache
module\node_modules\node-elementtree
my server js script resides in \module
The problem is because you are not using npm for installing your node-elementtree module
This is the package.json of node-elementtree. and it is clearly mentioned that there is a dependency on sax 0.3.5
"dependencies" : {
"sax": "0.3.5"
}
Incase if you had done npm install it would have resolved your dependency constraints.
Inside your node-elementtree module it uses sax here and your require didn't resolve to a proper module. Hence the error. Incase you can't use npm then install sax too using zip if possible but it may increase your dependency list once again as the above. So, Try resolving npm issue
Also you don't need to use
var cache = require('./node_modules/node-cache');
var elementTree = require('./node_modules/node-elementtree');
in your code
var cache = require('node-cache');
var elementTree = require('node-elementtree');
the above would do. Node automatically locates the module from ./node_modules directory and even from many more places

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