Get `lib` path of a globally installed node CLI tool - node.js

I have a node cli tool I'm developing called wiki-sync.
I need access to the path to the node_modules lib dir from within my node cli app at runtime. This path, in my case, looks like: /Users/mchpatr/.node_modules/lib/node_modules/#parm/wiki-sync/
I've tried many things and none of these seem to give me what I am looking for. I'm certain there's an easy way to do this and I'm just missing it.
Here's what I've tried from within bin/wiki-sync:
process.cwd() /Volumes/Unix/workplace/Parm/src/Parm
process.execPath /usr/local/Cellar/node/13.8.0/bin/node
process.argv[1] /Users/mchpatr/.node_modules/bin/wiki-sync
fs.realpathSync(process.argv[1]) /Volumes/Unix/workplace/Parm/src/Parm/dist/apps/wiki-sync/bin/wiki-sync
which wiki-sync /Users/mchpatr/.node_modules/bin/wiki-sync

require.resolve('#parm/wiki-sync') will return the path to #parm/wiki-sync.
__dirname or __filename will return the path to the files directory or the directory itself.

Related

How does NPM/Node.js do path resolution in the local node_modules/.bin directory

Been confused about this for awhile
I have an executable file (cli/exec.js) in an NPM module called "foo" like so:
/foo
--/cli
exec.js
--/lib
package.json
in package.json, we have:
"name": "foo",
"bin": {
"exec-foo": "cli/exec.js"
}
when this module gets installed, with npm install, node_modules looks like this:
--/node_modules
---/.bin
exec-foo
---/foo
---/lodash
---/async
---/whatev
.........
...What confuses the crap out of me: how does Node.js do module/dependency resolution with the require function, now that the exec-foo.js file is no longer where it once was in the project, but is now located in node_modules/.bin? Is there a simple explanation for this?
NodeJS resolution is pretty well explained in the documentation.
If the module identifier passed to require() is not a native module, and does not begin with '/', '../', or './', then Node.js starts at the parent directory of the current module, and adds /node_modules, and attempts to load the module from that location. Node will not append node_modules to a path already ending in node_modules.
In your case node_modules/.bin/exec.js will be a symbolic link - a pointer to the original file.
Then NodeJS checks the original file path and starts parsing the required modules. If it can't find in the current node_modules path goes 1 directory upwards until it finds your library.
If no library has been found it throws an error.

node.js controlling relative filepaths in different environments - pm2 vs vanilla node for example

I have a line of code:
var currentDir = './src/config';
fs.readdirSync(currentDir).forEach(function(dir) {...
This works fine on Mac, but on Ubuntu I'm getting an error:
Error: ENOENT, no such file or directory './src/config'
On mac I'm using node v5.5.0
on Ubuntu I'm using node v0.10.25, and using pm2.
======= Edit
See below for comments on the solution
The answer to this question was the comment by Evan Lucas:
When using a relative path, it will be relative to the cwd of the process. I would probably go for using an absolute path by resolving the relative file path to wherever you need it to be to be on the safe side. If it is relative to the file, you can use path.join(__dirname, './src/config')

node module.paths confusion

node module.paths confusion
Issue: required node modules do not use my global module.paths even though I add the global path to the array in my main.js application.
Example:
mymain.js
//global modules path
module.paths.push('C:\Users\xuser\AppData\Roaming\npm');
// finds ws in global modules path. Works!
wsmain=require('ws')
// Now load a 3rd party module, which also requires('ws')
C = require('cmod.js');
cmod.js
ws=require('ws'); // fails to find global path
q: How do I make sure that module global is also passed on to the require modules. Is there a way to pass it as a parameter or something?
I'm not sure there is a "global" path. The node.js documentation suggests a default require takes place relative to the file requiring it, and searches for a node_modules directory up the directory chain. From the docs:
For example, if the file at '/home/ry/projects/foo.js' called
require('bar.js'), then node would look in the following locations, in
this order:
/home/ry/projects/node_modules/bar.js
/home/ry/node_modules/bar.js
/home/node_modules/bar.js
/node_modules/bar.js
It looks like you can use NODE_PATH env var to give a list of places to look for modules:
https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
Based on the documentation, the following might work:
NODE_PATH=/path/to/node_modules/where/ws/lives node mymain.js

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

Determine command line working directory when running node bin script

I am creating a node command line interface. It is installed globally and uses a bin file to execute.
I plan to have a command window open at the root directory of the files I am working on and then just run the command however I have been unable to determine the current working directory as process.cwd() is returning the directory of the node package. I initially assumed that since the code is being executed using a batch file as a wrapper (that is how bin files can execute without node at the beginning) then it is impossible but coffee-script manages to do it. I took a look at the coffee-script source but couldn't follow it (not experienced enough).
To test it for yourself create a package with this package.json file:
{
"name": "test-package",
"version": "1.0.0",
"bin": {
"test-package": "./bin/test-package"
},
"main": "/lib/test"
}
this test-package file in bin:
#!/usr/bin/env node
var path = require('path');
var fs = require('fs');
var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');
require(lib + '/test');
Could anyone shed some light onto this.
and then try and get the command line directory inside lib/test.
process.cwd() returns directory where command has been executed (not directory of the node package) if it's has not been changed by 'process.chdir' inside of application.
__filename returns absolute path to file where it is placed.
__dirname returns absolute path to directory of __filename.
If you need to load files from your module directory you need to use relative paths.
require('../lib/test');
instead of
var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');
require(lib + '/test');
It's always relative to file where it called from and don't depend on current work dir.
Current Working Directory
To get the current working directory, you can use:
process.cwd()
However, be aware that some scripts, notably gulp, will change the current working directory with process.chdir().
Node Module Path
You can get the path of the current module with:
__filename
__dirname
Original Directory (where the command was initiated)
If you are running a script from the command line, and you want the original directory from which the script was run, regardless of what directory the script is currently operating in, you can use:
process.env.INIT_CWD
Original directory, when working with NPM scripts
It's sometimes desirable to run an NPM script in the current directory, rather than the root of the project.
This variable is available inside npm package scripts as:
$INIT_CWD.
You must be running a recent version of NPM. If this variable is not available, make sure NPM is up to date.
This will allow you access the current path in your package.json, e.g.:
scripts: {
"customScript": "gulp customScript --path $INIT_CWD"
}
path.resolve('.') is also a reliable and clean option, because we almost always require('path'). It will give you absolute path of the directory from where it is called.
Alternatively, if you want to solely obtain the current directory of the current NodeJS script, you could try something simple like this. Note that this will not work in the Node CLI itself:
var fs = require('fs'),
path = require('path');
var dirString = path.dirname(fs.realpathSync(__filename));
// output example: "/Users/jb/workspace/abtest"
console.log('directory to start walking...', dirString);
Warning if using ES Modules
According to the ECMAScript modules docs:
CommonJS variables __filename or __dirname are not available in ES modules.
Instead, use cases can be replicated via import.meta.url.
So according to why is __dirname not defined in node?, you can do the following:
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
Here's what worked for me:
console.log(process.mainModule.filename);

Resources