File Pathing in Node.js - javascript

I have a folder that looks like
Main > models > file1.ejs
|
|> routes > file2.ejs
Two require file1 from file2 the code is const variable = require("../models/file1.ejs)
Let's say I do not want to require the model relatively, why does
const variable = require("/models/file1.ejs") not work.
Isnt "/" meaning to start at the root directory?
If we have an extensive nest of folders within another, how can we avoid doing "../../../../" in our file pathing?
Additionally, why does a code in JS that looks like Comment = require("./models/comment")
work but does not work when you do Comment = require("models/comment")
Or something in ejs that looks like <%- include("partials/header") %>
<%- include("/partials/header") %> does not work.
Is there anyway to always start from the root directory during pathing? Starting with "/" seems to end up causing an error when its suppose to make my pathing start from the root directory.

For example consider the below code,
var filename = "file1.ejs";
var fullpath = __dirname + "/models/" + filename;
read the docs about __dirname here
This is how you can provide the absolute path, where the __dirname will provide you with the path until the current working directory.
Where as relative paths work as below,
For example, if you trying to access file file1.ejs which is inside models directory from other file file2.ejs which is inside directory models2 where the models2 directory is also inside models then you may provide the relative path,
ie, the folder structure is as follows,
basePath/models/file1.ejs
basePath/models/models2/file2.ejs
and access file1.ejs from file2.ejs as below,
var path = '../file1.ejs' // going one folder back and getting inside parent models directory where the file1.ejs resides

Isnt "/" meaning to start at the root directory?
No. "/" refers to your existing file directory.
Additionally, why does a code in JS that looks like Comment = require("./models/comment") work but does not work when you do Comment = require("models/comment")
"/" is how node differentiates if they should pick up locally or somewhere in your installed modules. Imagine you have Express installed in your project and you have a file express.js. Then require('./express') will import your local file but require('express') will import the installed library instead.
If we have an extensive nest of folders within another, how can we avoid doing "../../../../" in our file pathing?
I believe you will need Babel. I haven't found any good sample on the web, but here are some useful materials.
Side note, I have worked on node project with related setup, but the development experience was awful as my editor couldn't pick up the resolved path and was struggling with auto-complete and intellisense. (but I personally believe the setup way was wrong or depreciated).
Resources:
Import module from root path in TypeScript
https://www.npmjs.com/package/babel-plugin-module-resolver
https://webpack.js.org/configuration/resolve/

Related

How does Nodejs handle relative paths?

I have a question regarding Nodejs's path-handling.
I know that they have a page about that in the docs but it didnt contain what I needed.
So basically, I have a file that includes a relative path referencing a file (png in this case).
Now, based on where I call the file from, the picture is either found or not found (as the point in the fileSystem from where its called changes).
I am using the 'sharp' framework, 'sharp('./picture.png')' is similar to require.
Example:
File 'render.js' :
const pic = sharp('./picture.png')
Calling:
cmd\examplePath> node render.js //picture is found
cmd> node ./examplePath/render.js //picture is not found
The location of the picture relative to the file stays the same at all times!
My question now is if what I have described is to be expected from Nodejs or if there is something wrong. What would I need to do to be able to call the file from anywhere and have it still work?
Any tips are appreciated.
Thanks :)
Normally file handling in nodejs such a fs.open() just resolves a relative path versus the current working directory in nodejs. The current working directory will be whatever the OS working directory was when you started your nodejs app.
The current working directory is not necessarily the same as the directory where your script is located because the current working directory might be different than where your script is located when your nodejs program was started.
So, in your two command line examples, each is starting with a different current working directory, thus one works and one doesn't.
In general in nodejs, it is not advisable to rely on what the current working directory is because this lessens the ability to reuse your code in other projects where it might be loaded from a different directory. So, if the file you are trying to reference is in a known location relative to your script's file system location, then you would typically build a full path, using either __dirname (in CommonJS modules) or import.meta.url or import.meta.resolve() (in ESM modules).
For example, if the image is in the same directory as your script, then you could do this in a CommonJS module:
const path = require('path');
const fullPath = path.join(__dirname, "picture.png");
const pic = sharp(fullPath);
In an ESM module, you could do:
import path from 'path';
const __dirname = new URL('.', import.meta.url).pathname;
const fullPath = path.join(__dirname, "picture.png");
const pic = sharp(fullPath);
My question now is if what I have described is to be expected from Nodejs or if there is something wrong.
Yes, that is to be expected. Your are starting your program with different current working directories and have code that depends upon the current working directory being a certain value (because of your usage of a relative path).
What would I need to do to be able to call the file from anywhere and have it still work?
Build an absolute path using your script's directory as the anchor location as shown above.
Note that require() or import use completely different file searching logic and have some built-in behavior that is relative to the module's location that is running them. But, they are the exception, not the rule. Operations in the fs module (or other modules that use the fs module) use the current working directory as the base path if you supply a relative path.

Problem writing to file fs module, apparently the path is positioned at the root level

I'm practicing with typescript and I want to write a file using fs module but I don't know if is this a noob question or I'm doing something wrong but my project look like this:
root
-> dir (here are the js result from tsc)
-> src
--> data
---> data.json
--> service
---> service.ts
--> index.ts
-> package.json
-> tsconfig.json
And at service.ts apparently the path is:
let filePath = path.join('./','src','data','data.json') // this works
fs.writeFile(filePath, JSON.stringify(data,null,2), 'utf8', (err)=>{ if(err){ return console.log(err);}})
So I don't know why the path is positioned at the root level
If I try "../data/data.json" I get ENOENT ERROR no such file or directory
Is it ok?
Filesystem operations with relative paths always use the Current Working Directory - a concept explained here: https://en.m.wikipedia.org/wiki/Working_directory
When you run Node.js, you do so while being in a particular directory. For example, scripts such as npm start are usually executed in the root-level directory of a repository/project - this causes all relative paths to resolve starting from there. Note, however, that this may be different in production - it is possible for Docker, PM2, systemd, or any other tool to run your script while being in a different working directory (this can often be configured).
To inspect your current working directory in Node.js, use https://nodejs.org/api/process.html#processcwd
It is also possible to build paths relative to the directory of the JS file. This tutorial shows various examples on how to do that: https://www.digitalocean.com/community/tutorials/nodejs-how-to-use__dirname
It is important to remember that require() uses paths relative to __dirname, but fs resolves relative to CWD.

Folder path - Absolute folder path

I am trying to add static folder for a project in app.js file. Im using macOS.
app.use(express.static("public")); // will work
app.use(express.static("\public")); // will work
app.use(express.static("/public")); // wont work
Can someone tell me what is the difference between these three.
"Public" folder is in project file.
Like this --> My_project > (public, app.js, node_modules)
const express = require("express");
const bodyParser = require("body-parser");
const request = require("request");
const app = express();
app.use(bodyParser.urlencoded({extended:true}));
app.use(express.static("public"));
First, it's not clear which operating system you're using. From your second example, it looks like you're using Windows (since that's the only OS that uses the "\" character as a directory separator). My experience with node is limited to Linux, but I believe it ought to work the same with Windows...
Edit MacOS is actually a "Linux-like" OS, so the discussion of Linux below applies equally to MacOS.
So, to answer your first question about the three different "public" paths:
app.use(express.static("public")); will use the public directory relative to where you started your node application. So, if you're in the directory "src" and your "public" directory is in the "src" directory, then it will serve files from that "public" directory.
app.use(express.static("\public")); will (I think) work the same as with the previous example. This is using the Windows path separator, so this is behavior I'm not too familiar with.
app.use(express.static("/public")); will attempt to serve public files from a "public" directory located at the root of the filesystem on a Linux system. This is actually an unusual use - normally you wouldn't create a public file directory in your filesystem root. You would be more likely to use the first version (or a slightly different path specification that means the same thing, like ./public).
So your example gives three different path specifications with varying meanings on different operating systems. How can you avoid this confusion?
Node provides a solution to this kind of confusion: the path module. Specifically, path.join method is provided to construct paths that work correctly on your operating system.
One pattern which I have seen used a lot is to make sure you are getting exactly the file/directory you expect by making it relative to the current file, like so:
app.use(express.static(path.join(__dirname, 'public')));
Imagine that this is in a file called C:\development\myproject\index.js and your static assets are in C:\development\myproject\index.js. This code will wind up working like this:
app.use(express.static('C:\development\myproject\public'));
where the path is constructed via the path.join method.
And, if you switch to Linux in the future (or you have other developers working on the project on their Linux machines), the code doesn't need to be changed to update the path.
I believe,
app.use(express.static("public"));
This will serve ./public folder contents as static files. (default behaviour)
app.use(express.static("\public"));
This will also serve the ./public folder, because you are merely escaping p(like escaping " by \"). As p and escaped p are same values it will work as expected.
app.use(express.static("/public"));
This tries to serve /public folder. / without any . means root, so it will try to access your local drive root directory and check if there is a public directory inside it.
You can test this by creating a directory called public in root and making a file inside it.

Wepback require from variable

I am making console utility which accepts a path to configuration file as a console argument.
F.e: utility -f /path/to/file.js
I need to require this file to read configuration. Is it possible to handle this with webpack? As I understand context can not help me in this situation.
Thanks.
P.S. I'm already using webpack.
P.S Solution is to use something like: eval('require')(dynamicPath)
Webpack can only do a dynamic require like this if the file to be required is available at compile time. For example, if you require a "dynamic" file path, like
require('./assets/images/' + someVariable + '.png')
Then under the hood, Webpack will include all images matching that pattern in the bundled require code. It basically will include all files matching the regex:
/.\/assets\/images\/*.png/
I would probably try putting the config file in a specific folder, and using require on that folder:
require('./configs/' + process.env.CONFIG_NAME);
This way Webpack will only include all files in the configs folder.
The Webpack documentation is horrible but there is more information on the dynamic requires page.
If you are passing in a config file as an argument to a node process, it will be accessible in the process.argv array of command line arguments. I don't know if you are using some other framework (like the excellent commander) to help with making command line programs, but we can just slice the array to find what we need.
To resolve a path from the directory the script is launched in, you can use process.cwd() - this returns an absolute path to the working directory of the node process.
Finally you can use path.resolve(processPath, configPath) (docs) to generate a path that is always guaranteed to resolve to the config. You can then require this path.
You probably need to do this first. The top of your file could look something like this:
/* relevant require() calls for necessary modules */
var path = require('path');
// first two arguments are node process and executed file
var args = process.argv.slice(2);
var configIndex = args.findIndex('-f') + 1;
var configPath = path.resolve(process.cwd(), args[configIndex]);
var config = require(configPath);
/* the rest of your code */

locating path of a file in meteorjs

I have a project in meteorjs that is using the nodes filesystem to read file, but I am not able to locate the file to be read.
My file Location
Server
- startup
- app.load.coffee
- myfileToBeRead.txt
My try in app.load.coffee
fs = Npm.require('fs')
console.log fs.readFileSync 'server/startup/myfileToBeRead.txt'
I am not able to read the file as it says
Error: ENOENT, no such file or directory 'server/startup/myfileToBeRead.txt'
I think since meteor merges everything in a js file, I have to add full path to the file.
I have tried other paths aswell (with the full path, without the full path). Can you point me out to the correct direction here?
Thank you
Well with the answer from David, I also found that I could do this with the assets/app directory of the project. All I had to do was add the file to a directory named private. This would also help me write to a file inside the directory aswell.
fs = Npm.require('fs')
console.log fs.readFileSync "assets/app/myfileToBeREad", 'utf8'
if the file should be checked in
This is the easy case - just place the file in your private directory and access it with the assets api. For more examples, see my blog post on exactly this subject.
if the file should exist somewhere else on the server
Use an absolute path to a directory not associated with your project, e.g. /tmp or /home/foo/bar. Directories inside of a meteor project get jumbled up after you bundle and deploy your app, so their existence can't be counted on. Using your example above it should work if you do something like:
var fs = Npm.require('fs');
fs.readFileSync('/tmp/myfileToBeRead.txt');

Categories