The node.js Relative Path Case

Right now, it sucks because ___, as @izs told me to start with, I could not find a simple way to resolve a path from a module that exported a function into another one.
Spoiler: the reason I am trying to resolve paths is to load fresh modules runtime in polpetta. However, this might be a bad practice.
@WebReflection Lest I commit malpractice, I must tell you this is a terrible idea. Now warned, rock on with your bad self. Hack away :)
Still, my point is that it might be handy to be able to resolve paths relatively form the invoker regardless the why, even if you should always ask yourself that ;)
This case is quite easy to misunderstand so I'll skip extra explanations now and put down some code.

relative.js

This example file aim is to log ASAP two different path resolutions: the one from the path, passing through the process.cwd(), and the one from the relative.js file itself.

Object.defineProperties(this, {
parent: {
get: function () {
// used later on
return module.parent;
}
},
resolve: {
value: function (path) {
// it will resolve from this file
// not from the invoker
return require.resolve(path);
}
}
});

// path module resolves relatively
// from the current process.cwd()
console.log(require('path').resolve('.'));

// require resolves relatively from
// the current file
console.log(require.resolve('./relative.js'));
Running this from node terminal will most likely show something like:

require('./test/relative.js');
/Users/yourname/code
/Users/yourname/code/test/relative.js
Neither logs or resolution are actually OK if we would like to resolve relatively from that path.
If we would like to use that module method, talking about the resolve() one, we cannot trust the current path.

// will throw an error
require('./test/relative.js').resolve('./test/relative.js');

// will pass
require('./test/relative.js').resolve('./relative.js');
If we install that module through npm as global, or even local in some super folder, gosh knows where we should start the relative path resolution accordingly with the module itself, you know what I mean?

Being Relative To The Invoker Path

In order to be able to resolve relatively from the invoker, we need to know at least where is the invoker.
Thankfully, this is easy but be aware of the caching problem:

// relative.js
var
path = require('path'),
relativeDir = path.dirname(
module.parent.filename
)
;
this.resolve = function (module) {
return require.resolve(
path.join(relativeDir, module)
);
};
At this point we can invoke the method as expected without having erros, from the process folder.

// will log the right path
require('./test/relative.js').resolve('./test/relative.js');
Good, we are able to resolve module names, problem is ... only from the very first one that required relative.js due module caching so that module.parent will be one, and only one, for any other module.

A Hacky Solution

In order to avoid the caching problem within the required module itself, I came up with such trick at the end of the file:

// .. same content described above ...

// remove the module itself from the cache
delete require.cache[__filename];
In this way every single module that will require('./some-path/relative.js') will have a fresh new version of that module so that module.parent, and its filename, will be always the right one: how cool is that?
I am able to resolve relatively from any outer module its path the same way require.resolve(path) would do inside that module which is exactly needed and the goal of require-updated so that any module can use paths as if these were resolved from the file itself in order to require some other file, relative, absolute, or globally installed.
Still I believe there should be a better way to do this ... what do you say?

Comments

Popular posts from this blog

8 Things you should not be afraid of as a Developer

News

Why REST is so important