NodeJS readdir and require relative paths - node.js

Let's say I have this directory structure
/Project
/node_modules
/SomeModule
bar.js
/config
/file.json
foo.js
-
foo.js:
require('bar');
-
bar.js:
fs.readdir('./config'); // returns ['file.json']
var file = require('../../../config/file.json');
Is it right that the readdir works from the file is being included (foo.js) and require works from the file it's been called (bar.js)?
Or am I missing something?
Thank you

As Dan D. expressed, fs.readdir uses process.cwd() as start point, while require() uses __dirname. If you want, you can always resolve from one path to another, getting an absolute path both would interpret the same way, like so:
var path = require('path');
route = path.resolve(process.cwd(), route);
That way, if using __dirname as start point it will ignore process.cwd(), else it will use it to generate the full path.
For example, assume process.cwd() is /home/usr/node/:
if route is ./directory, it will become /home/usr/node/directory
if route is /home/usr/node/directory, it will be left as is
I hope it works for you :D

Related

path.dirname on Windows path is giving `.`

I in electron am doing:
path.dirname('C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron\\main')
That path is the actual value of my __dirname. How come it is not giving me C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron? I want that main part chopped off.
Assuming main is a directory inside electron. Also assuming that you have some file called index.js inside main folder where you want to have the path of electron directory.
So, you can do path.join this way:
var mainFolderParentPath = path.join(__dirname, '../');
Your original file location:
C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron\\main\\index.js
__dirname will return
C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron\\main
and then inside path.join '../', will chop off the main folder from path. So, you will be left off with:
C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron
Well you obviously didn't read the docs for dirname. It states that it works like the Unix command dirname which "strips non-directory suffix from file name", thus you get the C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron.
What you are looking for is basename.
path.basename('C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron\\main') will give you main.

fs.readFileSync is not file relative? Node.js

Suppose I have a file at the root of my project called file.xml.
Suppose I have a test file in tests/ called "test.js" and it has
const file = fs.readFileSync("../file.xml");
If I now run node ./tests/test.js from the root of my project it says ../file.xml does not exist. If I run the same command from within the tests directory, then it works.
It seems fs.readFileSync is relative to the directory where the script is invoked from, instead of where the script actually is. If I wrote fs.readFileSync("./file.xml") in test.js it would look more confusing and is not consistent with relative paths in a require statement which are file relative.
Why is this? How can I avoid having to rewrite the paths in my fs.readFileSync?
You can resolve the path relative the location of the source file - rather than the current directory - using path.resolve:
const path = require("path");
const file = fs.readFileSync(path.resolve(__dirname, "../file.xml"));
Just to expand on the above, if you are using fs.readFileSync with TypeScript (and of course CommonJS) here's the syntax:
import fs from 'fs';
import path from 'path';
const logo = fs.readFileSync(path.resolve(__dirname, './assets/img/logo.svg'));
This is because fs.readFileSync() is resolved relative to the current working directory, see the Node.js File System docs for more info.
Source: Relative fs.readFileSync paths with Node.js
And of course, the CommonJS format:
const fs = require('fs');
const path = require('path');
const logo = fs.readFileSync(path.resolve(__dirname, './assets/img/logo.svg'));
Another alternative if you are using type module is to use process.cwd()
package.json
{
"type": "module",
}
console.log(process.cwd() + relative_path) // /User/your_user/path_to_folder

Why use path.join() instead of just static('public')

In all the node express tutorials I've read the following syntax is used to create the public directory:
var path = require('path');
app.use(express.static(path.join(__dirname, 'public')))
However the following works just fine:
app.use(express.static('public'))
So why would I use the path module instead ?
The last example uses a relative path, which will work if you start your app from the directory that has public as a subdirectory.
However, it will break if you start your app from another directory. Let's assume that your app is located in /path/to/app/directory but that you start your script while /tmp is the current (working) directory:
/tmp$ node /path/to/app/directory/app.js
In that situation, Express will try to use /tmp/public as the location for your static files, which isn't correct.
Using path.join(__dirname, 'public') will create an absolute path, using the directory where app.js is located as the base. In the example above, it will resolve to /path/to/app/directory/public, which will also be valid if you start your script from another working 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

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

Resources