Any reason not to bind configurations to global object in Node.js? - javascript

I am looking for the best way to employ global configuration settings in my Node applications. In order of (my) preference the ways i have found are:
Attach config to global object
global.config = {
db: require('./config/db'),
server: require('./config/server'),
session: require('./config/session'),
auth: require('./config/auth')
};
Pass config object to modules that need it.
var config = {
db: require('./config/db'),
server: require('./config/server'),
session: require('./config/session'),
auth: require('./config/auth')
};
var responder = require('./responder')(config);
Require config files in each module. Since I usually split my config into seperate files I really do not like doing this. Since I dont always use certain files this also usually involces checking if files exist.
Is there any reason why one should avoid either of these methods? Is there any reason why one should be preferred over the others?

In my experience it is common use and good style to go with the option No. 2: Pass config options to modules that need it you suggested.
Reasons:
It decouples configuration from actual logic. If you include configuration files within
the module itself, there's a needless dependency to one specific configuration file.
There's still a defined dependency on specific configuration values which are provided as parameter - and not "magically" pulled from a global namespace which makes code hard to read, maintain and test.
This is by the way a rule of thumb for almost every language that allows things like global variables/objects and constructs for including "everything you like everywhere you like". But requirejs already pushes you a bit into the right direction by at least allowing exports to be a function that immediately accepts configuration. So the one-liner is an elegant way for requiring and configuring resources.
Everything beyond that would probably end up in a discussion about dependency injection (DI) concepts - which is a separate topic.

For small project all three ways are acceptable. For big I can say next:
Global variable is a problem
If you start to use this way, you need to defend config object like var config = {...}; config.freeze();. In any cases global variables is a bad practice, for NodeJS especially, because it destructs modular system.
Passing config is the best way
That is the reason? TESTING
In tests you need to get some states of your config file. The first and third ways provides you next code style:
config.js
module.exports= {
a: 10
};
app.js
var config = require('config');
module.exports.func = function(){
if (config.a > 10) return 'A';
return 'B';
}
Mocha+Chai test
var expect = require('chai').except,
config = require('config'),
app = require('app');
describe('Func', function(){
it('return "A" if a > 10', function(){
config.a = 12; //DHOOO!!! (c) Homer Simpson
expect(app.func()).to.equal('A');
});
it('return "B" if a <= 10', function(){
config.a = 9;
expect(app.func()).to.equal('B');
});
config.a = 12; //return default state of config. DHOOO!!!
});
How you can see you need to have editable config, that is a bad practice (big project where each developer can change state of config in any place... DHOOO!!!)
And for second way it looks like this:
config.js
var config = {
a: 10
};
config.freezy();
module.exports = config;
app.js
module.exports.func = function(config){
if (config.a > 10) return 'A';
return 'B';
}
Mocha+Chai test
var expect = require('chai').except,
app = require('app');
describe('Func', function(){
it('return "A" if a > 10', function(){
expect(app.func({a:12})).to.equal('A');
});
it('return "B" if a <= 10', function(){
expect(app.func({a:9})).to.equal('B');
});
});
UPDATE
In this example func is very syntetic, for real project you can see something like this:
module.js
var SubModule = require('submodule');
function MyModule(config, someVar) {
//Don't use full config, only options you needed.
//Pull out config options
this._a = config.a;
this._b = config.b;
this.doSomethink(someVar);
this.subModule = new SubModule(config);
}
MyModule.prototype.doSomething = function(){
if (this._a > 10) return 'A';
return 'B';
}
module.exports = MyModule;`
submodule.js
function MySubModule(config) {
this._c = config.c;
}
module.exports = MySubModule;

Related

How to use this in javascript module pattern?

I'm studying module pattern and have a question.
I want to use 'settings' anywhere.
script1.js
var MODULE = (function() {
var t = {};
this.settings = { // this == Window
users: ['john', 'emma']
}
return t;
})()
script2.js
MODULE.dom = function() {
var t = this; // this == MODULE
document.querySelector('p').textContent = t.settings.users[0]; // error
function _say() {
return t.settings.users[1] // error
}
return {
say: _say
}
}
MODULE.DOM = MODULE.dom.call(MODULE)
When use this.settings = {...}, 'this' means Window so code doesn't work.
When use t.settings = {...}, 'this' means MODULE so code works but when write MODULE in dev console, settings is exposed in MODULE variable. Is it ok?
I'd greatly appreciate any help, thank you!
When use t.settings = {...}, 'this' means MODULE so code works
That's the right way to do it.
but when write MODULE in dev console, settings is exposed in MODULE variable. Is it ok?
It's mostly OK.
If you're worried about the client being able to type in the variable name and see the code that gets run - there's no way to avoid that. They can just look at the devtools to see what the network requests are, and what is downloaded - or look at the Sources panel.
If you're worried about running into naming collisions with larger scripts, then - sometimes, libraries deliberately assign themselves to the window to allow other parts of the code to access them. Perhaps you'd like your MODULE to be like this. If not, then you should utilize JavaScript modules instead, which allow for scripts to be imported inside other scripts without polluting the global namespace at all or having any possibility of naming collisions. For example, you could do
// script1.js
export const MODULE = {
settings: {
users: ['john', 'emma'];
}
};
// script2.js
import { MODULE } from './script1.js';
// proceed to use MODULE
And you can do import { MODULE } from './script1.js'; from any script file, not just script2.js.
Personally, I consider the IIFE module pattern in JavaScript to be mostly obsolete nowadays. For any reasonable-sized script, better to write code in separate files and then import and export as needed. (A 1000 line file is somewhat hard to debug and refactor. Ten 100 line files are easier to debug and refactor.)

How to set environment variables like test environment for playwright-cucumber js

I've been using Playwright with Cucumber for e2e-automation of a react web application. This repo has been my starting point and it's been working out pretty good.
However, I'm looking for pointers on how to run these tests on different test environments - like development or QA, so that the target urls and other params vary as per the environment passed. For eg -
if (env == dev){
baseurl = dev_url
}
else{
baseurl = qa_url
}
The Cucumber documentation mentions the World parameter - an this issue looks like a similar issue, however I'm skeptical of passing a different JSON for this task.
Can this be achieved only at a Cucumber level or is there a Playwright or Node way of doing this?
As you are already using cucumber, define your world file like this:
First you can segregate your properties files into: properties-dev.json and properties-qa.json. Below code reads properties file based on env we are passing in defaultOptions object and stores entire properties file data into 'this'. Use 'this' in your hooks file and call this.keyNameForUrl to get url specific to environment.
Note: 'this' can be accessible only in world and hooks files (refer // https://github.com/cucumber/cucumber-js/blob/master/docs/support_files/world.md). If you need this data in other files, create a separate class and declare all public static varibles in it. In Hooks BeforeAll function, reassign values from 'this' to the static variables created in the class.
import { setWorldConstructor } from 'cucumber';
const fs = require('fs');
const defaultOptions = {
env: 'qa'
};
function processOptions(options) {
let envFile = 'properties-' + options.env + '.json';
let environment = JSON.parse(fs.readFileSync(envFile));
return Object.assign(options, environment);
}
function World(input) {
this.World = input;
});
Object.assign(this, processOptions(Object.assign(defaultOptions, options)), options);
}
setWorldConstructor(World);
// https://github.com/cucumber/cucumber-js/blob/master/docs/support_files/world.md

Nodejs, is better have a lot of same require or use a handle?

Image this esctructure:
- app.js
- core/
- service_1.js
- service_2.js
- service_3.js
- service_4.js
- service_5.js
- modules/
- module_1.js
- module_2.js
- module_3.js
The app.js uses the 3 modules, so the code of the app is:
var m1 = require('./modules/module_1');
var m2 = require('./modules/module_2');
var m3 = require('./modules/module_3');
m1.exec();
m2.exec();
m3.exec();
And each model uses all the services, so they need:
var s1 = require('./../core/service_1');
var s2 = require('./../core/service_2');
var s3 = require('./../core/service_3');
var s4 = require('./../core/service_3');
var s5 = require('./../core/service_3');
// some stuff...
So, I need to know if this is the best way to handle that or maybe do a "serviceManager" like:
app.js
var m1 = require('./modules/module_1');
var m2 = require('./modules/module_2');
var m3 = require('./modules/module_3');
var serviceManager = {
service_1 : require('./core/service_1'),
service_2 : require('./core/service_2'),
service_3 : require('./core/service_3'),
service_4 : require('./core/service_4'),
service_5 : require('./core/service_5')
};
m1.load(serviceManager);
m2.load(serviceManager);
m3.load(serviceManager);
m1.exec();
m2.exec();
m3.exec();
And each model I put:
var serviceManager = null;
exports.load = function(services) {
serviceManager = services;
}
// some stuff...
What is the best if I gonna use that class in almost all my files?
a) Get a lot of 'require'.
b) A handle to put 'require' only one time.
c) Another solution.
Dependency injection is really good for this. I've used and recommend insulin. This makes it very easy to load each of your modules in the dependency injection container and then just name dependencies in the modules you write.
You might do something like the following:
'use strict';
require('insulin').factory('myService', myServiceFactoryFunction);
function myServiceFactoryFunction(dependencyOne, dependencyTwo) {
// Do something with your dependencies.
}
This way you require once at the top of the file and never have to do it again in that file.
As mentioned in one of the other answers, node caches everything required, so each time you require the injection container, you get the same one. This makes it very quick and easy to build your app without either having to require things everywhere or pass things around.
Later, to get the module you created above you would just do the following where it's needed:
'use strict';
require('insulin').factory('mySecondService', mySecondServiceFactoryFunction);
function mySecondServiceFactoryFunction(myService) {
// myService is now available in this module
}
Insulin, as with most other dependency injectors you might use has other methods if you for some reason don't want to or can't rely on injection in some part of your application. You could do something like:
const insulin = require('insulin');
const myDependency = insulin.get('someModule');
where needed.
The best part about this to me is that the code becomes really clean and it's easy to tell what the dependencies are for a given file just by looking at the arguments passed to the factory function.
I would go with a lot of requires. It does not matter, because Node.js caches the modules after first load.
From the Node.js docs:
Modules are cached after the first time they are loaded. This means (among other things) that every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.

How to deal with mutual inclusions in Node.js?

I'm developing a Node.js application that contains a game engine, and I basically have this pattern in my engine:
A.js
var B = require('./B');
var A = module.exports = function () {
this.b = new B;
console.log(B.staticBar)
};
A.staticFoo = 'foo';
B.js
var A = require('./A');
var B = module.exports = function () {
console.log(A.staticFoo);
};
B.staticBar = 'bar';
So I want both A.staticFoo to be accessible in B.js and B.staticBar in A.js.
Any idea how to do that?
Thanks
EDIT : actually my static variables are config values, so another solution would be to group them into a config.js file and require that file in every other file, but I find it more elegant to define config variables directly as static members of related classes. Hope that's clear enough ;)
I would suggest separating your static state into a third module... By decoupling state from your module, you can operate either independently.
state.js
//state.js - changed by other modules...
module.exports = {
staticFoo: null,
staticBar: null
};
a.js
//a.js
var state = require('./state');
exports = module.exports = fnA;
...
function fnA() {
console.log(state.staticBar);
}
b.js
//b.js
var state = require('./state');
exports = module.exports = fnB;
...
function fnB() {
console.log(state.staticFoo);
}
Another example mentions something akin to dependency injection... given how modules work in JS, and that you can override for testing with proxyquire and the like, I tend to prefer the simpler requires structure over dealing with DI/IoC in JS as it muddles your project code.
I also like to do my requires, then my exports, then any methods within that module, usually just one method in a module.
It would depend on the architecture of your code. BUT, working with other people's code is always different of course.
The best choice is to separate your code into smaller module(s). If they're referencing each other it can challenging to build tests especially when the code grows.
OR
If that's not possible you could always remove coupling through the use of references.
B.js
var _A;
exports.setA = function(ref) {
_A = ref;
};
var B = exports.B = function () {
console.log(_A.staticFoo);
};
And use B.setA(A) to make sure B has a reference to use A.staticFoo

Is it possible to declare global variables in Node/Express 4.0

I have multiple routes that need to access a database, for development I use a local database, and obviously production I use a hosted database
The only problem is every time I go to push a release I have to go through each route manually changing the database link
e.g.
var mongodb = require('mongojs').connect('urlhere', ['Collection']);
It would be nice if I could declare a variable in app.js like
app.set('mongoDBAddress', 'urlhere');
then in each file do something like
var mongodb = require('mongojs').connect(app.get('mongoDBAddress'), ['Collection']);
Does anybody know if this is achievable I've been messing around with it for about an hour googling and trying to include different things but I have no luck. thanks.
From the docs:
In browsers, the top-level scope is the global scope. That means that
in browsers if you're in the global scope var something will define a
global variable. In Node this is different. The top-level scope is not
the global scope; var something inside a Node module will be local to
that module.
You have to think a bit differently. Instead of creating a global object, create your modules so they take an app instance, for example:
// add.js
module.exports = function(app) { // requires an `app`
return function add(x, y) { // the actual function to export
app.log(x + y) // use dependency
}
}
// index.js
var app = {log: console.log.bind(console)}
var add = require('./add.js')(app) // pass `app` as a dependency
add(1, 2)
//^ will log `3` to the console
This is the convention in Express, and other libraries. app is in your main file (ie. index.js), and the modules you require have an app parameter.
You can add a global variable to GLOBAL, see this this question, although this is probably considered bad practice.
We have two methods in node.js to share variables within modules.
global
module.export
But your problem seems to be different, what I got is you want to connect your application to different databases without changing code. What you need to do is use command line params
For more ref
server.js
var connectTo = {
dev : "url1"
production : "url2"
}
var mongodb = require('mongojs').connect(connectTo[process.argv[2]], ['Collection']);
Run your server.js as
node server.js dev
// for connecting to development database
or
node server.js production
// for connecting to prodiction database
To share connection across diffrent modules
//Method 1
global.mongodb = require('mongojs').connect(connectTo[process.argv[2]], ['Collection']);
//Method 2
exports.mongodb = require('mongojs').connect(connectTo[process.argv[2]], ['Collection']);
exports.getMongoDBAddress = function() {
return connectTo[process.argv[2]]
}

Categories

Resources