Setting up a central logging package for multiple applications - node.js

Say we create a package called 'my-loggers' that can be reused, that looks like this:
import bunyan = require('bunyan');
const loggers = {};
export const getLogger = function(name, config){
if(loggers[name]){
return loggers[name];
}
return loggers[name] = bunyan.createLogger(config);
};
then in each application, we do:
npm install -S my-loggers
then we use the logger like this:
import * as MyLoggers from 'my-loggers';
import config = require('../my-app-config');
const log = MyLoggers.getLogger('my-app', config.logging);
the problem is it really requires 3 lines of code to retrieve the logger for each file in each app.
I am trying to figure out a way to create a single package that can retrieve a logger for any file in any app, and I am trying to
cut everything down to just one LoC.
I am also trying to avoid relative paths.
I cannot think of a solution that involves 1 logging package for all our apps. The only thing I can think of is either a separate logging package per app (which is kinda lame), or doing a trick where we symlink some code from our project into node_modules, upon npm install, which allows us to avoid relative paths.
Anyone know of a good way to solve this one?

Ok, I have a solution. We can just do this:
import log from 'my-loggers/app1'
import log from 'my-loggers/app2'
import log from 'my-loggers/app3'
that way we can store different loggers in the same package.

Related

Make a var, "global" just in the npm Package instead of whole Project in Nodejs

I am transforming my Node MicroServices in npm packages, so that I can run several of them in a single server. They exchanges RabbitMQ messages, so they are independent from the listening server.
My problem is that each Ms used global.variables, like the DB connection for example. Now that they are Packages, and so I can have different Mss in one server, I can't share a global.db_connection because each Ms may use a different db.
Is there a way so that I can use a global.db_connection just inside a Package, and that var is global just inside that Package?
==== UPDATE1
Before, I wrongly referred to Modules. I mean npm package. Each MS is a separated npm package, that I install in the server. I've corrected my question now, using package instead of module.
=== EXAMPLE
I know there is a better way to use a DB connection among the code. I am using 'db_connection' just as example of a global object.
-- packageA.js
#module MS_A
global.db_connection = db.connect(URL_1);
class MS_A
{
...
}
module.exports = MS_A;
-- packageB.js
#module MS_B
global.db_connection = db.connect(URL_2);
class MS_B
{
...
}
module.exports = MS_B;
-- server.js
global.needed_variable = 3;
var MS_A = new require("./packageA.js")().start();
var MS_B = new require("./packageB.js")().start();
/**
"needed_variable" should be visible inside both packages.
"db_connection" should be not visible outside each package
*/
MS_B should use its own db_connection, and be not aware of the db_connection of MS_A (and vice versa).

How to Properly Import a Module Into A File (Node.js)

I am trying to make a video chat using WebRTC and Node.js. I currently am trying to add a selectable microphone (e.g. being able to change mics and webcams). I made the function, but when I try to import a function from the file that generates the IDs of the the devices, it doesnt work. Note that I am not currently getting any errors, instead, when I add the import statement to the file, nothing shows up (except for the dropdowns that change the mic and webcam).
Is there a reason that node wont let me import a function?
Note that the file that I am trying to import into exports a bunch of functions (thats the purpose of it), RTC.js. However, I also tried importing into another file and it didnt work either (the file that imports the first file, rtc.js).
Thanks in advance
The github repository is located here
Export is like this line you already did https://github.com/divinelemon/VideoChatAppSwitchMics/blob/master/ws/stream.js#L34
module.exports = stream;
Import is like here you did https://github.com/divinelemon/VideoChatAppSwitchMics/blob/master/app.js#L5
let stream = require( './ws/stream' );
you can also ES6 import/export function:-
const someFunction = (){
...
}
export default someFuntion ( in the case on single function)
When you want to export multiple functions
export { someFunction1, someFunction2}.
Now the place where you want to import
import somFunction from 'filelocation' ( note in case of default exports you need to use the same name of the function)
In the case of multiple functions.You can change the function name but keep in mind the order of exports and imports.
import { myFunction1,myFunction2} from 'fileLocation'

How requiring a module on entry point makes available on other modules on NodeJS?

This is probably a duplicated question, but I couldn't find anything.
Since I'm learning NodeJS, I think that I'm not using the right words to search, so it's hard to find an answer.
Here is the situation:
I'm currently following an online course about NodeJS and coding an API.
In the current step we are using Winston library to log errors. The instructor, have configured on Index,js, which is the entry point of the app, like this:
File: index.js
const winston = require('winston');
const errorHandler = require(./middleware/error.js);
//(...) some other imports
app.use(errorHandler);
winston.add(winston.transports.File,{filename:'logFile.log'});
And in other module we've created in the course to handle errors, he requires winston and simply call to log the error. Something like this:
File: error.js
const winston = require('winston');
function errorHandler(err,req,res,next){
winston.error(err.message,err);
res.status(500).send("something failed");
}
module.exports = errorHandler;
After doing a test, the error is correctly written to the file, and my question is: How it works? How a setting made on the 'required version' of winston at index.js is visible from the other required version at error.js?
From index.js we are importing error.js too, so i can imagine somehow this two modules are sharing this winston object, but again, I don't understand how or where is it shared.
Again, please excuseme if I'm not using the right terms to refer anything here, I'll accept any advice.
Thanks.
When a module is loaded in node.js, it is cached by the require() sub-system. So, when you then require() it again, that means you'll get the exact same module as the previous one.
So ... if you initialized the module after you first loaded it and the module stores some state that represents that intialization, then subsequent use of that module will be using the same (already initialized) module.
And in other module we've created in the course to handle errors, he requires winston and simply call to log the error.
It gets the same instance of the winston module that was already initialized/configured previously.
After doing a test, the error is correctly written to the file, and my question is: How it works? How a setting made on the 'required version' of winston at index.js is visible from the other required version at error.js?
Module caching as describe above. There's only one winston module that all are sharing so if it's initialized/configured in one place, all will use that configuration.

Webpack Aliases in Node JS Server code

I'm building an isomorphic React/React-Router/Redux/Webpack application and I'm attempting to implement server side rendering.
My directory looks like:
/client
/actions
/components
/containers
/server
/server.js
In my webpack config, I have aliases set up for all the folders inside client:
var path_base = path.resolve(__dirname, '..');
const resolve = path.resolve;
const base = function() {
var args = [path_base];
args.push.apply(args, arguments);
return resolve.apply(resolve,args);
};
const resolve_alias = base.bind(null, 'src/client');
const aliases = [
'actions',
'components',
'constants',
'containers',
'middleware',
'reducers',
'routes',
'store',
'styles',
'utils',
'validation'
];
so that inside the code that gets bundled by webpack, I can do:
import { Widget } from 'components';
and that import gets resolved by webpack.
Now in my server code, in order to do the rendering, I have to import some of my client files, like routes/index.js. The problem I'm running into when I import my routes file, it's using a webpack alias to another file, say components or containers so naturally, the node js require system can't resolve it.
How do I fix something like that? I looked at this question and it talks about essentially setting up the same aliases that exist in webpack with mock-require. But then the issue becomes that my routes file imports all my components which then all import things like stylesheets, images, etc. Should I then be using something like webpack-isomorphic-tools?
The guides I've been looking at (this for example) are all great at showing how server side rendering is accomplished but none of them really talk about how to resolve all the requires and whatnot.
After battling with this issue for 2 days I settled on babel-plugin-webpack-alias.
What you need to do to resolve paths with that is:
$ npm install --save-dev babel-plugin-webpack-alias
Add the plugin to your .babelrc
Add the aliases to your webpack.config (make sure you use path.join())
Refer to this post if you have problems loading styles
The other option I tried was universal-webpack but I found it to be a bit verbose. If you want to see roughly how the whole server-side loading works, you can check out this video.
If you really want them, run your server side code through babel and use this plugin: https://www.npmjs.com/package/babel-plugin-module-alias which will let you do the same thing as webpack.
Edit: This one works a lot better: https://github.com/jagrem/babel-resolve-relative-module it allows multiple paths
Try to use NODE_PATH. Node will always look for a module in this path during require calls. It allows to short cut your relative paths as you want.
// turn this
import {Widget} from '../../components';
// into this
import {Widget} from 'components';
See Node.js docs for more information.
P.S. this thing is very sensitive, so use it carefully. Now your code tightly depends from the environment and may break somewhere.
If you use webpack-isomorphic-tools then it'll take your webpack config into account for your server side which will make all your aliases work.
https://www.npmjs.com/package/webpack-isomorphic-tools

How to reference local files in a npm module?

I wrote a simple npm module to precompile my handlebars templates when using django compressor to do post-processing for some client side components and found that I need to ship the npm module with a few js files.
Currently I just assume no one is installing this with the global flag because I've "hard coded" the path to these dependencies in the npm module itself
example layout of my npm module
/
* /bin
* /lib/main.js
* /vendor/ember.js
Now inside main.js I want to use the ember.js file ... currently my hard coded approach looks like this
var emberjs = fs.readFileSync('node_modules/django-ember-precompile/vendor/ember.js', 'utf8');
Again -this only works because I assume you install it local but I'd like to think node.js has a more legit way to get locally embedded files
Anyone know how I can improve this to be more "global" friendly?
What you can do is get the directory of the current file and make your file paths relative to that.
var path = require('path')
, fs = require('fs');
var vendor = path.join(path.dirname(fs.realpathSync(__filename)), '../vendor');
var emberjs = fs.readFileSync(vendor + '/ember.js', 'utf8');
Hope that helps!
One of the great strengths of Node.js is how quickly you can get up and running. The downside to this approach is that you are forced to fit the design patterns it was build around.
This is an example where your approach differs too much from Nodes approach.
Node expects everything in a module to be exposed from the modules exports, including templates.
Move the readFileSync into the django-ember-precompile module, then expose the returned value via a module export in lib/main.js.
Example:
package.json
{
"name": "django-ember-precompile",
"main": "lib/main.js"
}
lib/main.js
module.exports.ember = readFileSync('vendor/ember.js')
vendor/ember.js
You obtain your template via
var template = require('django-ember-precompile').ember
This example can be refined, but the core idea is the same.

Resources