I'm fairly new to nodejs. Writing my first application. I'm pretty used to php.
In order to keep code organized and clean, i always write functions in separate files and include them as required in php.
However, in nodejs i've had to require them like i would require a module.
For example.
functions.js
module.exports = {
check_db : function(key){
},
check_cache : function(key){
memcached.get(key,function(err, data){
console.log(data);
});
},
};
Included that in the main app like so
// Establish connection with cache and database
const mysql = require('mysql2');
const Memcached = require('memcached');
const memcached = new Memcached('localhost:11211');
const bb = require('bot-brother');
//Load the database cache functions
const dbc = require("./functions");
dbc.check_cache(123);
Now i can access the functions from dbc from the main app file, but i cannot use modules that have been required in the main app from the functions file.
I get an error that memcached is not defined.
How can i go about solving this?
Simple solution, you can require("memcached") in the functions.js file and create the server here. But I wouldn't go with this solution, as, if you need memcache somewhere else, you would have opened many connections on the memcache server.
Another, and cleaner solution IMO, is to inject the memcache dependency into your services (or functions as you call them). (this practice is called dependency injection if you want to learn about it and what are the benefits of it)
Here is how it would work:
you still create the memcache connection in the main file ;
instead of exporting a raw json object in your functions.js, you export a function that takes an argument (here memcache)
in your main file, you require that function and call it to get the service you want.
Here is what the code would look like:
main.js
//Load the database cache functions
const dbcFactory = require("./functions");
const dbc = dbcFactory(memcached)
functions.js
module.exports = function (memcached) {
return {
check_db : function(key){},
check_cache : function(key){
memcached.get(key,function(err, data){
console.log(data);
})
}
};
Related
I have a Javascript frontend that does Ajax calls to my backend. To do that, it needs a "backend_URL" that I hard-coded in the Ajax get() call, say "http://myservice/backend".
Now if I want to deploy my app on different machines, some of which will use this url with HTTPS: "https://myservice/backend", and some not (because they lack a proper certificate and do not expose valuable data).
Where should I put the "USE_HTTPS=1" config variable so that someone deploying the app can choose to use or not SSL ? Of course the question extends itself to other config variables.
I thought about adding a ".config" file at the project root, but then I don't know how to import it in my code. Or should I export environment variables ? Or a node.js feature ?
I ended up writing a conf.js file with content
window.CONFIG = {
SOME_CONSTANT: 22,
}
and included it in a new <script> in my index.html before the other scripts.
The window is not mandatory but shows where it comes from when I call that as window.CONFIG anywhere in the rest of the javascript.
CONFIG = (function(){
var conf_info = {};
conf_info["url"] = 'http://codepen.io/pen/';
return{
getValue : function(param){
return conf_info[param];
}
}
})();
//some where in different file
document.getElementById("result").innerHTML = CONFIG.getValue('url');
how can I exports this dynamic module?
// ./data/example5.js
module.exports = {title : example5, recentCheck : "2018-08-22"}
The contents change in real time. And I execute the followed function once a minute and connect the module.
var files = fs.readdirSync(`./data/`);
var i = 0;
var link = [];
while(i<files.length){ // read all file
link[i] = require(`../data/${files[i]}`);
//main.js
setInterval(start,10000);
I try to create and connect a new module file once a minute, but the first stored file(module) is extracted. The modulefile is being saved in real time correctly.
Shutting down and running the node will extract the changed modules correctly.
How do I handle a dynamically changing module?
I would recommend saving the data in a JSON file and then reading the data from the file rather than trying to use it as a module.
Just make the objects you're updating variables in the module that you're including.
Make a function called getVariable, and simply return the variable.
Include getVariable in your main module.
I have a Node.js module that I have kept as a single file up to this point. It's getting rather large though and has a lot of functionality in it that might be better separated into other modules. For example, separating out logging initialization and functionality into it's own module.
My module has a lot of (I want to say "global" but not really) top-level variables that lots of different functions access, use and modify. If I separate out functionality into separate files/modules and require them into my primary module, what is the proper approach to passing those variables between the modules?
For example, with everything in one module/file, it's easy to do this:
const logger = (log, message) {........}
const makeRequestHandler = (url, filepath) {
....
logger.info('some message here')
....
}
So it's pretty easy to access top-level systems like the logger. But, if I decided to split my logger and makeRequestHandler into their own modules/files, how would I handle this?
let logger = require('./mylogger') // Custom module
let makeRequest = require('./makerequest') // Another custom module
makeRequest.handler(url, filepath, logger)
This would work, but it doesn't seem elegant or optimal. It would get even more weird if I have a lot of different variables that I needed to pass in:
makeRequest.handler(url, filepath, logger, profiler, reportingBuffer, compressionHandler)
I've also considered passing stuff into the modules when requiring:
let makeRequest = require('./makeRequest')(logger)
or better yet:
let makeRequest = require('./makeRequest')(this) // I can access all variables made in my primary/top-level module
Is there an approach here that is more proper and better/easier to maintain? Is the last one the best approach?
What about a global locator pattern or service locator/service provider pattern as pointed out in comments wherein you can have something like a service registry and include these services in any module you want to use them in.
Although I am not sure about being the best solution of all, but it is easier to implement and feels like a neater solution than passing in the this context around the modules.
//logger.js
const logger = (log, message) {........}
export logger
Now, in the app file is where you can initialize the logger and other service instances and register them in the global locator
let logger = require('./mylogger') // Custom module
init() {
//init and set the logger
global.logger = new logger();
...
}
And this is how you can use it in the code to makRequest
let logger = global.logger;
const makeRequestHandler = (url, filepath) {
....
logger.info('some message here')
....
}
What I feel is problem with these solutions :
//Solution 1 : As you pointed out yourself this can get messy when number of paramters increase and is not very readable or understandable.
let logger = require('./mylogger')
let makeRequest = require('./makerequest')
makeRequest.handler(url, filepath, logger)
//Solution 2 : Passing around the `this` context is never a good idea,for keeping sensitive data independent or scope isolation
let makeRequest = require('./makeRequest')(this)
note :
This article explains some aspects of this solution in detail for your consideration.
Also there are some npm modules which provide these features like Service Locator
. HTH
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]]
}
I defined mysql connection with all parameters necessary to app.js, how can make visible to other scripts in routes/ by default, without requiring or redefining mysql parameters, just using client.query(..)?
A pattern I use is to set up my db object in a module once and export it: (let's call it utils/mySQL.js)
//I haven't used real mysql in node so excuse the pseudo-syntax:
var db = require('mysql-driver-thingy');
db.connect('localhost', 'sqlport', options...);
db.otherSetupFunctions();
console.log("Finished db setup. You should only see this message once! Cool.");
module.exports = db;
And then I can require the db object everywhere I need it. Since requires are cached, this does't actually call the setup methods multiple times.
In app.js:
var db = require('./utils/mySQL.js');
...
In models/user.js:
var db = require('../utils/mySQL.js');
...
A final option, which isn't recommended, is to pollute the global namespace. This seems to be the answer you're really after:
//set up your db
...
// and now make it available everywhere:
global.client = db.client
You can now magically use the client object in all your modules, without even requiring it.
There are many reasons globals are bad, though:
If your code and other code define globals, they could conflict and overwrite each other.
It's hard to find where you defined the db/client object, etc.
You can inject mysql connection into other scripts like this:
app.js
var mysqlConnection = new Conection(params);
require('controller/main.js)(mysqlConnection);
main.js
module.exports = function(mysqlConnection) {
// You can access your mysql connection here
};
UPDATE:
You can inject several variables same way. Also you still can export methods from module if you need this:
app.js
var mysqlConnection = new Conection(params);
var news = require('model/news.js)(app, mysqlConnection);
news.list(function(err, news) {
// Do something
});
news.js
module.exports = function(app, mysqlConnection) {
var methods = {};
// mysql connection and app available from here
methods.list = function(cb) {
mysqlConnection.list(function(err, data) {
cb(err, data);
});
};
return methods;
};