how to create environment variables to store data in a file? - node.js

Hey actually i am doing some project in Nodejs. I need a configuration file in order to store the data to file system but i do not know how to write a configuration file to store data to file. please help me with this. thanks in advance

Sounds to me that you are looking for the following NPM module/library - dotenv. You simply require('dotenv').config(); which is probably best placed at the top (after use strict;) and create a text file which would read as an example:
url_prefix='mongodb://'
url_ip='#localhost'
port=':27017/'
dbase='NameofDB'
Of course you can add anything you like to this file. Just remember it is a text file and should not contain spaces etc.
Though the default for the .env file is in the root of your project you can actually place it wherever you like, and simply put:
require('dotenv').config({path: '/custom/path/to/your/env/vars'});
(Above was taken from the dotenv documentation and it works as I use it in projects.)
To acquire any Global variable you would simply type:
process.env.url_prefix
Obviously from there you can build the needed entry code to your DB from process.env statements such as:
process.env.url_prefix+process.env.url_ip etc. OR
${process.env.url_prefix}${process.env.url_ip}
Using dotenv allows you to keep sane control over those process.env globals.
Be aware there is a gotcha! Be careful not to overwrite any of those globals in your code. As they will remain overwritten as long as your Node process is running.

If you mean you need some constants and business logic/data file to read from, you can simply include the file in your script using the require module.
Ex: Your file name is test.json, then:
var test = require('test.json');
Further, you can use a CONSTANT in the file as 'test.CONSTANT'
Note: Please make sure you use module.exports wherever needed. Details are here

Usually people use JSON to store configurations and stuff, since it is very javascripty.. You can simply make a JSON config file. In case you need to store some special data like SECRET URL, just use environment variables. FYI I found your question unclear. Does this answer your question.
const fs = require("fs");
// Example Config
let config = {
DB: "mongodb://blahblah:idhdiw#jsjsdi",
secret: "thisandthat",
someScript: "blah.js"
};
// Write to file.
fs.writeFile('config.cfg', JSON.stringify(config), err => {
if (err) throw err;
console.log("[+] Config file saved!");
// Retrieve
let confData = JSON.parse(fs.readFileSync('config.cfg'));
console.log(confData.secret);
});
// To save variables in environment variables
// Generally You will not set environment variables like this
// You will have access to setting environment variables incase
// you are using heroku or AWS from dash board. Incase of a machine
// you can use ** export SOME_ENV_VAR="value" ** in your bash profile
process.env.IP = "10.10.10.10";
// Too risky to put else where.
process.env.API_KEY = "2ke9u82hde82h8";
// Get Data
console.log(process.env.IP);
console.log(process.env.API_KEY);

Related

What is the best way to separate your code in a Node.js application?

I'm working on a MEAN (Mongo Express.js Angular Node.js) CRUD application. I have it working but everything is in one .js file. The single source code file is quite large. I want to refactor the code so CRUD functionality is in different source code files. Reading through other posts, I've got a working model but am not sure it is the right way in Node using Mongo to get it done.
Here's the code so far:
<pre>
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var path = require('path');
var db;
var connect = 'mongodb://<<mddbconnect string>>;
const MongoClient = require('mongodb').MongoClient;
var ObjectID = require("mongodb").ObjectID;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname + '/'));
// viewed at http://localhost:<<port referecnes in app.listen>>
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname + '/index.html'));
});
MongoClient.connect(connect, (err, database) => {
if (err) return console.log(err)
db = database
app.listen(3000, () => {
console.log('listening on 3000' + Date() );
// Here's the require for the search function in another source code file.
var searchroute = require('./serverSearch')(app, db);
})
})
//Handlers
The rest of the CRUD application functions with app.post, app.get. These are other functions I want to move into different source code files, like serverSearch.js.
</pre>
The code I separated right now is the search functionality which is inside of the MongoClient.connection function. This function has to successfully execute to make sure the variable 'db' is valid before passing both variables 'app' and 'db' to the the search function built out in the source code file serverSearch.js.
I could now build out my other CRUD functions in separate files in put them in the same area as 'var searchroute = require('./serverSearch)(app,db);
Is this the best way to separate code in a MEAN application where the main app and db vars need to be instantiated then passed to functions in other source code files?
What you are basically describing is modular coding heading towards "services" perhaps even micro-services. There are a few factors to keep in mind for your system. (I have no doubt that there are many other approaches to this btw). Basically in most NodeJS systems I have worked on (not all) I try to apply the following architecture in development and then bring over as much as possible I to production.
Create a directory under the main one. I usually use some type of name that points to the term functions. In this directory I maintain function and /or class files divided into categories. Function wrappers for DB would be held in DB functions. This file would only contain functions for the DB. Security functions in another file. Helper functions in another. Time manipulation in another. I am sure you get the idea. These are all wrapped in module exports
Now in any file in my project where say I would need DB and helpers I will start it by:
let nhelpers = require("helpfuncs");
let ndb = require("dbfuncs");
Obviously names are different.
And btw I divide all the NPM packages in the same way under an environment directory.
Maintaining that kind of structure allows you to maintain sane order over the code, logical chaining in any decent IDE, and having relevant methods show up in your IDE without having to remember every function name and all the methods within.
It also allows you to write an orderly system of micro-services making sure each part dies exactly what you want and allows for sane debugging.
It took me awhile to settle on this method and refine it.
It paid off for me. Hope this helps.
Edit to clarify for the OP:
When it comes to the process.env variables I became a great fan of dotenv https://www.npmjs.com/package/dotenv
This little package has saved me an incredible amount of headaches. Of course you will have to decide if you include it in production or not. I have seen arguments for both, but i think in a well set up AWS, Google, Azure environment (or in Docker of course) I am of the opinion it can safely be used.
A couple of caveats.
Do not leave your dotenv file in the root. Move it somewhere else in your directory structure. It is simple and I actually put it in the same directory as all my environment files and helper files.
Remember it is simply a text file. So an IDE will not pick up your specific env variables in chaining. (Unless someone knows of a trick which I would love to hear about)
If you put env variables like access info to your DB system or other sensitive stuff, HASH THEM FIRST, put the hash in your env and have a function in your code which specifically just does the hash to the string. Do not under any conditions leave sensitive information in your environment file without hashing it first.
The final Gatcha. These are not PHP magic globals which cannot be overwritten. If you lose track and overwrite one of those process.env variables in your code it will take the new value until you restart your node app and it reads from the dotenv file again. (But then again that is the rule with all environment variables not only user defined ones)
Any typos above excuse me. Done from my cell in the train.

NodeJS - Store Global variable

I'm currently trying to get a list of all of the members that are signed in. I'm using socket.js for this and using event handlers.
I have the following event:
eventEmitter.on('userSignedIn', function(socket, user) {
socket.emit("userJoined", {currentUsers: user.first_name});
});
Then, in JQuery, I am doing the following:
socket.on('userJoined', function (message) {
newItem = $("<li>Item " + message.currentUsers + "</li>").show();
$('.users-list').prepend(newItem);
});
This however is not working and not even showing the correct username(s).
Basically, what I want to do is when the event userSignedIn it appends an array users with the user that's just signed and then send this through the socket. But I'm struggling to see how I can store this inside the global app?
A global variable in node is accessed through process.env.
If you need to store this as a global variable in Node, go to the dotenv module, install it, (farily simple to use it) and use it to store your original global for the counter. In your .env file you would have say counter=1. Then you can increment it by accessing the global in your code by stating process.env.counter and you can increment it as well.
Remember: if you process stops running or goes down the counter will return to the original state of 1 when you bring it back up.
You can if you wish not use the dotenv module and simply create and access a process.env variable straight in your code. However, dotenv is very flexible, and you may want to use it for other purposes.
Hope this helps

How to set process.env before a browserified script is run?

The initial html comes from the back-end. The server has a defined process.env.NODE_ENV (as well as other environment variables). The browserified code is built once and runs on multiple environments (staging, production, etc.), so it isn't possible to inline the environment variables into the browserified script (via envify for example). I'd like to be able to write out the environment variables in the rendered html and for browserified code to use those variables. Is that possible?
Here's how I imagine that being done:
<html>
<head>
<script>window.process = {env: {NODE_ENV: 'production'}};</script>
<script src="/build/browserified_app.js"></script>
</head>
</html>
Instead of hardcoding enviroment variables here and there, use the envify plugin.
npm install envify
This plugin automatically modifies the process.env.VARIABLE_HERE with what you passed as an argument to envify.
For example:
browserify index.js -t [ envify --DEBUG app:* --NODE_ENV production --FOO bar ] > bundle.js
In your application process.env.DEBUG will be replaced by app:*, process.env.NODE_ENV will be replaced by production and so on. This is a clean && elegant way in my opinion to deal with this.
You can change your entry point file, which would basically to do such setup and then require the original main file.
process.env.NODE_ENV = 'production';
require('app.js');
Other way (imo much cleaner) is to use transform like envify which replaces your NODE_ENV in the code with the string value directly.
Option 1
I think your approach should generally work, but I would't write directly to process.env since I am pretty much sure that it gets overwritten in the bundle. Instead you can make global variable like __env and then in the actual bundle code set it to process.env in your entry file. This is untested solution, but I believe it should work.
Option 2
Use localStorage and let your main script read variables from there upon initialization. You can set variables to localStorage manually or you can even let the server provide them if you have them in there. Developer would just open console and type something like loadEnv('production'), it would do XHR and store the result in the localStorage. Even with manual approach there is still an advantage that these doesn't need to hard-coded in html.
If manual doesn't sound good enough and server is a dead end too, you could just include all variables from all environments (if you have them somewhere) in the bundle and then use switch statement to choose correct ones based on some conditions (eg. localhost, production host).
Thinking about this, you are definitely out of scope of Browserify with your needs. It can make bundle for you, but if you don't want these information in the bundle, you are on your own.
So I've decided it's the web server's job to insert the environment variables. My scenario required different loggers per environment (e.g. 'local','test','prod').
code:
var express = require('express')
, replace = require('replace');
...
var app = express();
var fileToReplace = <your browserified js here>;
replace({
regex: 'ENV_ENVIRONMENT'
, replacement: process.env.ENVIRONMENT
, paths: [fileToReplace]
});
...
app.listen(process.env.PORT);
I hardcoded 'ENV_ENVIRONMENT', but you could create an object in your package.json and make it configurable.
This certainly works, and it makes sense because it's possibly the only server entry point you have.
I had success writing to a json file first, then importing that json file into anywhere that needed to read the environment.
So in my gulp file:
import settings from './settings';
import fs from 'fs';
...
fs.writeFileSync('./settings.json', JSON.stringify(settings));
In the settings.js file:
if(process.env.NODE_ENV) {
console.log('Starting ' + process.env.NODE_ENV + ' environment...');
} else {
console.log('No environment variable set.');
process.exit();
}
export default (() => {
let settings;
switch(process.env.NODE_ENV) {
case 'development':
settings = {
baseUrl: '...'
};
break;
case 'production':
settings = {
baseUrl: 'some other url...'
};
break;
}
return settings;
})();
Then you can import the settings.json file in any other file and it will be static, but contain your current environment:
import settings from './settings.json';
...
console.log(settings.baseUrl);
I came here looking for a cleaner solution...good luck!
I run into this problemn building isomorphic react apps. I use the following (ok, it's a little hacky) solution:
I assign the env to the window object, ofcourse I don't expose all env vars, only the ones that may be public (no secret keys of passwords and such).
// code...
const expose = ["ROOT_PATH", "ENDPOINT"];
const exposeEnv = expose.reduce(
(exposeEnv, key) => Object.assign(exposeEnv, { [key]: env[key] }), {}
);
// code...
res.send(`<DOCTYPE html>
// html...
<script>window.env = ${JSON.stringify(exposeEnv)}</script>
// html...
`);
// code...
then, in my applications clients entry point (oh yeah you have to have a single entry point) I do this:
process.env = window.env;
YMMV AKA WFM!

How can you persist user data for command line tools?

I'm a front-end dev just venturing into the Node.js, particularly in using it to create small command line tools.
My question: how do you persist data with command line tools? For example, if I want to keep track of the size of certain files over time, I'd need to keep a running record of changes (additions and deletions) to those files, and relevant date/time information.
On the web, you store that sort of data in a database on a server, and then query the database when you need it again. But how do you do it when you're creating a Node module that's meant to be used as a command line tool?
Some generic direction is all I'm after. I don't even know what to Google at this point.
It really depends on what you're doing, but a simple approach is to just save the data that you want to persist to a file and, since we're talking node, store it in JSON format.
Let's say you have some data like:
var data = [ { file: 'foo.bar', size: 1234, date: '2014-07-31 00:00:00.000'}, ...]
(it actually doesn't matter what it is, as long as it can be JSON.stringifiy()d)
You can just save it with:
fs.writeFile(filename, JSON.stringify(data), {encoding: 'utf8'}, function(err) { ... });
And load it again with:
fs.readFile(filename, {encoding: 'utf8'}, function(err, contents) {
data = JSON.parse(contents);
});
You'll probably want to give the user the ability to specify the name of the file you're going to persist the data to via an argument like:
node myscript.js <data_file>
You can get that passed in parameter with process.argv:
var filename = process.argv[2]; // Be sure to check process.argv.length and have a default
Using something like minimist can be really helpful if you want to get more complex like:
node myscript.js --output <data_file>
You also can store files in temporary directory, for example /tmp directory on linux and give user the option to change the directory.
To get path to temporary directory you can use os module in nodejs:
const os = require('os');
const tmp = os.tmpdir();

Add global function to every execution of NodeJS

In my project folder project I have a file utils.js like this
global.root_path = process.cwd();
global.custom_require = function() {
console.log('custom require called');
}
I would like to include this file in every execution of node so that in every js file in project i can call custom_require, or access global.root_path as I'm doing already with built-in function require.
Do you know if there is a solution (command line options, environment variable or whatever) to achieve this?
UPDATE
I don't want to include utils.js in every file, in that case I wouldn't need to modify global object.
Thanks!
Simply require it. Example app.js:
require('./utils.js');
var express = custom_require('express');
var app = express();
var port = process.env.PORT || 3000;
app.listen(port);
Then, you could just do (in terminal)
node app
As long as you require the code containing the global declarations on it, then you can use those globals from any file that's required after the fact.
You most probably don't want to have a custom "plugin" altering the behavior of all your applications when run locally, thus it'd be best to stay away from that kind of pattern. Instead, you might want to create a module, use npm link on it, and then npm link something in your project's directory, where something is the module name.
Then each project could just add one line like require('something'); at the very beginning. Changing something would immediately impact all the projects which included it, thanks to the behavior in npm link.

Resources