How to override a method in Node.js? - node.js

I have a module that defines functions that will be shared by other modules. Some of those functions need to be overridden. This is what I was thinking, but it doesn't work:
// shared_module.js
module.exports = {
alternativeFun() {
exports.doSomething()
sharedFun()
},
sharedFun() {
console.log('shared')
}
}
// alternative_module1.js
module.exports = {
doSomething() {
console.log('alternative 1')
}
}
// alternative_module2.js
module.exports = {
doSomething() {
console.log('alternative 2')
}
}
// main.js
const shared1 = require('./shared_module')
shared1.doSomething = require('./alternative_module1').doSomething
shared1.alternativeFun()
const shared2 = require('./shared_module')
shared2.doSomething = require('./alternative_module2').doSomething
shared2.alternativeFun()

Setting module.exports does not magically change the value of exports. You will need to also assign it to the same value (module.exports = exports = ...) if you want to use it inside your module's functions.

Related

webpack require expression missing modules

From webpack documentation, when a require expression is not known at compile time, it should generate a context module and include all the modules that could match the expression.
const handlers = {};
for (const name of Object.keys(SomeObject)) {
try {
handlers[name] = require(`./${name}.js`);
} catch {} // eslint-disable-line no-empty
}
module.exports = handlers;
however, what I get is `
const handlers = {};
for (const name of Object.keys(SomeObject)) {
try {
handlers[name] = require(`./${name}.js`);
} catch {} // eslint-disable-line no-empty
}
module.exports = handlers;
however, what I actually get is this error Cannot find module ./\u001a.js
but if I turn it into a dynamic import expression then it works
const handlers = {};
for (const name of Object.keys(SomeObject)) {
try {
import(`./${name}.js`).then(m => { handler[name] = m; });
} catch {} // eslint-disable-line no-empty
}
module.exports = handlers;
But I would prefer not to do that since the offending code is from some node package

node.js adding new export field without braking existing requires

Consider following simple scenario, file config.js:
const config = {
a: '123'
}
module.exports = config;
and it's usage:
const cfg = require('./conifg');
console.log(cfg.a);
Now I'm in need to add additional export member to config.js:
const config = {
a: '123'
}
function someFunction() {
console.log('blah');
}
module.exports = {
config,
someFunction
};
This modification brakes down so-far working code, because cfg.a in
const cfg = require('./conifg');
console.log(cfg.a);
points now to undefined.
Is there any way to extend module.exports while remaining it's "default" exported member to not brake things down?
you may export all property of config separately
module.exports = {
...config,
someFunction
};
or if you don't want use spread, you can access by
const cfg = require('./conifg');
console.log(cfg.config.a);
You can do it like this
const config = {
a: '123',
someFunction: someFunction
}
function someFunction() {
console.log('blah');
}
module.exports = config;

why module.export { ...require('module') } work but not module.export { require('module') }

justExport.js
const first = () => {
console.log('frist from justExport')
}
const second = () => {
console.log('second fromt justExport')
}
module.exports = {
first,
second,
}
tmp.js
module.exports = {
...require('./justExport') // work
require('./justExport') // SyntaxError: Unexpected string
}
main.js
const justExport = require('./justExport.js')
const tmp = require('./tmp.js')
console.log('Hello World!')
I have voluntarily create a fake example with the less possible code.
{ ...require('./justExport') } is object literal spread. While { require('./justExport') } is incorrect object literal syntax because it doesn't contain a key.
Unless the intention is to create shallow copy of justExport module, object literal isn't needed. It can be:
module.exports = require('./justExport');
To further clarify the answer from #estus, note that the following works due to ES6 shorthand property names:
const justExport = require('./justExport');
module.exports = {
...justExport, // works
justExport // works because key is implicitly defined by variable name
}

How to pass data to next middleware function in NodeJS

I'm writing my own implementation of middleware for a socket system. I've read through the source code of Laravel's middleware and some documentation on ExpressJS's implementation for inspiration.
However, I'm getting stuck on passing the data from one middleware handler to another.
I wrote a very basic example below. The output should be 4 but I don't know how to pass the output from one handler to the other. I'm guessing by setting a temporary variable, but I'm not sure how performant that is.
let each = require('lodash/each')
class Middleware {
constructor() {
this.handlers = [
function (data) {return data + 1},
function (data) {return data + 2}
]
}
}
class Router {
constructor() {
this.middleware = new Middleware
}
route(data) {
each(this.middleware.handlers, function(handler) {
handler(data) // no idea what to do here
})
}
}
class Socket {
constructor() {
this.router = new Router
}
write(data) {
return this.router.route(data)
}
}
let router = new Router
console.log(socket.write(1)) // should be 4
Change the route function inside Router class as following and the result of socket.write(1) will be 4:
class Router {
constructor() {
this.middleware = new Middleware
}
route(data) {
each(this.middleware.handlers, function (handler) {
data = handler(data)
})
return data
}
}

Pass 'this' to a class variable inside constructor

I am interested, how to pass this to a class variable inside a constructor of a parent, so I could use parents methods and access other variables of the parent and call their methods?
Here is my parent class:
var async = require('async');
var Rater = require('./rater')
var Similars = require('./similars')
var Suggestions = require('./suggestions');
module.exports = class Engine {
constructor() {
this.likes = new Rater(this,'likes');
this.dislikes = new Rater(this,'dislikes');
this.similars = new Similars(this);
this.suggestions = new Suggestions(this);
}
And here is the example of usage and where is get the following error:
Cannot read property 'engine' of undefined
at --\\classes\rater.js:89:19
module.exports = class Rater {
constructor(engine,kind) {
this.type = kind;
this.engine = engine;
if(kind == 'likes') //database schemes
this.db = Likes_db;
else if(kind == 'dislikes')
this.db = Dislikes_db;
else if(kind == 'similars')
this.db = Similars_db;
else if(kind == 'suggestions')
this.db = Suggestions_db;
}
//..
//other methods
//..
remove(user,item,done) {
this.db.remove({user: user,item: item},(err) => {
if(err)
return done(err);
async.series([
function(done) {
this.engine.similars.update(user,done); //error-cant enter the method
},
function(done) {
this.engine.suggestions.update(user,done);
}
],function(done) {
});
});
}
}
It has nothing to do with the constructor.
The problem appears because you are using a regular function as the callback and the context switches (you get another this in there).
Use an arrow function instead to keep the same context.
async.series([
(done) => {
this.engine.similars.update(user,done); //error-cant enter the method
},
(done) => {
this.engine.suggestions.update(user,done);
}
],function(done) {
});
Simply doing this works fine:
class Rather {
constructor(engine: Engine) {
engine.method();
}
}
class Engine {
constructor() {
new Rather(this);
}
method() {
console.log('ENgine');
}
}
new Engine();
You can see a working example here.
Note: As an OOP design decision though this is not very clean, you are introducing a cyclic dependency. Try going injection or at least introduce an interface to separate the 2 classes.
Try to define a _this var and then give it to parameter:
module.exports = class Engine {
var _this = this, _constructor = (<any>this).constructor;
constructor() {
this.likes = new Rater(_this,'likes');
this.dislikes = new Rater(_this,'dislikes');
this.similars = new Similars(_this);
this.suggestions = new Suggestions(_this);
}

Resources