Require for a relative path across modules - node.js

I have project A that has a config.json file in its root. The project has a dependency on external module B, calling B.setConfig('./config.json').
While inside B.setConfig(path), if I call fs.existsSync(path), it says Ok, file exists, but calling require(path) fails with Cannot find module "./config.json".
Is it possible to adjust the relative path while inside module B to make require work?
I would prefer not to call setConfig with the full path, as it makes things awkward.

I found it, eventually, that if we want to take a relative path from module A (call it remotePath), and use it within require in module B, then to get the full path inside module B we can use the following:
var path = require('path');
var fullPath = path.join(path.dirname(process.argv[1]), remotePath);
var moduleInsideA = require(localPath); // this now works
process.argv[1] gives us the module A start-up file, from which we take the directory path, and then join it with the remote relative path, which then gives us the full path.

Related

Is it possible to use computer path in Node?

Normally in node one would use a path similar to this:
../js/hereIsMyJs.js
However in mac for example (pc is different)
the path can be ~/Desktop/Ohms/js/hereIsMyJs.js
Is there any module or way to use the computer path I just presented in node?
I'm using a module that requires the path to where the file should be placed.
It has to work dynamic so the optimal solution would be for me just to feed it the "computer" path.
const fileName = '~/Desktop/Ohms/somewhere/here.jpg'
QRCode.toFile(fileName, 'https://example.com')
To achieve what you want, it's normal to use node's native path.resolve https://nodejs.org/api/path.html#path_path_resolve_paths
// Start from current directory, and gives absolute path valid to the current OS.
console.log( path.resolve("../js/hereIsMyJs.js") ); // ie: C:\\projects\\js\\hereIsMyJs.js
// It also accepts multiple arguments, so you can feed it partial paths
path.resolve( "..", "js" ,"hereIsMyJs.js" ); // same result as above.
Other things worth to mention:
The tilde character ~ is short for the home directory in the *nix world. And works most places not windows.
In node you can use require('os').homedir() to get the home directory
There is also __dirname (gives absolute path of the directory containing the currently executing file) and process.cwd() which gives the directory from where you executed your file
And finally there is path.join() which is similar to resolve, but works for joining relative paths, and doesn't care about the current directory.

Node get path of the requiring parent file

I'm writing a node module and need to read a file in the same directory as the file which requires my module.
For instance, I have app.js and in the same folder, template.html.
In some unknown directory is module.js and app.js requires it.
How can I read template.html from module.js?
Inside your file you will have a module global (not actually a global)
you can get the parent object using module.parent and the filename with module.parent.filename then you could extract the folder
so from from your module.js you can use module.parent.filename.
http://nodejs.org/api/modules.html
p = require('path')
template = p.join(p.dirname(module.parent.filename),'template.html')
And if you are looking for the path of the file which was executed then you can use require.main.filename
Have a look here: http://nodejs.org/docs/latest/api/globals.html#globals_dirname
The you can just do this from within app.js:
var path = __dirname + '/template.html';
Then you can send this path to your module.js via some function or API.
Then your module can just use this path.
Inside a "module.js", the trick is using module.parent.filename
I don't personally like using globals, and for certain files (like configuration or templates), managing module require stack isn't so hard.
module.parent is mapped to the parent requiring module (which could be app.js as in your example).
Combining module.parent.filename with the path module gets you a few useful things like:
var path = require('path');
var parent_path = path.dirname(module.parent.filename);
var parent_relative = path.resolve(path.join(parent_path, '../', 'view'));
var template = path.join(parent_path,'./views/template.html');
I don't like using globals for anything to do with paths, I get spagetti ../../../dir./s

What is the difference between require('mypackage.js') and require('mypackage')?

Both these require statements appear to work the same way:
var Mypackage = require('mypackage.js');
var Mypackage require('mypackage');
Is there a difference between them?
Here is the answer:
Module.prototype.load = function(filename) {
debug('load ' + JSON.stringify(filename) +
' for module ' + JSON.stringify(this.id));
assert(!this.loaded);
this.filename = filename;
this.paths = Module._nodeModulePaths(path.dirname(filename));
var extension = path.extname(filename) || '.js';
if (!Module._extensions[extension]) extension = '.js';
Module._extensions[extension](this, filename);
this.loaded = true;
};
Node.JS looks to see if the given module is a core module. (e.g. http, fs, etc.)
Always takes the precedence in the loading modules.
If the given module is not a core module (e.g. http, fs, etc.), Node.js will then begin to search for a directory named, node_modules.
It will start in the current directory (relative to the currently-executing file in Node.JS) and then work its way up the folder hierarchy, checking each level for a node_modules folder.
Once Node.JS finds the node_modules folder, it will then attempt to load the given module either as a (.js) JavaScript file or as a named sub-directory; if it finds the named sub-directory, it will then attempt to load the file in various ways. So, for example
If you make a request to load the module, "utils" and its a directory not a .js file then:Node.JS will search a hierarchical directory for node_modules and
utils in the following ways:
./node_modules/utils.js
./node_modules/utils/index.js
./node_modules/utils/package.json
If Node.JS still can't find the file in above steps, Node.js will then start to look into the directory paths from environment variables i.e. NODE_PATH set on your machine(obviously set by Node.JS installer file if you are on windows)
Not Found in all the above steps then, prints a stack trace to stderE.g.: Error:Cannot find module 'yourfile'
For more information: link is here even the cyclic require() is explained very well.

Proper way to reference files relative to application root in Node.JS

I have a Node.JS application running on Linux at AWS EC2 that uses the fs module to read in HTML template files. Here is the current structure of the application:
/server.js
/templates/my-template.html
/services/template-reading-service.js
The HTML templates will always be in that location, however, the template-reading-service may move around to different locations (deeper subdirectories, etc.) From within the template-reading-service I use fs.readFileSync() to load the file, like so:
var templateContent = fs.readFileSync('./templates/my-template.html', 'utf8');
This throws the following error:
Error: ENOENT, no such file or directory './templates/my-template.html'
I'm assuming that is because the path './' is resolving to the '/services/' directory and not the application root. I've also tried changing the path to '../templates/my-template.html' and that worked, but it seems brittle because I imagine that is just resolving relative to 'up one directory'. If I move the template-reading-service to a deeper subdirectory, that path will break.
So, what is the proper way to reference files relative to the root of the application?
Try
var templateContent = fs.readFileSync(path.join(__dirname, '../templates') + '/my-template.html', 'utf8');
To get an absolute filesystem path to the directory where the node process is running, you can use process.cwd(). So assuming you are running /server.js as a process which implements /services/template-reading-service.js as a module, then you can do the following from /service/template-reading-service.js:
var appRoot = process.cwd(),
templateContent = fs.readFileSync(appRoot + '/templates/my-template.html', 'utf8');
If that doesn't work then you may be running /service/template-reading-service.js as a separate process, in which case you will need to have whatever launches that process pass it the path you want to treat as the primary application root. For example, if /server.js launches /service/template-reading-service.js as a separate process then /server.js should pass it its own process.cwd().
Accepted answer is wrong. Hardcoding path.join(__dirname, '../templates') will do exactly what is not wanted, making the service-XXX.js file break the main app if it moves to a sub location (as the given example services/template).
Using process.cwd() will return the root path for the file that initiated the running process (so, as example a /Myuser/myproject/server.js returns /Myuser/myproject/).
This is a duplicate of question Determine project root from a running node.js application.
On that question, the __dirname answer got the proper whipping it deserves.
Beware of the green mark, passers-by.
For ES modules, __dirname is not available, so read this answer and use:
import { resolve, dirname, join } from 'path'
import { fileURLToPath } from 'url'
import fs from 'fs'
const relativePath = a => join(dirname(fileURLToPath(import.meta.url)), a)
const content1 = fs.readFileSync(relativePath('./file.xyz'), 'utf8') // same dir
const content2 = fs.readFileSync(relativePath('../file.xyz'), 'utf8') // parent dir
We can use path madule to access the current path
const dirname = __dirname;
const path = require('path');
path.resolve(dirname, 'file.txt')
where
dirname - is give us present working directory path name
file.txt - file name required to access

How to resolve a relative path in node?

Came across this situation recently - I have an environment variable for a directory path like so:
var fooDir = process.env.FOO_DIR;
and I want to make sure this directory exists with a synchronous mkdir (at some point later):
fs.mkdirSync(fooDir, mode);
however if the user has supplied the environment variable via a realtive ~/ path node cannot resolve it
export FOO_DIR='~/foodir'
is there a way in node to resolve this without invoking a child process exec call to the actual shell? currently my solution is to do a replace myself like so:
fooDir = fooDir.replace(/^~\//, process.env.HOME + '/');
just curious if someone has a better solution.
You have it right: ~ is expanded by the shell, not the OS, just like *. None of the C file functions that node.js wraps handle ~ either, and if you want this you have to do the replacement yourself, just as you've shown. I've done this myself in C when supporting config files that allow relative file paths.
However, you should probably handle the case where HOME isn't defined; I believe this happens with non-interaction logins with bash, for example, and the user could always choose to unset it.
You can convert it to absolute path with path.join:
const path = require('path')
const absolutePath = path.join(process.cwd(), relativePath)
Check out Rekuire, it is a node module that solves the relative paths problem in NodeJs.

Resources