Process.chdir() has no effect on require - javascript

Given the structure directory structure:
.
├── alpha.js
└── foo
└── beta.js
And file contents
alpha.js
module.exports = "alpha"
foo/beta.js
var cwd = process.cwd()
process.chdir('../')
var alpha = require('./alpha.js')
console.log(alpha)
process.chdir(cwd)
From within foo/beta.js. I'd like to be able to trick require into thinking that the current working directory is the project root. The example above does not work when the following is run.
node ./foo/beta.js
However if I switch over the code to within foo/beta.js to the following. Reading the file from the system and passing it to the npm module _eval.
updated foo/beta.js
var path = require('path')
var cwd = process.cwd()
process.chdir(path.join(__dirname, '..'))
var fs = require('fs')
var _eval = require('eval')
var alpha = _eval(fs.readFileSync('./alpha.js'))
console.log(alpha)
process.chdir(cwd)
This does work, which proves it should be possible with require as well. No matter where you run if from it will always require the file. node ./foo/beta.js or cd foo && node ./beta.js
Is there any way that I can prepend or set the directory that require uses from within the file?

From the node.js doc for require():
If the module identifier passed to require() is not a native module,
and does not begin with '/', '../', or './', then node starts at the
parent directory of the current module, and adds /node_modules, and
attempts to load the module from that location.
If it is not found there, then it moves to the parent directory, and
so on, until the root of the file system is reached.
From this, you can see that the current directory is not used in loading modules. The main takeaway here should be that modules paths are relative to the location of the current module. This allows modules to load sub-modules in a self-contained fashion without having to know anything about where the parent is placed in the directory structure.
Here's a work-around function that loads a module file descriptor from the current directory if the filename passed to it does not start with a path separator or a ..
var path = require('path');
function requireCWD(fname) {
var fullname = fname;
if (fname && fname.length &&
!path.isAbsolute(fname) &&
fname.charAt(0) !== '.') {
fullname = path.join(process.cwd(), fname);
}
return require(fullname);
}
Then, any filename you give to requireCWD that is not relative and does not start with a "." will be loaded relative to the current working directory. If you want to allow even "." and ".." to be relative to the current working directory, then you can remove that test for '.' from the function.

Related

Error: Cannot find module './src/handlers/buttons.js' after migrating all files to a ./src folder [duplicate]

Let's say I have this directory structure
/Project
/node_modules
/SomeModule
bar.js
/config
/file.json
foo.js
-
foo.js:
require('bar');
-
bar.js:
fs.readdir('./config'); // returns ['file.json']
var file = require('../../../config/file.json');
Is it right that the readdir works from the file is being included (foo.js) and require works from the file it's been called (bar.js)?
Or am I missing something?
Thank you
As Dan D. expressed, fs.readdir uses process.cwd() as start point, while require() uses __dirname. If you want, you can always resolve from one path to another, getting an absolute path both would interpret the same way, like so:
var path = require('path');
route = path.resolve(process.cwd(), route);
That way, if using __dirname as start point it will ignore process.cwd(), else it will use it to generate the full path.
For example, assume process.cwd() is /home/usr/node/:
if route is ./directory, it will become /home/usr/node/directory
if route is /home/usr/node/directory, it will be left as is
I hope it works for you :D

Avoiding relative require paths in Node.js

I prefer to import dependencies without lots of relative filesystem navigation like ../../../foo/bar.
In the front-end I have traditionally used RequireJS to configure a default base path which enables "absolute" pathing e.g. myapp/foo/bar.
How can I achieve this in Node.js?
What you can do is use require.main.require which would always be the module path of the starting file. See https://nodejs.org/api/modules.html#modules_accessing_the_main_module
This means, that when you run
const x = require.main.require('some/file/path/y')
It would require it based on the base path of your starting file (that was invoked , node app.js meaning the app.js file).
Other options include using process.cwd() to get the starting path of your app, but that would be depending on where you invoke your node process, not the location of the file. Meaning, node app.js would be different than of you would start it one level up, node src/app.js.
Just to add to the other answer, you can put this few lines in your main file:
(function (module) {
let path = require('path')
let __require = module.constructor.prototype.require
let __cpath = __dirname
module.constructor.prototype.require = function (str) {
if (str.startsWith('package:')) {
let package = str.substr(8)
let p = path.resolve(__dirname, package)
return __require(p)
} else {
return __require(str)
}
}
})(module)
It extends your require in such way:
if path begins with package: (i.e. package:src/foo/bar) it translates it to require('/absolute/path/to/your/app/src/foo/bar'),
if it doesn't start with package: then it behaves like a normal require would.

calling a function in another file in javascript using node.js

I have a problem, i am trying to create an object that i can use over and over in a separate javascript file. I have a file called foo.js and another file called boo.js. I want to create the object in boo.js In my server.js file i required foo.js, and it works fine i can access foo.js. I want to be able to access boo.js from foo.js. I keep getting errors when i require boo.js in foo.js and i cant access it. Is There a way to do this?
here is my code
//boo.js
var obj = function () {
return {
data: 'data'
}
}
module.exports = {
obj: obj
}
foo.js
//foo.js
var request = require('request');
var x = require('./modules/boo')
var random= function() {
return x.obj();
}
module.exports = {
random: random
}
If they are in the same directory you will want to require like so var x = require('./boo'). The ./ is relative to the current directory.
they are both in the same directory
In that case, you'll want to remove the modules/ from the path:
var x = require('./boo');
require() is aware of the current script's location and bases relative paths from the script's own parent directory.
The ./ at the start of the path will refer to the same directory as __dirname, which seems to be modules/.
console.log(__dirname);
// "/project-path/modules"
Including modules/ in the path will result in doubling it:
var path = require('path');
console.log(path.resolve(__dirname, './modules/boo'));
// "/project-path/modules/modules/boo"
(Side note: The fs module does not behave the same way. Relative paths for it are based from the current working directory or process.cwd().)

Obtaining path in nodejs

My Directory structure is something as below:
app/
server/
api/
user/
controller.js
images/
image1.jpeg
The problem is when reading image1.jpeg within controller.js I have to use a string like
var imagePath = __dirname + '/../../../images/images1.jpeg';
fs.readFile(imagePath, ()....
now the above works FINE. however what I don't like is this string '/../../../'
is there a better way to access files in the images/ folder ?
You could use path.relative. You'd probably want to save these as constants but you could do the following to make things more readable.
Pass in the path to your current directory as the first parameter and the path to the image itself from the same parent directory (in this case app) and it will return the relative path from the current directory to the image.
// returns '/../../../images/images1.jpeg'
var relativePathToImage = path.relative(
'/app/server/api/user',
'/app/images/images1.jpeg');
var pathToImage = __dirname + relativePathToImage;
Short of passing the path to app/images to the controller, that's about as good as you can do.
You could traverse the module.parent references until module.parent isn't set, if you can safely make assumptions about where your main script is. For example, if your main script is app.js inside app/, you could do something like:
var path = require('path');
var topLevel = module;
while (topLevel.parent)
topLevel = topLevel.parent;
topLevel = path.dirname(topLevel.filename);
var imagesBasePath = path.join(topLevel, 'images');
// ...
fs.readFile(path.join(imagesBasePath, 'images1.jpeg'), ...);
I use an npm module called node-app-root-path to help me manage my paths within the NodeJS application.
See:
https://github.com/inxilpro/node-app-root-path
To obtain the application's root path you would do require('app-root-path');
Example:
global.appRoot = require('app-root-path');
var imagePath = global.appRoot.resolve('server/images');
var img1 = imagePath + '/image1.jpeg';
fs.readFile(img1, ()....
Not sure whether is it a good idea or not but for this case I have stored the appRoot as a global variable and this is so that it will be available anywhere within my NodeJS application stack, even to some of my other NodeJs libraries.
There are many other usages noted in their documentation, have a look and see if it helps you too.

process.env.PWD vs process.cwd()

I am using Meteor JS...and within my Meteor app I am using node to query the contents of different directories within the app....
When I use process.env.PWD to query the contents of a folder I get a different result from when I use process.cwd() to query the results of a folder.
var dirServer = process.env.PWD + '/server/';
var dirServerFiles = fs.readdirSync(dirServer);
console.log(dirServerFiles);
//outputs: [ 'ephe', 'fixstars.cat', 'sepl_30.se1', 'server.js' ]
vs
var serverFolderFilesDir = process.cwd() +"/app/server";
var serverFolderFiles = fs.readdirSync(serverFolderFilesDir);
console.log(serverFolderFiles);
//outputs: [ 'server.js' ]
using process.cwd() only shows server.js within the Meteor.
Why is this?
How is process.cwd() different from process.env.PWD?
They're related but not the same thing.
process.env.PWD is the working directory when the process was started. This stays the same for the entire process.
process.cwd() is the current working directory. It reflects changes made via process.chdir().
It's possible to manipulate PWD but doing so would be meaningless, that variable isn't used by anything, it's just there for convenience.
For computing paths you probably want to do it this way:
var path = require('path');
path.resolve(__dirname, 'app/server')
Where __dirname reflects the directory the source file this code is defined in resides. It's wrong to expect that cwd() will be anywhere near that. If your server process is launched from anywhere but the main source directory all your paths will be incorrect using cwd().

Categories

Resources