Sharing constants between a web client and NodeJS server - node.js

I have a NodeJS application with common constants between the client and the server.
The constants are stored in variables rather than inline. Those variables could be defined in two separate files, one for client and one for server.
File 1:
// client_constants.js
MESSAGE_TYPE_A = "a";
MESSAGE_TYPE_B = "b";
File 2:
// server_constants.js
exports.MESSAGE_TYPE_A = "a";
exports.MESSAGE_TYPE_B = "b";
To avoid duplicate code I would like to store constants in a single location and a single format for both the client and the server. Wat do?

You can do something like this:
// constants.js
root = exports ? window
root.MESSAGE_TYPE_A = "a";
root.MESSAGE_TYPE_B = "b";
"exports" does not exist on the client side in which case it will use the default "window" object.

Sort of like Hector's answer, but works in my version of Node and in my browser because it uses comparisons to "undefined" and typeof.
var context = (typeof exports != "undefined") ? exports : window;
context.constant_name = "constant_name_string";

Related

How node-modules are implemented in node.js , how function implemention and creating instance are same in socket.io

const io = require('socket.io')();
// or
const Server = require('socket.io');
const io = new Server();
I am confused with following syntax
1) what is socket.io (is it a class or interface i checked the documention in node.js it showed be interface )
2)If it is interface i think we have to use class for using it (i didn't see any documentation to implement interface in javascript )
3) for understanding i tried the following (created 2 files)
example.js
module.exports = function () {
console.log("welcome to javascript");
}
use.js
let imp = require('./example')()
From following Link i have learned about require [https://nodejs.org/en/knowledge/getting-started/what-is-require/][1]
Now i am confused how socket is implemented and how the following 2 syntax's are equal
If socket is a function we can call by
const io = require('socket.io')();
If it is a class we generally do the following (create a instance and use it )
const Server = require('socket.io');
const io = new Server();
But in the documention they said both the syntax are equal how ?
One is for excuting the module.exports and one is used for instancing a class how both are equal
When you do this:
let x = require('someModule');
The value of x is whatever the module sets the module.exports value to in the module. It can literally be anything. It's entirely up to the module what they assign to that. It is often an object (with properties), but it can also be a function and sometimes it's even a function with properties.
To see what socket.io assigns to module.exports, we can go right to the source where we see:
module.exports = Server;
So, then we go look at what is Server and find this:
function Server(srv, opts){
if (!(this instanceof Server)) return new Server(srv, opts);
if ('object' == typeof srv && srv instanceof Object && !srv.listen) {
opts = srv;
srv = null;
}
opts = opts || {};
this.nsps = {};
this.parentNsps = new Map();
this.path(opts.path || '/socket.io');
this.serveClient(false !== opts.serveClient);
this.parser = opts.parser || parser;
this.encoder = new this.parser.Encoder();
this.adapter(opts.adapter || Adapter);
this.origins(opts.origins || '*:*');
this.sockets = this.of('/');
if (srv) this.attach(srv, opts);
}
From that, we can see that it is a constructor function that can be called as either:
const x = new Server(...);
or as:
const x = Server(...);
So, the answer is as follows:
require('socket.io') gives you a constructor function.
That constructor function can be caller either with new or just as a regular function and it adapts to return the same thing, a new server object.
So, when you do this:
const server = require('socket.io')();
it first gets the exported constructor function and then calls it and assigns the newly created object to the server variable.
1) what is socket.io (is it a class or interface i checked the documentation in node.js it should be interface )
socket.io on the server exports a constructor function for creating a server object. It can be called either as a regular function or with new.
2)If it is interface i think we have to use class for using it (i didn't see any documentation to implement interface in javascript )
It's a function. Javascript doesn't have a specific type called an interface. The socket.io code defines a constructor the older fashioned way (before the class keyword existed) though the outcome is largely the same. It defines a constructor function that, when called will create an object of the desired type.
3) Now i am confused how socket is implemented and how the following 2 syntax's are equal
In Javascript, these two different pieces of code create the same server object:
const io = require('socket.io');
const server = io();
and
const server = require('socket.io')();
The second is just a shortcut that doesn't assign the intermediate result from require('socket.io') to a variable, but rather just calls it directly. It will work like this only when the first function call returns a function. So, the first syntax gets a function, assigns it to the io variable and then calls it. The second syntax gets the function and immediately calls it without assigning it to a variable. In both cases the result of getting the function and calling it ends up in the server variable.

Nodejs naming conventions for modules

Given this pattern :
A module defines a public API, but needs runtime information.
// Contrived example for a module abstracting a db
module.exports = function (host, schema, ...) {
// A "module-level", private, instance of an object
// that will be used by the public API of the module
var connection = getConnection(host, schema, ...);
return {
queryItems : function (arg) {
// Something that uses both the "module" level instance
// and runtime args.
return connection.query(... arg ... );
}
}
};
Another module will have to require it, than "instanciate" the module, and
use it.
// Module "bar"
var db = require("db"),
xxx = db("myhost", "myschema");
xxx.queryItems("Test"):
In "traditionnal" OO, the first module would expose a class constructor, and by conventions those
have a first capital letter, so you would write
var Db = require("db"),
db = new Db("....", "....");
And there is not ambiguity ; the meaning of "var cat = new Cat()" is pretty accepted ; "var felix = new Cat()" would only be used in case of multiple instances.
Is there a "canonical" / "idiomatic" way, in nodejs, to name such a module exposing functions, and the object that was returned by this function ?
(Sorry if too subjective, I'm looking for the "established" convention rather than a "best" one.)

Configuring $.ajax with backbone on node for testing with vows

(Edited to greatly simplify)
On node I have the following server.js file.
var Backbone = require('backbone');
var Tweet = Backbone.Model.extend({});
var Tweets = Backbone.Collection.extend({
model : Tweet,
url: function () {
return 'http://search.twitter.com/search.json?q=backbone'
}
});
var myTweets = new Tweets();
myTweets.fetch();
When I run this, I get an error that says. "Cannot call method 'ajax' of undefined" (1359:14)
basically that is the result of $ being undefined. Why is it undefined? Well there are a number of intermediate steps but when the file is loaded, it is expecting "this" to be "window" in browser or "global" on server. executed on node "this" = {}.
So the question, "How do I set 'this' to global" inside the backbone.js file?
On Backbone >= 1.x, you can simply assign Backbone.$ rather than using Backbone.setDomLibrary.
Solution for Backbone < 0.9.9
The first issue you need to address is how you are running this on Node anyway. Nodejs is a server-side JS environment, but it does not include any logic for controlling a DOM. For that you need to load something like JSDom.
When you have some DOM environment set up, you can load jQuery and your code into it and it should work just like a browser.
To answer your question specifically though, loading jQuery into the global is a bit of an ugly way to do it. You should use Backbone's setDomLibrary function to set $ to what you want.
Try something like this:
if (typeof exports !== 'undefined') {
MyModels = exports;
Backbone.setDomLibrary(require('jquery'));
server = true;
} else {
MyModels = this.MyModels = {};
}
This will fail if you try to do any DOM functions though.

How to check express local variable exists when in script tag of jade?

I have a data variable sent to client-side, but it may not always be included as a variable in the express locals. If it doesn't exist, var data = !{JSON.stringify(data)}; returns var data = ; which causes a js error.
I've tried using conditionals prefixed with '-' but that doesn't seem to work.
script(type='text/javascript')
- if locals.data
var data = !{JSON.stringify(data)};
- else
var data = {};
How do I give it a default if locals.data is undefined?
Don't you hate it when you wrack your brain, then ask for help on SO, only to figure it out 5min later...
Looks like the following keeps the jade and javascript happy:
var data = !{ JSON.stringify(locals.data || '') };

How to use global variable in node.js?

For example I want to use custom logger:
logger = require('basic-logger'),
logger.setLevel('info')
var customConfig = {
showMillis: true,
showTimestamp: true
}
var log = new logger(customConfig)
How to use this logger in other modules instead of console.log ?
Most people advise against using global variables. If you want the same logger class in different modules you can do this
logger.js
module.exports = new logger(customConfig);
foobar.js
var logger = require('./logger');
logger('barfoo');
If you do want a global variable you can do:
global.logger = new logger(customConfig);
global.myNumber; //Delclaration of the global variable - undefined
global.myNumber = 5; //Global variable initialized to value 5.
var myNumberSquared = global.myNumber * global.myNumber; //Using the global variable.
Node.js is different from client Side JavaScript when it comes to global variables. Just because you use the word var at the top of your Node.js script does not mean the variable will be accessible by all objects you require such as your 'basic-logger' .
To make something global just put the word global and a dot in front of the variable's name. So if I want company_id to be global I call it global.company_id. But be careful, global.company_id and company_id are the same thing so don't name global variable the same thing as any other variable in any other script - any other script that will be running on your server or any other place within the same code.
you can define it with using global or GLOBAL, nodejs supports both.
for e.g
global.underscore = require("underscore");
or
GLOBAL.underscore = require("underscore");
I would suggest everytime when using global check if the variable is already define by simply check
if (!global.logger){
global.logger = require('my_logger');
}
I've found it to have better performance
Global variables can be used in Node when used wisely.
Declaration of global variables in Node:
a = 10;
GLOBAL.a = 10;
global.a = 10;
All of the above commands the same actions with different syntaxes.
Use global variables when they are not about to be changed
Here an example of something that can happen when using global variables:
// app.js
a = 10; // no var or let or const means global
// users.js
app.get("/users", (req, res, next) => {
res.send(a); // 10;
});
// permissions.js
app.get("/permissions", (req, res, next) => {
a = 11; // notice that there is no previous declaration of a in the permissions.js, means we looking for the global instance of a.
res.send(a); // 11;
});
Explained:
Run users route first and receive 10;
Then run permissions route and receive 11;
Then run again the users route and receive 11 as well instead of 10;
Global variables can be overtaken!
Now think about using express and assignin res object as global.. And you end up with async error become corrupt and server is shuts down.
When to use global vars?
As I said - when var is not about to be changed.
Anyways it's more recommended that you will be using the process.env object from the config file.
If your app is written in TypeScript, try
(global as any).logger = // ...
or
Object.assign(global, { logger: // ... })
However, I will do it only when React Native's __DEV__ in testing environment.
May be following is better to avoid the if statement:
global.logger || (global.logger = require('my_logger'));

Resources