I'm writing a simple application in Node.js with Express.
The path to my script is like path/to/script/server.js. When I run the script through node server.js and I'm in the above path, everything works perfectly.
When I try to run the script trhough node path/to/script/server.js it gives me the following error:
Error: Failed to lookup view "index.html" in views directory "d:\views"
at Function.app.render [...]
My views are in path/to/script/views.
How to solve it?
In your path/to/script/server.js use this setting (in place of what you may already have for your views path):
app.set('views', __dirname + '/views');
The default value for this setting is process.cwd() + '/views', which isn't exactly ideal. However setting it as above will make sure that the views directory is relative to server.js instead of the current working directory.
There are two solutions, both are opinionated.
Use cd path/to/script && node server.js. That will change your current folder to path/to/script and then run server.js. As a result, process.cwd() will return the desired working folder.
Pros: If there is other code relying on current working folder, it will start working as well.
Cons: It does not look graceful, and will also change your prompt's location, even if you did not want to. Though it is not omg hacks, and is often used, especially when writing cronjob files and application launchers.
Change your code not to rely on current working directory. That is: app.set('views', __dirname + '/views'); which will return directory name of a script, rather than directory from which your application was launched.
Pros: is often considered as good practice, does not have side effects.
Cons: you might have to modify the code in more than one place. Your code then relies on location of server.js to be where views folder is.
Why so? Mainly because working directory is rather an essential information and is often used or your benefit, not only to break things when it is not set properly.
Example of how it could be useful:
Imagine having two sites with same code but different serving content, the code is located in /path/to/code and data is in /sites/www1 and /sites/www2, then the magic can happen:
cd /sites/www1 && node /path/to/code.
Related
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.
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.
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.
I am currently making a Meteor app and am having trouble reading files from the private subdirectory. I have been following a couple different tutorials and managed to get it to work flawlessly when I run the meteor app locally. This question (Find absolute base path of the project directory) helped me come up with using process.env.PWD to access the root directory, and from there I use .join() to access the private folder and the pertinent file inside. However, when I deployed this code, the website crashes on startup. I am very confident that it is an issue with process.env.PWD, so I am wondering what the proper method of getting Meteor's root directory on a deployed app is.
//code to run on server at startup
var path = Npm.require('path')
//I also tried using the below line (which was recommended in another Stackoverflow question) to no avail
//var meteor_root = Npm.require('fs').realpathSync( process.cwd() + '/../' );
var apnagent = Meteor.require("apnagent"),
agent = new apnagent.Agent();
agent.set('cert file', path.join(process.env.PWD, "private", "certificate-file.pem"))
agent.set('key file', path.join(process.env.PWD, "private", "devkey-file.pem"))
In development mode the file structure is different than after bundling, so you should never rely on it. Particularly, you should not access your files directly like you're doing with path methods.
Loading private assets is described in this section of Meteor's documentation. It mostly boils down to this method:
Assets.getBinary("certificate-file.pem");
and it's getText counterpart.
As for configuring APN agent, see this section of documentation. You don't have to configure the agent by passing file path as cert file param. Instead you may pass the raw data returned by Assets methods directly as cert. The same holds for key file ~ key pair and other settings.
As an alternative, you would need to submit your files independently to the production server to a different folder than your Meteor app and use their global path. This, however, would not be possible for cloud providers like Heroku, so it's better to use assets in the intended way.
Example:
fs.readFile(path.join(__dirname, 'path/to/file'), callback);
versus
fs.readFile('path/to/file', callback);
Both seem to work, so I'm wondering if I can just skip the __dirname prefix, i.e. if there is any reason to prepend it.
From the node docs,
__dirname
is the name of the directory that the currently executing script resides in.
This will allow for flexibility across multiple deployments (eg: development / production).
If you are not deploying to any remote servers, you probably don't need the __dirname tag.
It is often better to use __dirname because it won't care where node is running from (i.e. the cwd).
Try running your application from a different directory - the __dirname variant will still succeed while the other will not. I.e. instead of node app.js run node foo/app.js assuming app.js lives in a directory named foo.