require.resolve() works. Why doesn't module.parent.require.resolve()? - node.js

I'm trying to find the file of included modules. From the main module, require.resolve('module') happily returns me the value of the main key from the module's package.json.
However, I would like to do this from a module that's been included via npm. If I simply call require.resolve('module'), it looks in the node_modules for this module, whereas I need to resolve it from the point of view of the running package.
According to the docs, require is actually module.require and module.parent returns the module that first required this one. Why then does module.parent.require.resolve('module') not work? I get ana
error:
TypeError: module.parent.require.resolve is not a function
Oddly though, console.log module.parent.require.toString() returns
function (path) {
assert(path, 'missing path');
assert(typeof path === 'string', 'path must be a string');
return Module._load(path, this, /* isMain */ false);
}
so it certainly looks like a function to me.
Anyone know what's going on? I've also tried require.main.require.resolve() and that does a very similar thing.

TypeError: module.parent.require.resolve is not a function
Oddly though, console.log module.parent.require.toString() returns ...
module.parent.require is a function, module.parent.require.resolve is not.
Why is resolve() not a function?
It appears require() and module.require() are not the same:
console.log(require === module.require); // false
For the curious:
console.log(module.require.toString())
function (path) {
assert(path, 'missing path');
assert(typeof path === 'string', 'path must be a string');
return Module._load(path, this, /* isMain */ false);
}
console.log(require.toString())
function require(path) {
try {
exports.requireDepth += 1;
return mod.require(path);
} finally {
exports.requireDepth -= 1;
}
}
So require() calls module.require(), but is not the same thing.
What about resolve()?
We know require.resolve is a function:
console.log(require.resolve.toString())
function resolve(request) {
return Module._resolveFilename(request, mod);
}
But module.require.resolve is not:
console.log(module.require.resolve)
undefined
So unfortunately resolve() is only available at require.resolve(), and not at module.require.resolve() (or module.parent.require.resolve() for that matter).
Solution?
Not a great solution, but you could try manually calling Module._resolveFilename() and passing in the parent module instead of the current module:
const Module = module.constructor;
const fileName = Module._resolveFilename('module', module.parent);
This solution isn't great because it relies on internal API functions that could possibly change in the future. It would be nice if NodeJS would provide better documentation and APIs for module loading/resolving.

Related

How Node.js implements require() in its own internals?

While going through the source of require() in the GitHub repository for Node.js, I am surprised and confused by one thing:
The file loader.js that actually defines the require() logic, uses require() calls in itself.
How is this possible?
Is there some other code for the require() calls used in the internals of Node.js, for e.g. all the require() calls used in loader.js file.
I know that all require() calls in a Node.js program that I write in a given editor, on my machine, are resolved using the Module.prototype.require method declared in loader.js.
It seems like the actual base require is defined here, in /internal/bootstrap/loaders.js. This line makes use of [compileFunction][3] in /lib/vm.js. That again uses _compileFunction which is defined as such:
const {
ContextifyScript,
MicrotaskQueue,
makeContext,
isContext: _isContext,
constants,
compileFunction: _compileFunction,
measureMemory: _measureMemory,
} = internalBinding('contextify');
Which, if we go back to /internal/bootstrap/loaders.js, is defined as such:
let internalBinding;
{
const bindingObj = ObjectCreate(null);
// eslint-disable-next-line no-global-assign
internalBinding = function internalBinding(module) {
let mod = bindingObj[module];
if (typeof mod !== 'object') {
mod = bindingObj[module] = getInternalBinding(module);
ArrayPrototypePush(moduleLoadList, `Internal Binding ${module}`);
}
return mod;
};
}
And getInternalBinding we find at the top of that file, in this comment:
// This file is compiled as if it's wrapped in a function with arguments
// passed by node::RunBootstrapping()
/* global process, getLinkedBinding, getInternalBinding, primordials */
Which brings an end to our tour here. So yes, there's still some code between the require() defined in loader.js and the actual C binding. As for what happens in C-land, I'm not sure myself.

modify nodejs require() to search for .min.js

O/S is ubuntu 16, node version is 4.2.6.
I have source / development code and run / distribution code, the source.js files are minified and mangled to create equivalent source.min.js files, and I would like for node js require to automatically search for .min.js files as well as .js files.
But as I have a lot of files, I would prefer not to have to go through every require in every file and instead modify the built-in require() function.
This is a very simple implementation of a stand alone function, but how can I modify the built-in function to behave the same way ?
function require(file){
try{return require(file)}
catch(e){return require(file+='.min.js')}
}
You can achieve this by modifying prototype function require of Module class and apply it globally
Here is how you can do it :
var pathModule = require('path');
var assert = require('assert').ok;
module.constructor.prototype.require = function (path) {
var self = this;
assert(typeof path === 'string', 'path must be a string');
assert(path, 'missing path');
try {
return self.constructor._load(path, self);
} catch (err) {
// if module not found, we have nothing to do, simply throw it back.
if (err.code === 'MODULE_NOT_FOUND') {
throw err;
}
// resolve the path to get absolute path
path = pathModule.resolve(__dirname, path+".min.js")
// Write to log or whatever
console.log('Error in file: ' + path);
}
}

Calling a module function inside a Nodejs callback

I have a module that writes to a log file. (coffeescript sorry, but you get the idea!)
require = patchRequire(global.require)
fs = require('fs')
exports.h =
log: ()->
for s in arguments
fs.appendFile "log.txt", "#{s}\n", (e)->
if (e) then throw e
It works file when I call it directly. But when I call it from a callback, for example casperjs start event:
h = require('./h').h
casper = require('casper').create()
casper.start "http://google.com", ()->
h.log("hi")
casper.run()
... I always get this or similar "undefined" TyepError:
TypeError: 'undefined' is not a function (evaluating 'fs.appendFile("log.txt", "" + s + "\n", function(e) {
if (e) {
throw e;
}
})')
Googling this doesn't give many clues!
CasperJS runs on PhantomJS (or SlimerJS) and uses its modules. It is distinct from nodejs. PhantomJS' fs module doesn't have an appendFile function.
Of course you can use fs.write(filepath, content, 'a'); to append to a file if used in casper. If you still want to use your module both in casper and node then you need to write some glue code like
function append(file, content, callback) {
if (fs.appendFile) {
fs.appendFile(file, content, callback);
} else {
fs.write(file, content, 'a');
callback();
}
}
I think the problem is with the coffeescript. Try using a splat parameter instead of relying on the arguments object.
log(statements...)
If that doesn't work, you might need to look at the javascript output or try the same thing in plain JavaScript and see if you get the same error.

RequireJS dependency is undefined if I name the module

I'm using Durandal, and I'm trying to use this module as a dependency for another module:
define('Beer', function () {
return function Beer (name, brewery) {
this.name = name;
this.brewery = brewery;
};
});
In the other module, I do this:
define(['knockout', 'models/Beer'], function (ko, Beer) {
return {
displayName: 'Add',
name: ko.observable(),
brewery: ko.observable(),
save: function () {
var beer = new Beer(this.name(), this.brewery());
console.log(beer);
}
}
});
My javascript is loaded, because I define it in my paths (and I checked in Firebug). But the Beer argument in my second module is undefined. I don't know why, as my Beer module does return something (it returns the function). What else can I look at? Most solutions I find are that the (first) module isn't returning anything, but mine clearly is.
UPDATE
Apparently, when I remove the name of my Beer module, it works:
define(function() {
return function Beer (name, brewery) {
// ...
}
});
Even though this code would seem to work, it doesn't for me. Can anyone tell me why?
You are mixing named modules with anonymous modules in your approach.
If you name the module 'Beer', you require it using the name, not the path:
require(['Beer'], function (Beer) {
var a = new Beer();
});
If you remove the name from the Beer module, you have an anonymous module which you can load by path:
require(['path/to/Beer'], function (Beer) {
var a = new Beer();
}
Edit: the topic you linked to does not use RequireJS, even though it looks similar.

Node.js customize require function globally

I am trying to modify require like this
require = function (path) {
try {
return module.require(path);
} catch (err) {
console.log(path)
}
}
However, scope of this modification is only in the current module. I want to modify it globally, so every module that is required by this module will also get the same copy of require function.
Basically, I want to catch SyntaxError to know which file has problem. I can't seem to find any other alternative. If I put module.require in try/catch block, I'll be able to get the file name which caused SyntaxError.
I managed to solve it by modifying prototype function require of Module class. I put this in the main script and its available to all the required modules.
var pathModule = require('path');
var assert = require('assert').ok;
module.constructor.prototype.require = function (path) {
var self = this;
assert(typeof path === 'string', 'path must be a string');
assert(path, 'missing path');
try {
return self.constructor._load(path, self);
} catch (err) {
// if module not found, we have nothing to do, simply throw it back.
if (err.code === 'MODULE_NOT_FOUND') {
throw err;
}
// resolve the path to get absolute path
path = pathModule.resolve(__dirname, path)
// Write to log or whatever
console.log('Error in file: ' + path);
}
}
Why don't you use a try-catch block inside your code and once an error occurs to check the stack trace. Check out these links
How to print a stack trace in Node.js?
http://machadogj.com/2013/4/error-handling-in-nodejs.html

Resources