What does it mean if you require('ssh2') in Node.js without a specific object (e.g. require('ssh2').Client)? I have some code I am trying to understand and I am just learning Node.js. It's used like this:
var ssh2Connection = require("ssh2");
...
var conn new ssh2Connection();
conn.on("ready", function() {
...
});
Requiring require("ssh2") is essentially returning the value defined by this line
module.exports = 'hello'
Requiring require("ssh2").Client is essentially returning the value defined by this line
module.exports.Client = 'hello'
This is used to extend multiple objects to a module. Could be something like
module.exports.Client1 = 'hello1'
module.exports.Client2 = 'hello2'
Related
Currently I am just passing my fileNamePrefix like that:
let shortid = require('shortid');
let fileNamePrefix = shortid.generate();
module1.run(fileNamePrefix); //generating a file based on `fileNamePrefix` `xxxxx.f1.json`
module2.run(fileNamePrefix); //generating a file based on `fileNamePrefix` `xxxxx.f2.json`
module3.run(fileNamePrefix); //generating a file based on `fileNamePrefix` `xxxxx.f3.js
Which I think in not quite right, I might need to pass more things to my modules later on, so I want to avoid to pass that as function params.
What is the best way to approach that in nodejs?
Will global object like global.fileNamePrefix = shortid.generate(); will do in that case or would you approach that different? I just read that global is not good...
You can use either singleton approach or approach suggested by #Сергей Тертичный
Singleton :
//shortid.js
var fileSingleTon = module.exports = {
fileNamePrefix: null,
getFileNamePrefix: function() {
return fileSingleTon.fileNamePrefix || fileSingleTon.generate()
},
generate: function() {
console.log('generating..');
return fileSingleTon.fileNamePrefix = 'your_file_prefix';
}
}
//module1.js
var fileNamePrefix = require('./shortid').getFileNamePrefix();
//do stuff for module1
//module2/js
var fileNamePrefix = require('./shortid').getFileNamePrefix();
//do stuff for module1
and so on..
Even now you are calling require('./shortid').getFileNamePrefix(); multiple times, generate function is getting called only once.
Node Caching approach :
Consider you have shortid.js as following :
// A: block of code to do some manipulations
// B : module.exports = manipulation result.
So basically in node js "modules" core module which is responsible for giving us module.export functionality executes whatever is here above export(in abode example the part A) only for the first time and caches it even if you have required in in multiple other files. However, it only executes the functions or block of code in every require which is inside export. So you can use this approach where your A block will have login to generate fileNamePrefix and then B just returns it.
Just create module like that:
// unicname.js
let shortid = require('shortid');
let fileName = shortid.generate();
module.exports = {fname: fileName};
//module1.js
const {fname} = require('./unicname.js');
....
Since the node.js caching the modules the value will be calculated only one time so you can get same value in all your modules.
I have the following simple test module (called testModule) in Screeps:
module.Exports = {
myProperty:'test'
};
In main, I try to output the contents of the module like so:
var x = require('testModule');
console.log("Value:" + JSON.stringify(x));
But all I get is an empty object ({});
As a result, x.myProperty is undefined. I have also tried making the module into a function, like so:
module.Exports = function(){
return {
myProperty:'test'
};
};
Then assigning it to x with var x = require('testModule')(); but I get the same result.
Obviously the game is still in development, so it is possible that this is a bug, but I'd like to rule out a mistake on my part first. Anyone been able to achieve what I'm trying to do? Anyone see what I'm doing wrong?
Edit
Interestingly, it gives me the same empty object even if I change the module to this:
module.Exports = 'test';
Surely this should be printing the string 'test' rather than an empty object? Is this a quirk of require js?
Just figured this out - I was using an uppercase E in module.exports. I have corrected the case and now it works fine:
module.exports = {
myProperty:'test'
};
If I have a javascript object, I would normally interact with the object and its methods like this:
var obj = someObject.getInstance();
var result = obj.someMethod();
where someMethod is defined like this:
someObject.prototype.someOtherMethod = function() { //do stuff };
someObject.prototype.someMethod = function(foo) { this.someOtherMethod(); };
However, I am getting an error when I want to call someMethod in Ruby via ExecJS:
context = ExecJS.compile(# the javascript file)
context.call('someObject.getInstance().someMethod')
# Gives a TypeError where Object has no method 'someOtherMethod'
On the other hand, functions that are defined in the javascript module are working fine:
someFunction = function() { // do stuff };
# in Ruby
context.call('someFunction') # does stuff
Can ExecJS handle Javascript objects and their methods, or am I only able to call functions with it?
With regards to the specific application, I am looking into https://github.com/joenoon/libphonenumber-execjs, but the parse function in Libphonenumber does not work for the above reason.
Discovered the answer through some experimentation. I managed to get the desired functionality by using context.exec() instead of call.
js = <<JS
var jsObj = someObject.getInstance();
var res = jsObj.someMethod();
return res;
JS
context.exec(js);
However, if your method returns a Javascript object, you have to serialize it first or otherwise parse the results so that it can be returned by ExecJS into a suitable Ruby object.
I think I'm badly misunderstanding how to use module.exports. It seems every module is overwriting what the last one spit out.
app.js:
var express = require("express")
, app = express()
, routes = require('routes')
, server = app.listen(1337, "0.0.0.0")
, io = require('socket.io').listen(server)
, redis = require("redis")
, client = redis.createClient();
var moduleA = require("./moduleA")(io, client); (need to pass socket.io and redis client)
var moduleB = require("./moduleB")(io, client); (same)
moduleA.js:
module.exports = function(io, client){
this.test = 'foo';
return this;
};
moduleB.js:
module.exports = function(io, client){
this.test = 'bar';
return this;
};
back to app.js:
console.log(moduleB.test); (prints "bar")
console.log(moduleA.test); (also prints "bar")
Could someone explain what I'm doing wrong? I can't think of any other way to do this, since the exports helper (?) itself doesn't seem to accept parameters.
You are exporting a constructor. You need to construct it, not call it.
Change
var moduleA = require("./moduleA")(io, client);
to
var moduleA = new (require("./moduleA"))(io, client);
or (for clarity)
var ModuleA = require("./moduleA");
var a = new ModuleA(io, client);
What you are seeing happen is the usual behavior when calling constructors as functions in sloppy mode: this references the global object. So of course modifying the global object from two locations will overwrite each other, and returning this will just return the global object. You can test this yourself: with your current code,
moduleA === moduleB === this === global
One way to prevent yourself from ever shooting yourself in the foot like this again is to use strict mode instead of sloppy mode. To do so, add the line
"use strict";
at the top of every module you write (before any other code). In strict mode, this for constructors called without new is undefined, so you will get an earlier and much easier-to-understand error.
Strict mode has many benefits of this sort; for an overview see [1], [2], [3].
An alternate solution is to stop using constructors altogether, but instead use factory functions. This would look like:
module.exports = function (io, client) {
var result = {};
result.test = "foo";
return result;
};
You seem to be trying to do something like this anyway, since you return this even though doing so in a constructor is entirely unnecessary. You could just stop using this and use an actual object under your control, instead of one whose semantics change depending on whether your function is being called or constructed.
I follow this pattern to organize my js application.
As that example says our application should has the single entry point. File application.js doing that work.
// Filename: application.js
var chat = {
// Create this closure to contain the cached modules
module: function() {
// Internal module cache.
var modules = {};
// Create a new module reference scaffold or load an
// existing module.
return function(name) {
// If this module has already been created, return it.
if (modules[name]) {
return modules[name];
}
// Create a module and save it under this name
return modules[name] = { Views: {} };
};
}()
};
// Using the jQuery ready event is excellent for ensuring all
// code has been downloaded and evaluated and is ready to be
// initialized. Treat this as your single entry point into the
// application.
jQuery(function($) {
$(document).ready(function(){
var foo = new Application.module('Chat').Collection();
});
});
// Filename: chat-module.js
(function(chat){
chat.Model = Backbone.Model.extend({ ... }),
chat.Collection = Backbone.Collection.extend({ ... }),
})(Application.module('Chat'));
It seems well but if try to define chat module for example and invoke it later I have the following error:
Uncaught TypeError: Property 'Collection' of object #<Object> is not a function
I think that error due jQuery ready invokes when chat-module.js not available yet.
How can I resolve that problem?
Your code creates an object and assigns it to the global variable chat, which has a module function as a property:
var chat = {
module: function...
};
...but then when you use it, you use Application.module rather than chat.module.
Application.module('Chat')
and
var foo = new Application.module('Chat').Collection();
It seems to me that your chat variable should be called Application.
Also note that you're using module in two different ways, both with new and without. Without would be the correct use based on your code. It will work both ways because module returns a function (which is an object), and so that will override the normal new behavior, but it means that using new serves no purpose and is misleading to someone reading the code.