fs.readFileSync is not file relative? Node.js - 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

Related

Determining the path in fs.readFile()

var fs = require('fs');
var obj = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
This is the code for my app (index.js) . It uses a file named config.json using a relative path ./config.json. When I compile this into my mac using $pkg index.js, I obtain a test-macos file that is my app. Both the app and the config.json file are located in the same folder named project (this is why I can use the relative path ./config.json). However, once runnning the app I run into an error:
/Users/amelie/Documents/project/test-macos ;
exit; internal/fs/utils.js:312
throw err;
^ Error: ENOENT: no such file or directory, open './config.json'.
Therefore it seems that my app cannot find the config.json file. I could determine an absolute path but I need these two files to always be together because I need the path in the variable
var obj = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
to be always the same since I share those files to other people and the absolute path would therefore change. Is there a way to do this ?

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

How to get filename of script being executed in NodeJS?

How to get filename of script being executed in NodeJS application?
You can use variable __filename
http://nodejs.org/docs/latest/api/globals.html#globals_filename
Use the basename method of the path module:
var path = require('path');
var filename = path.basename(__filename);
console.log(filename);
Here is the documentation the above example is taken from.
As Dan pointed out, Node is working on ECMAScript modules with the "--experimental-modules" flag. Node 12 still supports __dirname and __filename as above.
If you are using the --experimental-modules flag, there is an alternative approach.
The alternative is to get the path to the current ES module:
const __filename = new URL(import.meta.url).pathname;
And for the directory containing the current module:
import path from 'path';
const __dirname = path.dirname(new URL(import.meta.url).pathname);
You need to use process.argv. In there will be the name of the script that was executed from the command line, which can be different than what you will find in __filename. Which is appropriate depends on your needs.
http://nodejs.org/docs/latest/api/process.html#process_process_argv

NodeJS readdir and require relative paths

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

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