Is it possible to use computer path in Node? - node.js

Normally in node one would use a path similar to this:
../js/hereIsMyJs.js
However in mac for example (pc is different)
the path can be ~/Desktop/Ohms/js/hereIsMyJs.js
Is there any module or way to use the computer path I just presented in node?
I'm using a module that requires the path to where the file should be placed.
It has to work dynamic so the optimal solution would be for me just to feed it the "computer" path.
const fileName = '~/Desktop/Ohms/somewhere/here.jpg'
QRCode.toFile(fileName, 'https://example.com')

To achieve what you want, it's normal to use node's native path.resolve https://nodejs.org/api/path.html#path_path_resolve_paths
// Start from current directory, and gives absolute path valid to the current OS.
console.log( path.resolve("../js/hereIsMyJs.js") ); // ie: C:\\projects\\js\\hereIsMyJs.js
// It also accepts multiple arguments, so you can feed it partial paths
path.resolve( "..", "js" ,"hereIsMyJs.js" ); // same result as above.
Other things worth to mention:
The tilde character ~ is short for the home directory in the *nix world. And works most places not windows.
In node you can use require('os').homedir() to get the home directory
There is also __dirname (gives absolute path of the directory containing the currently executing file) and process.cwd() which gives the directory from where you executed your file
And finally there is path.join() which is similar to resolve, but works for joining relative paths, and doesn't care about the current directory.

Related

Understanding how path works in Node

So I have developed a Node Api and on local the path works fine, but I want to move it now to a server online, and don't know how to address the path.
This is the path in local: const path = "/Users/username/Code/projectname/api/invoices"
And what I want to do is make it work also for online, also to make sure that the folder api is what is going to be uploaded, not the one with projectname as it contains the client folder and other folders, so only the api folder.
use __dirname to get the path of the folder.
The __dirname in a node script returns the path of the folder where the current JavaScript file resides.
const path = `${__dirname}/api/invoices`
You can use the __dirname variable.
For this, you first need to import path.
const nodePath = require("path");
Then, to get the path, you need to join the directory name and your custom path together.
const path = nodePath.join(__dirname, "/api/invoices");
This should correctly join the path together.
Note: Naming conventions changed to avoid naming conflicts.
In conclusion, you can use the __dirname variable!

Nodejs difference between ./folderpath vs ../folderpath

I'm new in nodejs. I try to use some file in my filesystem. I would like to get them through some realtive path. Here is the structure:
-app
-resources
-tmp
-file1
-file2
-common
-common.js
-etc
So, I would like to reach the file1 and file2 in my resources/tmp folder from the common.js file in int common folder. I used two relative path methodic:
// First , wrong one
var tmpfolder = '../resources/tmp';
// Second, good one
var tmpfolder = './resources/tmp';
The file absolute path is something like this:
C:\Users\xy\Documents\work\nodejs\projects\project_wrapper_folder\project_folder\resources\tmp
If I log the first relative path I got this result:
C:\Users\xy\Documents\work\nodejs\projects\project_folder\resources\tmp
which is wrong, because it does not contains the wrapper folder.
But the second works fine.
Can somebody explain me this behaviour?
UPDATE
I see the meaning if '../', thanks your explanations!
I have tried #Lissy answer: "So baring that in mind ./ will resolve to the value of your project root..." that sounds great, but the result is not.
I have this logic in my app:
var tmpfolder = require('./otherFolder/orhetFile');
where otherFolder is the subfolder of my project_folder. So, when I used this here, I got an error called Cannot find module ...
But if I use this './' in fs module, here: /project_folder/otherFolder_2/otherFile_2 like:
var path = `./resources/tmp`;
fs.mkdirsSync(path);
It works!
these is strange for me. If './' means the current folder, than the example above sould not work (but it's works).
But if the './' means path of the project root, the example with require should work (but does not work).
Strange for me, is there some meaning of require or fs??
In Summary
./my-file means look at the root, whereas ../my-file, means come out of the current directory, and look in the parent folder.
Explanation of Relative and Absolute Paths in Node.js
The default document root is set with the NODE_PATH environment variable (however it would be terrible practice to modify that). So baring that in mind ./ will resolve to the value of your project root.
And so let tmpfolder = require('./resources/tmp'); would resolve to
C:\Users\......\project_wrapper_folder\project_folder\resources\tmp as you have seen
A relative path is denoted by not starting with ./, so for example let tmpfolder = require('my-scripts/some-script'); would look in the current directory for another folder called my-scripts.
Following on from that ../ is relative to the current directory, but goes out one (to it's parent) and looks from there. You can go out two directories by doing ../../my-dir and so on (this is not great practice though, as it can get hard to manage if you have ../../../../../../)
Better method
You can use the __dirname constant in Node to locate the directory name of the current module.
e.g.
fs.readFile(__dirname + '/../foo.bar');
Useful Links
I think you'll find this article on Better local require() paths for Node.js very useful.
Also, for a bit of further reading, here is the official Node.js documentation on paths
The .. means the previous dir. So you are getting out from project_wrapper_folder and then add to the script dir resources\tmp and that way the project_wrapper_folder is no longer in the relative path.
Lets assume you are inside a folder called app.
when you use ../resources/tmp, it will come out of the app folder and will search for tmp inside resources folder.
when you use ./resources/tmp, it will look within the app folder for resources folder and tmp inside it.
../ points to the parent directory while ./ points to current working directory.
A dot basically means "go one folder back in the path"
So:
'./' points at the folder you are in.(in your case the folder common/)
'../' points at the folder that contains the folder you are in. (in your case the folder app/)

path.dirname on Windows path is giving `.`

I in electron am doing:
path.dirname('C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron\\main')
That path is the actual value of my __dirname. How come it is not giving me C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron? I want that main part chopped off.
Assuming main is a directory inside electron. Also assuming that you have some file called index.js inside main folder where you want to have the path of electron directory.
So, you can do path.join this way:
var mainFolderParentPath = path.join(__dirname, '../');
Your original file location:
C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron\\main\\index.js
__dirname will return
C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron\\main
and then inside path.join '../', will chop off the main folder from path. So, you will be left off with:
C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron
Well you obviously didn't read the docs for dirname. It states that it works like the Unix command dirname which "strips non-directory suffix from file name", thus you get the C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron.
What you are looking for is basename.
path.basename('C:\\Users\\Blagoh\\Documents\\GitHub\\Screeenshoter\\dist\\electron\\main') will give you main.

Require.js optimizer supposed to copy all files over into the output directory?

I am trying to integrate the r.js optimizer on the server side (Apache Sling) and face one problem: when resolving modules it always looks them up under the output directory (dir), not from within the source directory (baseUrl or appDir), doesn't find them and thus fails.
/project/build.js
({
name: "modules/main",
dir: "/target",
baseUrl: "/sources"
})
If you wonder, the root path / is inside the server's JCR repository, not a file system. Also I simplified the example a bit (hopefully without concealing the issue).
It will resolve and read the main file properly:
/sources/modules/main.js
require(["modules/foo"]);
However, when it now tries to resolve modules/foo, it tries to read it from /target/modules/foo.js instead of /sources/modules/foo.js as I would expect, which does not exist and the whole r.js execution fails and stops.
I tried using appDir and all kinds of combinations, but the issue is always the same. I am fairly sure it is not related to my integration code... AFAIU from documentation and googling around, it should either copy them to the target before building the optimized file or simply pick them up from the source directory automatically.
Am I supposed to copy all the raw source files to /target myself before running r.js?
Maybe the problem is that baseUrl=/overlay is different from build.js residing inside /project?
Maybe r.js also looks at the current working directory of the r.js process (which is so far undefined in my case)?
Can the output directory (dir) live outside appDir or baseUrl?
My require.js configuration looks like so:
({
appDir: "../app",
baseUrl: "js/lib", // means the base URL is ../app/js/lib
dir: "../app-built", //target
// offtopic, but a very handy option
mainConfigFile: "../app/config.js",
// I'm not 100% sure if it's equivalent to your version
// where you're not using "modules" and just "name"
modules: [{
name: "../some/main" // this is ../app/js/some/main.js
}]
})
Reading through https://github.com/jrburke/r.js/blob/master/build/example.build.js#L15 - it seems you do want an appDir specified if you want the files to be copied to the target dir before optimization.
To answer your other questions
you don't need to manually copy files over
baseUrl should point to the same place as baseUrl used in your app's config - however you have to adjust it depending on what appDir you choose to use (e.g. appDir="../app" and baseUrl="js/lib", or appDir="../app/js" then baseUrl="lib", etc.)
appDir and dir should be relative to the build config file - I don't know what happens when you use absolute paths
yes - output dir does (has to?) live outside appDir. BaseURL is within the appDir/dir (all these names are really confusing..)
I would say
use the "appDir" setting
try using "modules" like I did instead of just "name"
make "appDir" and "dir" relative paths to the build file if you can - these absolute paths might be what's breaking? because other than that the config looks very similar to the one I use
I know there's a different way of configuring it where your output is 1 file, which case the files are read from the source dir - but I haven't used that much myself.
Hope this helps.
Answering myself: I got it to work with the single output file approach using out instead of appDir or dir:
({
name: "modules/main",
baseUrl: "/sources"
out: "/target/out.js",
})
In this case it reads all the modules from the sources and creates a /target/out-temp.js which it then moves to /target/out.js when done.
This seems to suit my needs so far.

How to resolve a relative path in node?

Came across this situation recently - I have an environment variable for a directory path like so:
var fooDir = process.env.FOO_DIR;
and I want to make sure this directory exists with a synchronous mkdir (at some point later):
fs.mkdirSync(fooDir, mode);
however if the user has supplied the environment variable via a realtive ~/ path node cannot resolve it
export FOO_DIR='~/foodir'
is there a way in node to resolve this without invoking a child process exec call to the actual shell? currently my solution is to do a replace myself like so:
fooDir = fooDir.replace(/^~\//, process.env.HOME + '/');
just curious if someone has a better solution.
You have it right: ~ is expanded by the shell, not the OS, just like *. None of the C file functions that node.js wraps handle ~ either, and if you want this you have to do the replacement yourself, just as you've shown. I've done this myself in C when supporting config files that allow relative file paths.
However, you should probably handle the case where HOME isn't defined; I believe this happens with non-interaction logins with bash, for example, and the user could always choose to unset it.
You can convert it to absolute path with path.join:
const path = require('path')
const absolutePath = path.join(process.cwd(), relativePath)
Check out Rekuire, it is a node module that solves the relative paths problem in NodeJs.

Resources