How to require a file relative to requirer? - node.js

I'm developing a library where I would like to load one or more files relative to the requirer. To better illustrate this:
// ~/app.js
import { horn } from 'unicorn'
horn.load()
// ~/node_modules/unicorn/horn.js
export default {
load() {
require('./user.config.js') // Here I would like to load the user config
// relative to "~/app.js"
}
}
I tried inspecting the global require and its parent property but it only give me a filename without more context.

Here's what you have available:
module.parent
This is the module handle of the first module to load this module. Because module handles are cached, this will only reflect the first module that loaded you.
module.filename
This is the fully qualified filename to a module. So, if you want the fully qualified filename of the parent module, you could use this:
module.parent.filename
If you just want the path of the parent module so that you could load something from that directory, then you can split off the path from the filename to get just the path using the path module.
path.dirname(module.parent.filename)
If you want to load a file from that directory, you could do this:
let fileToLoad = path.join(path.dirname(module.parent.filename), "user.config.js");
let config = require(fileToLoad);
You will have to remember the caveat above that module.parent only returns the very first module to load you because after that the module is cached and just the original module handle is returned (it is not reloaded).

Related

How do I use require inside a module with the parents context?

app.js
require('./modules/mod');
modules/mod/mod.js
modules.exports = () => {
require('./modules/secondmodule');
}
Essentially I want the above code to be able to require modules, but using the same context that itself was called from, e.g. another module in the same folder, without having to use relative paths.
I thought module.require() did this, but it seems to give me the same error that require() was after I moved my code into the separate module (mod.js).
edit:
I have since discovered I can use require.parent.module and it seems to be working. Please let me know if this is not advised.
require uses paths that are relative to current module. It's possible to do this by providing require from parent module:
modules.exports = parentRequire => {
parentRequire('./modules/secondmodule');
}
Which is used like:
require('./modules/mod')(require);
It's correct to use relative modules instead because child module shouldn't be aware of the context in which it's evaluated:
require('../secondmodule');
In case mod has to be decoupled from secondmodule, dependencies can be provided to it with some common pattern, e.g. dependency injection or service locator.
Secondary optional answer:
module.exports = () => {
module.parent.require('./modules/secondmodule');
}

Importing a file local to an npm module

I have a node module named redux-loop that I'm using, and I would like to modify one of its functions slightly.
It's not a very complicated file, so I've made a copy of it in my react-native app and made my changes. The original code requires a few exports from files inside the module, eg:
var { loop, isLoop, getEffect, getModel } = require('./loop');
var { batch, none } = require('./effects');
The problem is that my copy of this file cannot seem to get direct access to those files, so I can't import those symbols.
I've tried various combinations of things, such as:
var { loop, isLoop, getEffect, getModel } = require('redux-loop/loop');
var { batch, none } = require('redux-loop/effects');
…which conceptually would mean to me to require the loop.js file inside the redux-loop module, but apparently module loading doesn't work that way.
What's the best way for me to import theses symbols into this file?
If I understand your question and you're open to reapplying your changes to the source of the package, you could use npm edit <pkg> and modify the package directly. When your changes are done the package will be rebuilt with your modifications.

Check if the required module is a built-in module

I need to check if the module that is going to be loaded is a built-in or an external module. For example, suppose that you have a module named fs inside the node_modules directory. If you do require("fs") the built-in module will be loaded instead of the module inside node_modules, so I'm sure that this question has a solution.
Example:
var loadModule = function (moduleName){
if (isCoreModule (moduleName)){
...
}else{
...
}
};
loadModule ("fs");
process.binding('natives'); returns an object that provides access to all built-in modules, so getting the keys of this object will get you the module names. So you could simply do something like:
var nativeModules = Object.keys(process.binding('natives'));
function loadModule(name) {
if (~nativeModules.indexOf(name)) {
// `name` is a native module name
} else {
// ...
}
};
loadModule('fs');
you can use require.resolve.paths(str):
1- if str is core module the call will return null.
2- if str is not core module you will get an array of strings.
My first attempt would be: require.resolve(moduleName).indexOf('/') <= 0. If that is true, it's a core module. Might not be portable to windows as implemented, but you should be able to use this idea to get going in the right direction.
Aside: beware require.resolve does synchronous filesystem IO. Be careful about using it within a network server.
Aside: Careful with the term "native" which generally means a native-code compiled add-on, or a C/C++ implementation. Both "core" and community modules can be either pure JS or native.
I think "core" is the most accurate term for built-in modules.
Aside: best not to shadow global variable names, so moduleName instead of just module which can be confusing with the global of the same name.
Module.isBuiltin Added in: v18.6.0, v16.17.0
import { isBuiltin } from 'node:module';
isBuiltin('node:fs'); // true
isBuiltin('fs'); // true
isBuiltin('fs/promises'); // true
isBuiltin('wss'); // false

get path of the file the module is being called from?

Let's say I have a node.js module
module.exports = function () {
console.log(__filename);
}
And in the main file I call it like
var x = require('path/to/module');
x();
That gives me the path to the module file. For example if I stored the module at ~/project-root/lib/mod.js and the main.js file lies at ~/project-root/main.js, that setup gives me the output:
~/project-root/lib/mod.js
I want to use something in place of __filename in the module that gives me to location of of the file from which it was called from. (e.g. the output would be ~/project-root/main.js instead, in this example).
The module can be located anywhere. So using path to adjust for only this example would fail in other scenarios (for example if module is stored in ~/project-root/node_modules/ or the global node.js modules directory.
I have a feeling it's something fairly trivial and I'm overlooking something. But I haven't found a solution from anything Google has yielded during an hour long search. Maybe I'm using the wrong keywords!
Module.parent called in your module lets you access to the exports of the file it was called from.
You can put the function below in your main.js and you can call module.parent.filename() in your module.
module.exports.filename = function () {
return __filename;
}

Nodejs importing multiple classes with modules.export from multiple source files

I have a directory with multiple js source files that is imported on client side webpage. I am also needing to import all of those sources files into server side node js app.
I have used the following approach so far
if( 'undefined' != typeof global ) {
module.exports = global.Class= Class;
}
The code is appended to the end of the source file
However I need to avoid editing the source files. Is there a good approach of how to import all of the classes contained the source folders? Instead of just running through the source files and having a modules.exports for each class? Also is there a way to give a directory to the require() call and have it import all the contained source files?
By exporting the objects into the global namespace you are kind of going against best standards in Javascript. The point in the module.exports is so that you can use requireJS to import the object that you need, rather than have every object available to you. So I'm afraid the answer is no, the require call only accepts single module references (due to the return value of the function assigning the object to a variable).
The 'good' approach would be to include a single file on the client that holds your main cilent code that references the modules/objects it needs to continue working. The source files will then be included as and when they are needed.
If you could modify the client side files, you could use this pattern: http://caolanmcmahon.com/posts/writing_for_node_and_the_browser/
file: tool.js
(function(exports) {
exports.Hello = function(name) {
console.log('Hello %s', name);
}
})(exports || window);
file index.js
require('./tool').Hello('username');

Resources