Why does require() not require an absolute path but an express.static() does? - node.js

I am trying to run my index.js script from outside the project directory. My project structure is as follows:
app
- config
- config.js
- public
- index.html
- src
- index.js
Now when I run my src/index.js from outside my app folder, require() is able to resolve the relative paths
const config = require(`../config/config`);
On the other hand express.static is not able to resolve such relative paths.
e.g. app.use(express.static("../public"));
Why do I need to use path.join and get the absolute path?

require() works off __dirname which is independent of what the current directory was when your app was loaded. It's always the directory where the module is located in, so it is consistent.
express.static() when used with relative paths uses the directory that the main app was launched form, so if you use relative paths, its behavior varies depending upon how you launch the app.
From the express doc for serving static files:
However, the path that you provide to the express.static function is
relative to the directory from where you launch your node process. If
you run the express app from another directory, it’s safer to use the
absolute path of the directory that you want to serve
So, if you want the directory to be module relative, you have to manually combine your path with __dirname to make a full path, as you have discovered.

Related

NodeJS - Paths break after deployment

I deploy my NodeJS Projects with supervisord. Strangely most of the paths, which are paths
inside the served index.html: links to static files (stylesheets and js files)
inside javascript files, require statements to other files(e.g.: require('./scripts/'))
I believe the reason for that to be the command node "path/to/my/application/app" since it runs the application from a different directory.
How can i avoid changing the paths whenever i push a new version of my application to production?
Can you recommend any tools to solve this problem? Is there a clean way of setting the paths so that the application works so i can run it from anywhere(my local machine/my webspace)?
Use a relative path. For example if index.html is in a directory as same as a .js file referring it u can use ('./index.html'). If it were in a parent directory u could use (../index.html)

How to resolve path to a file within node_modules

Problem loading a file using relative path when my node app is initialised using a another node app
I have created an npm which relies on a file stored relative to project root. something like this
index.js
- res
- config.json
Now I read the config.json using following code
const pathToConfig = path.resolve(__dirname, '../res/config.json')
This works great locally.
But in my prod setup this app is initialised by another node app.
And __dirname resolves to root of that app so all my logic to find config.json get messed up.
Is there any way I can read the file without worrying about how node app was initialised?
Have you tried the command process.cwd()? It is almost the same as __dirname but does differ slightly.

How Express.static decides a relative path

All:
I wonder when I use express.static with a relative path like
app.use(express.static('./dist'));
How do I know what is the root directory? One interesting thing I find is:
If I run node server/app.js(all express server code is inside app.js) and put dist fold along with server folder, it works, but if I run node app.js inside server folder, then it does not. So does this mean express decide root base on some variables from Node?
Thanks

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.

NodeJitsu error: Error: ENOENT, stat '/opt/run/snapshot/

My app’s folder structure for NodeJitsu is as follows (i.e., when i do a jitsu deploy, I'm in the folder that contains "server.js" - i.e., the "server" folder).
Root server
|___server.js
|___package.json
client
|___www
|___index.html
|___css
|___js
|___etc.
So at the root is the folder "server", containing the starting script, “server.js”. Then there’s a folder called “client”, parallel to "server", with a folder within that called “www”, and within “www” is the main “index.html”.
In my “server.js” file, I have the following code:
app.get(‘/’, function(req,res)
{
var aPath = path.resolve(“../client/www/”, “index.html”);
res.sendFile(aPath);
});
I don’t have a app.use(express.static(__dirname + '/somefolder'). And when I start the app, I get this error:
Error: ENOENT, stat '/opt/run/snapshot/client/www/index.html'
My process.cwd() is /opt/run/snapshot/package. Obviously the above path isn’t pointing to the location where “index.html” resides. But I thought the way I do the path.resolve(…) should point to “index.html”. I can’t see where the problem is. If “server.js” is in the root, then to get to “index.html”, which is in “client/www/index.html”, then I should need to write “../client/www”, relative to the excuting script, to get to “index.html”, right?.
Do you have any insights as to where the path is not set up correctly? What should /opt/run/snapshot/ be pointing to? Or, what changes do I need to make in the get(‘/’) handler to correctly point to my “index.html”?
EDIT
I incorrectly drew the folder structure. Now it's correct.
I also turned off the app.get() and turned on the app.use(express.static(__dirname + '/../client/www/'). But to no avail: now i get a Cannot GET / error.
What I'm ultimately after is to have the "server.js" file be the Node server that, mostly, just serves AngularJS HTML files to the browser, with attendant images, stylesheets, etc., from the "client" folder. This is the server's main role, with an additional role of authenticating the app's users, employing the very nice Satellizer module. And that's it. I have a MongoDB attached, but otherwise this is a very common and straightforward Node.js server app.
Thanks!
Try it without rooting, resolving and log out to double check:
// notice no leading / which is root. __dirname should be the dir of current file running
var staticPath = path.resolve(__dirname, '../client/www');
console.log(staticPath);
Then pass that into express.static
app.use(express.static(staticPath);
I would probably recommend following the layout and convention of express generated apps with app in the root and static files under public
/public
<static files>
app.js
Then do what the generated app does:
app.use(express.static(path.join(__dirname, 'public')));

Resources