Dealing with module inclusion in my NodeJS projects I always struggle a bit in the way of specifying paths to other module files of the project to be required.
I obviously use relative paths. But this implies doing things like:
const helper = require("../../lib/util/helpers.js
This has some drawbacks:
I always need to take in account where the file from which I requiring another module is placed.
As the project grows I occasionally need to move some files to another place due to project restructuring so I need to review not only paths from files requiring it, but also the paths of all modules required in the file I am moving.
I always thought it would be much clearer if I could specify paths relative to the project root instead of the file itself. To be clear, that is where my package.json
file (or node_modules
directory) is placed.
I know I can resolve the path of any external module using require.resolve()
and I though I could do something like path.dirname(path.dirname(path.dirname(require.resolve('express'))))
but it seems too dirty to me.
Unfortunately, as far as I know, there isn't any require.modules_path
or require.projectRoot
property so I need to rely on some trick like that I mentioned above or traversing the whole tree up to the first parent directory containing a package.json
file.
My question is: Is there any better solution which I am missing?
I approached an, even not perfect, acceptable solution by using a runtime Symbol to store project's root path as a property of the process
object.
Using a symbol to name that property we avoid any possibility of colliding with another
process
object properties, even with future ones.
What I did was simply adding this two lines to my app.js
(which in Express projects is placed in project root directory and required from the main app entry point bin/www
where I also ensured it is the first required dependency):
const $root = Symbol.for("projectRoot"); │ return new Promise(function (resolve, reject) {
process[$root] = __dirname;
After that, the only thing I need to do in all other modules is to repeat the first row at the very beginning:
const $root = Symbol.for("projectRoot");
...and use it in all require statements. For example:
const helper = require(process[$root]+"/lib/util/helpers.js
Maybe it is far from perfect, but it works for me...