I have a Discord bot I'm maintaining since a year, and a couple of months ago I changed a bit the file structure to clean it up and make it easier for me to know what's going on.
The thing is, whenever I try to request a file (with require) that is in a folder located in the bot's root directory, sometimes it works with "./" and other times it works with "../"
The current file structure is:
----commands
-------commands.js(multiple files)
----images
-------halloween
----------images.png/jpg(multiple images)
----logs
-------bot.log
----modules
------logger.js
----settings
-------config.json
-emojis.json
-gifs.json
-index.js
Following the structure above, when for example I try to request one of the halloween images in a command, the logical thing to me would be to use "../images/halloween/image.png", but instead I have to use "./images/halloween/image.png" as if the "images" folder is within the "commands" folder
In one of the commands I have to use:
const logs = require("../modules/logger");
const background = await Canvas.loadImage("./images/halloween/background.jpg");
I would like to know why this happens. It really messes with my brain seeing an error saying that a file was not found only because node.js decided that this time the parent directory is "./" instead of "../"
Assuming your commands file is making file system calls (because you're accessing an image from it), the directory you invoke your script from can matter. Make sure you're using the path utility to resolve your file locations. See NodeJS accessing file with relative path for more details.
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.
This question already has answers here:
Next.js: How to make links work with exported sites when hosted on AWS Cloudfront?
(3 answers)
Closed 10 months ago.
hoping a Next.js magician could help me with this, or at least just tell me flat out if it isn't possible.
We have a site which is compiled down into static files. These will be served from S3.
When I run next export, everything builds correctly, but I had hoped to be able to directly access subpages without adding the .html extension. I assumed (wrongly) that next built pages into directories, and dropped an index.html into that directory.
The setup on the dev side is fairly simple. Each component has a directory, eg "some-component", with an index.js which exports the named component from an adjacent file like "some-component.js".
This all works if I start at the site root - I can navigate to, eg, /components/some-component without worrying about the extension.
Next has created a some-component directory, but the file inside that is still just called some-component.html. So if I hit that url from the browser, it obviously 404s.
Is there any way to get next to spit out index.html's into the directories, so browsing directly to the directory (try saying that after a drink) works? Or am I barking up the wrong tree?
I know there are other solutions to this, particularly for s3, but figured it was worth asking about.
Cheers!
Next.js has a trailingSlash setting that should work for you:
// next.config.js
module.exports = {
trailingSlash: true,
}
When this setting is true, and using something like ./pages/products/shoes.jsx as an example, a directory named after the .jsx file (shoes) is created and that .jsx file then becomes an index.html file inside that directory, i.e., href="/products/shoes/". Your server will send that path's index.html (or can be configured to if it doesn't already) even when index.html isn't specified in the href.
This is my project's filesystem.
root
index.js
package.json
...etc
commamds
- ping.js
- eval.js
- ...etc
This is a normal discord.js bot.
But when I try reloading the commands, I use the following code:
...etc
let pull = require(`./${file}`);
// file is command files from fs.readdirSync() and it can be 'ping.js', 'eval.js', ...
...etc
But it throws a referenceerror that the module can't be found. But when I try fs.readFile(), it works. What's the problem?
fs.readFile() defaults to the current working directory if there is no path or if there's a relative path on the filename.
require() has a completely separate set of rules for where it looks for files. For example, a filename with no path at all looks in the node_modules directory and in the global module location(s). A filename starting with ./ looks in the current module's home directory. And so on... It's a different set of rules than fs.readFile().
Since you don't show us what file actually is, it's hard to know precisely, but perhaps you need to combine the filename with the appropriate path so you are giving require() a full path name and it will go exactly there, not use the normal rules for where require() looks when given only a plain filename.
I created the files following the tutorial (http://dataops.co/android-login-registration-system-with-node-js-and-mongodb/), but unfortunately the error is shown like in the image.
I'm new to node.js and to this kind of programming.
PS.: All of the other files that are referred in the tutorial are right, and the chgpass.js is in the target folder.
Code from the file that requests the chgpass.js file AND the tree from the folder (open with Word and select MS-DOS):
http://www.mediafire.com/download/w283nsjuuj9j794/File-Folder.txt
As your config folder is inside of node_modules folder, thus use:
var chgpass = require('config/chgpass');
Explanation:
In tutorial config folder is inside node_modules that way you can directly access it using require('config/chgpass')
But if you put outside of node_modules then you have to give the complete path of the folder from the location you are requiring it. That is in your case: require('../config/chgpass')
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');