Determining Node modules location at runtime - node.js

I am building a tool which is basically a node.js module. This tool can be installed globally (with -g option) I have few static files in the module to generate a report. If the module is invoked locally, I can refer to the static files with relative path ./node_modules/<module>/static/filename. But when the tool is invoked as a command, how do I refer to the static files? And how can I determine whether the tool is invoked as a local module or as a command?

When your tool is installed globally, there are usually two entries on Unix systems:
/usr/local/lib/node_modules/<module>/ -> the directory containing all module source files
/usr/local/bin/<script.js> -> symlink to your module executable script
Because Node is using the real path (i.e. after all symlinks were resolved) to resolve a path relative to current module, you don't need to worry about differences between global and local install.
What you do need to handle is the possibly different current working directory where the node process is running. The solution is to resolve the relative path to your static file against the absolute path where your module resides, not to assume that the node process will run in a particular directory as you do in your example.
There are two ways for that:
Using __dirname (API docs), which contains the directory name (path) of the current source file:
var path = require('path');
// assuming this script is in package root directory
var staticFile = path.resolve(__dirname, 'static', 'filename');
// if the script is in lib/ subdirectory, then you want to call
var staticFile = path.resolve(__dirname, '..', 'static', 'filename');
Using require.resolve(), which returns the exact same filename as would be used by a call to require():
// assuming this script is in package root directory
var staticFile = require.resolve('./static/filename');
// if the script is in lib/ subdirectory, then you want to call
var staticFile = require.resolve('../static/filename');

Use the magic variable __dirname. It refers to the directory containing your script file.
http://nodejs.org/api/globals.html#globals_dirname

Related

Node fs.readdirsync read directory in npm package

i tried to use fs.readdirSync and it work perfectly, but when i publish to npm and install this package to my new project, it not read my package directory instead it will read from my new project directory.
My goal is to get list file names inside package directory not new project directory
const dirents = fs.readdirSync("./", { withFileTypes: true });
console.log(dirents)
You need to use __dirname because it is an environment variable that tells you the absolute path of the directory containing the currently executing file.
Instead of using ./ it will represent your current working directory

node.js: resolve path relative from a test file

I working on a function implementation that is going to be distributed as a npm package.
Once this package has been installed by a consumer as a devDependency, they should be able to load a configuration file by calling a function (let's call it setConfig) from their test files.
I am trying to understand how to resolve a relative path (relative to the test file) when the consumer invokes my function (setConfig('./../some/relative/path/to/config')).
For instance, in the following project structure:
|- node_modules
|- my-published-package
|- dist/file.js (<- this hold setConfig)
|- src
|- configToLoad.json
|- __tests__
|- someTest.spec.js
The config could be specified as ../configToLoad.json and the setConfig should be able to resolve the path relatively to the test file path. In other words, the test author would write `importedClassFromPackage.setConfig('../configToLoad.json').
The setConfig function has the following signature:
setConfig(configPath: string): void {}
Where configPath can either be:
a relative path (from the test file that invokes that function)
an absolute path (absolute path of the configuration file)
a module specifier (i.e my-module/path/to/config.json)
First off, when your setConfig() function runs, you have no idea at all where it was called from. You do not and cannot know the directory of the file that you were called from.
As such, it is the responsibility of the caller to give you a path that you you can just use directly. It needs to either be a fully qualified path or be a relative path that is relative to the current working directory. It cannot be a path that is relative to the directory that the caller's module was in (unless that happens to be the same as the current working directory) because you will have no idea what the caller's module directory is.
So, in your desired spec where you want configPath to be any of these:
a relative path (from the test file that invokes that function)
an absolute path (absolute path of the configuration file)
a module specifier (i.e my-module/path/to/config.json)
Only the absolute path option will work or can be made to work.
The relative path won't work because your function does not know the directory of the test file you were called from.
The module specifier won't work because you don't know how to get the directory of that module name and it's ambiguous because it is possible to have the same named module loaded from more than one place (this happens in the real world when dependencies use a common module, but are using different versions of it).
Note, the caller can use path.join() to join their own module directory with the name of the file and pass you that fully qualified path. In a CommonJS module, the caller gets their own directory from __dirname. In an ESM module, the caller has to extract the directory from import.meta.url.

Writing NPM package, how do I specify that a PNG file path is in reference to the node_module script as opposed to from where it's imported

I'm writing a npm package that requires importing PNG files from within the package:
Directory Structure
__test__
__test__/test.js
src
src/resources
src/resources/PNG Image File
src/index.js
I'm using require(../src/index.js) from within test.js.
Whenever I try to reach ./resources/image.png from index.js, the path is attempted from within __test__ (because it's technically being imported an run by test.js.
I can't use the path ../src/resources because the goal is to create this as an NPM package that can be imported from anywhere.
What's the best way to specify within index.js that no matter where it's run, it should be looking within it's own directory for these image files.
You can use __dirname to represent the directory where your module was loaded from which is independent of how it was loaded.
So, from within index.js, you can refer to your PNG file llocation ike this:
let pngFileDirectory = path.join(__dirname, "..", resources);
And, if you know the filename you're looking for:
let pngFile = path.join(__dirname, "..", resources, "myFile.png");
Done this way, you dynamically construct the path relative to your own module file. Since the image file is part of the same NPM installation, the PNG file is in a fixed relative location to your own module file and this is independent of how your module was loaded or what the current working directory is in the project. Using __dirname is the key.

Force require to check the current directory for a module

I'm creating a command line application with Node. How can I make require check the current directory for the module?
For example, I want to run the command in the testing directory:
root#hello:~/projects/testing$ mycmd
And get the module which is in the node_modules/ of that directory, rather than it using a global version.
var myModule = require("testing/mymodule");
Using process.cwd() to find their current directory, I can then just get the dependencie from the node_modules/ folder.
/usr/local/lib/node_modules/mycmd/index.js:
require(process.cwd() + "/node_modules/request");

How to provide module dependencies for required script in a sibling directory

I am running a node.js script (foo.js) that requires a helper script that is located in a sibling directory.
//foo.js:
var magic = require('../util/magic');
magic.js uses a npm module express. However, the main directory of the 'program' (holding package.json and node_modules) is the folder where foo.js is located.
/program
/node_modules
/express
..
/foo.js
/package.json
/util
/magic.js
When running the program, the statement require('express') in magic.js fails - the module cannot be found.
Is there a way to make node.js load the express module from the program/node_modules directory?
I would like to avoid any of the following:
move the node_modules directory to a common parent of util and program
add a node_modules directory to util
pass in a reference of the required modules to magic.js
Appreciate your help!
You could supply a relative path instead the module name, because this is how Node.js is going to check for the modules folder if you don't specify a path:
/util/node_modules
/node_modules
Since you know where the module already exists, just do this instead:
var express = require('../program/node_modules/express');
However, you should place any files related to the module within the module itself when developing modules. If you don't, they don't get packaged with the module either when it is published, and you have this inconvenience of not being able to access dependencies specified in the package file.

Resources