Node js how to have leading period path? - javascript

I have a path to run e.g: ./abc/def/myshell.sh
I use path.join like this
path.join('.', 'abc', 'def', 'myshell.sh');
but it removes the leading period.
How can I keep it? Is there any other function?

Depending on whether you want the current working directory or the directory the script is is, you should use process.cwd() or __dirname as the first parameter to path.join.
I ran across the same issue setting up a gulp build, where I needed to include a file from the script's directory. Using path.join seems to optimize out certain path segments, so ./ is discarded even if it's the first part of the path (and would be significant).
To avoid that, anything that provides an absolute path (cwd or dirname) can be passed instead, forcing a full path to be built.

Related

How does Nodejs handle relative paths?

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.

Node.js require local file throws an error

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.

Call other Webpack loaders from within a loader

I am writing a Pug dependency loader. Basically it will just output an identical Pug file, except that require() calls will be replaced with a path to the file they are requiring. Obviously, therefore, I need to take that path and hand it off to the Webpack loader chain so that it will be handled in whatever way is appropriate, e.g. by using file-loader to copy an image file to its appropriate location.
Everything's working except for this part. I can't figure out how to pass the path to Webpack to be loaded. To be clear, I want the same sort of thing to happen as when you require() a file in your Webpack entry file - Webpack should take the path, run it through the list of possible loaders, and handle it appropriately.
I have tried just using a require() call, I've tried this.resolve() and this.loadModule() but none have worked. Since this.resolve() accepts a context as its first argument, I have carefully given it the appropriate context of my /src folder. The image is at /src/images/image.jpeg, and yet it actually gives an error that it cannot resolve that path, even though it is correct, so I'm not sure what I'm doing wrong or how to make this work.

How do I load a node module as if the current module were located somewhere else?

I have some nodejs code running in a module somewhere. From this module, I would like to load a module located in a completely different place in the file system -- for example, given the path "/another/dir" and the module name "foo", I would like Node to act as if a module running in /another/dir had called require("foo"), rather than my own module.
My code is running here
/some/folder/node_modules/mine/my_module.js
I have the path "/another/dir/", the string "foo",
and want to load this module
/another/dir/node_modules/foo/index.js
In other words, the module documentation refers to the process "require(X) from module at path Y", and I would like to specify my own value for Y
Can this be accomplished? If so, how? If not, why not?
The simplest, is just to resolve the path into an absolute path, this will be the recommended approach for most if not all cases.
var path = require('path');
var basedir = '/another/dir';
var filename = 'foo'; // renamed from dirname
var filepath = path.join(basedir, 'node_modules', filename);
var imports = require(filepath);
If you really need to make require act as if it is in a different directory,
you can push the base directory to module.paths
module.paths.unshift('/another/dir/node_modules');
var imports = require('foo');
module.paths.shift();
module.paths can also be modified externally via the environment variable NODE_PATH, tho that would be the least recommended approach but this does apply it globally across all modules.
A symlink with npm link
To avoid problems or modify source code I would use npm link, from your example:
First:
cd /another/dir/node_modules/foo # go into the package directory
npm link # creates global link
This will create a global link for the foo module, on Linux you need root permissions to do this.
Then:
cd /some/folder/ # go into some other package directory.
npm link foo # link-install the package
/some/folder/package.json should contain foo as a dep, is not mandatory, without it you get an extraneous warning with npm ls:
"dependencies": {
[...]
"foo": "*"
}
No symlink with local NODE_PATH
You don't like symlinks ? You can still use NODE_PATH but locally instead setting a global variable as #rocketspacer suggested, because as he rightly stated, it's not recommended to use it globally.
Note: In any case I would use a User variable and not a System-wide variable, a co-worker could log with a different username on the same machine and still get a modified NODE_PATH.
But to do this locally for just one invocation on Linux you can simply call:
NODE_PATH=$NODE_PATH:/another/dir/node_modules npm start
It will use that NODE_PATH only for that invocation.
Same one time invocation on Windows:
#ECHO OFF
SET BASE_NODE_PATH=%NODE_PATH%
SET NODE_PATH=%BASE_NODE_PATH%;C:\another\dir\node_modules\
node index.js
SET NODE_PATH=%BASE_NODE_PATH%
And...
You could also use a local dep like:
"dependencies": {
"foo": "file:/another/dir/node_modules/foo"
}
But would require an npm install and it would copy the content of foo in the current package node_modules folder.
It's quite easy to achieve, just add absolute paths to module object
in your current script /some/folder/node_modules/mine/my_module.js add this
module.paths.push('/another/dir/node_modules');
//this must be absolute, like /Users/John/another/dir/node_modules
var foo = require('foo');
For demo, open node in terminal, and type module.paths, it will show all the path node will search for require, you just add your path
"require(X) from module at path Y"
Means calling require(X) from within a file located at path Y. So you practically can't change Y.
Although the above solutions work (modifying module.paths & requiring absolute path), you'll have to add those snippets to every file in your project where you need requiring the foreign modules.
Even more, modifying module.paths is not officially supported. So it's not guaranteed to work in future updates of node
Introducing NODE_PATH
NODE_PATH is an environment variable that is set to a colon-delimited list of absolute paths.
Within those absolute paths, Node.js will search for a module that matches your require statement when all else has failed (Having indexed node_modules up to File System Root and still no match was found)
It is officially supported, although not recommended as it goes against convention (Your co-worker may not be aware of the NODE_PATH usage as there is no descriptive way of telling that in your project itself)
Notes:
On Windows, NODE_PATH is delimited by semicolons instead of
colons.
Node doesn't look for node_modules within those paths like
its default behavior, so your paths should be exactly where you
contain needed modules. For example: "/another/dir/node_modules"
Detailed information can be found on NodeJs official document:
https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
For those of you who are unaware of what environment variables is and how to set them, I have a windows screenshot that will get you started
In simple lines, u can call your own folder as module :
For that we need: global and app-module-path module
here "App-module-path" is the module ,it enables you to add additional directories to the Node.js module search path And "global" is, anything that you attach to this object will b available everywhere in your app.
Now take a look at this snippet:
global.appBasePath = __dirname;
require('app-module-path').addPath(appBasePath);
__dirname is current running directory of node.You can give your own path here to search the path for module.

getting jquery load/get use the current require.js path

require.js allows to smartly redefine the "include path" so that you can decide to install your dependancies into arbitrary sub-directories, transparently for them.
Well, this is true for the recursive require() these might do, but unfortunately it doesn't seem to work for the jquery load/get they might do: these still refere to html path, so that datas cannot be moved together with their lib.js.
how to make jquery load/get refer to this current require path ?
or am I missusing require.js features ?
thanks !
You can use toUrl for this. (Documented: go here in the documentation and search for toUrl.)
You need to have require as a dependency of your module (define(["require", ...], function (require, ...) {...) and then you call require.toUrl(path) where path is a path relative to your module. This call will return a path which is the same as if the path argument were a module's path defined in your RequireJS configuration. In other words, it is a path which will be relative if your baseUrl in your configuration was relative, or absolute if baseUrl is absolute. At any rate, you should just be able to feed it to $().load or $.get.

Categories