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.
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 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/
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.
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.
I'm now learning Node.js and Express, and want to use mysql module to render multiple unique pages, so instead of writing out var connection=mysql.createConnection({user:'root', password: 'root'...etc}) line on every file located under routes directory, I'm sure it's better off to just call my own mysql config file on each routing file.
However, where should I put the config file on Express hierarchy and how can I call the file from within each routing file? I know all images, style sheets, and javascript files should be located within each specific directory under public directory, but I don't know where to put all the other files that are intended to be accessed from routing files.
I also want to know whether all of my files, ranging from main app.js to files under routes directory to files under public directory, etc... can be found by users once I publicize this web application on the Web. If it's the case, then I think I should not put database config file on directories that clients can access to...right? In other words, I want to make sure which files can be accessed to by clients and which cannot in order to avoid security attacks.
To answer your first question "Where to put the config file?":
This is a little bit personnal. Put it to the root of your application.
config.js:
module.exports = {
database:{
host: ""
user: "..."
}
}
then you include it in you app.js:
app.js:
...
config = require("./config");
db = config.database;
var connection=mysql.createConnection({user:db.user, ...})
Note that you might want two config file, one in you version control and one private to the machine. Different developers might have different database access for example. But I don't think you have to worry about that for now.
For your second question "Are all my files public?":
No, only the file you specify as static (with the express middleware) will be served.
app.js:
...
// Exposes the public folder
app.use(express.static(__dirname + '/public'));
You can put them wherever you want. I usually create a /conf directory right off the project root and put config files in there, in JSON format.