Variable assignment withing .env file - node.js

I have one .env file , that looks like :
NODE_ENV = local
PORT = 4220
BASE_URL = "http://198.**.**.**:4220/"
PROFILE_UPLOAD = http://198.**.**.**:4220/uploads/profile/
POST_UPLOAD = http://198.**.**.**:4220/uploads/discussion/
COMPANY_UPLOAD = http://198.**.**.**:4220/uploads/company/
ITEM_UPLOAD = http://198.**.**.**/uploads/item/
GROUP_UPLOAD = http://198.**.**.**/uploads/group/
I want to do something like this :
NODE_ENV = local
IP = 198.**.**.**
PORT = 5000
BASE_URL = http://$IP:$PORT/
PROFILE_UPLOAD = $BASE_URL/uploads/profile/
POST_UPLOAD = $BASE_URL/uploads/discussion/
COMPANY_UPLOAD = $BASE_URL/uploads/company/
ITEM_UPLOAD = $BASE_URL/uploads/item/
GROUP_UPLOAD = $BASE_URL/uploads/group/
Expected result of BASE_URL is http://198.**.**.**:4220/
I have tried many few syntax but not getting computed values
Tried Syntax : "${IP}" , ${IP} , $IP
I have used dotenv package , for accessing env variables.

dotenv-expand is the solutions as #maxbeatty answered , Here are the steps to follow
Steps :
First Install :
npm install dotenv --save
npm install dotenv-expand --save
Then Change .env file like :
NODE_ENV = local
PORT = 4220
IP = 192.***.**.**
BASE_URL = http://${IP}:${PORT}/
PROFILE_UPLOAD = ${BASE_URL}/uploads/profile/
POST_UPLOAD = ${BASE_URL}/uploads/discussion/
COMPANY_UPLOAD = ${BASE_URL}/uploads/company/
ITEM_UPLOAD = ${BASE_URL}/uploads/item/
GROUP_UPLOAD = ${BASE_URL}/uploads/group/
Last Step :
var dotenv = require('dotenv');
var dotenvExpand = require('dotenv-expand');
var myEnv = dotenv.config();
dotenvExpand(myEnv);
process.env.PROFILE_UPLOAD; // to access the .env variable
OR (Shorter way)
require('dotenv-expand')(require('dotenv').config()); // in just single line
process.env.PROFILE_UPLOAD; // to access the .env variable

dotenv-expand was built on top of dotenv to solve this specific problem

As already stated you can't assign variables in .env files. You could move your *_UPLOAD files to a config.js file and check that into .gitignore , then you could do
//config.js
const BASE_URL = `http://${process.env.IP}:${process.env.PORT}/`
module.exports = {
PROFILE_UPLOAD: BASE_URL+"uploads/profile/",
POST_UPLOAD: BASE_URL+"uploads/discussion/",
....
}

Unfortunately dotenv can't combine variables. Check this issue to see more and find a solution for your project.

Related

issues while running node.js project on windows

I got node.js project which is developed to run on linux. Now the requirement is to run it on windows. I am facing some issues in that.
On linux, project runs with script which in turn runs below commands
export ABC_ENV=manufacturing; export NODE_ENV=development; npm run dev
package.json
"scripts": {
"dev": "ts-node-dev --respawn --transpile-only --inspect -- src/app.ts",
"build": "./node_modules/typescript/bin/tsc"
},
src/config/app.config.ts
import {readFileSync} from 'fs';
import {join} from 'path';
const secureEnv = require('secure-env');
/**
* Decrypt the .env.enc file, bind parsed environment variables to
* global.env, and expose them centrally as aliased constants
* for consumption throughout the app.
*/
try {
const basePath = join(__dirname, '../../', `.env-${process.env.ABC_ENV}`)
const secret = readFileSync(`${basePath}.key`, {encoding: 'utf8'}).trim();
global.env = secureEnv({secret, path: `${basePath}.enc`});
} catch (e) {
console.error(`Problem reading encrypted .env variables:\n${e}`);
}
if (!global.env) {
throw new Error('Environment variables were not properly bound to `global` by secure-env.');
}
export const operationalMode = global.env.OP_MODE || 'development';
export const port = global.env.PORT;
export const databaseHost = global.env.DB_HOST || 'localhost';
export const database = global.env.DB_NAME;
export const databaseUser = global.env.DB_USER;
export const databasePass = global.env.DB_PASS;
export const twilioAccountSid = global.env.TWILIO_SID;
export const twilioApiKey = global.env.TWILIO_API_KEY;
export const twilioApiSecret = global.env.TWILIO_API_SECRET;
export const awsAccessKey = global.env.AWS_ACCESS_KEY;
export const awsSecret = global.env.AWS_SECRET;
export const awsTopBucket = global.env.AWS_TOP_BUCKET;
export const expressSessionSecret = global.env.EXPRESS_SESSION_SECRET;
export const jwtAccessSecret = global.env.JWT_ACCESS_TOKEN_SECRET;
export const sysadminEmail = global.env.SYSADMIN_EMAIL;
export const loggingEmail = global.env.LOGGING_EMAIL;
To run project in Windows, first I installed packages with npm i. With secure-env, I have created .env.enc file from .env file. Then I excuted below commands
set ABC_ENV=manufacturing;
set NODE_ENV=development;
npm run dev
But by running above commands, it gives error like which is from app.config.ts :
Environment variables were not properly bound to `global` by secure-env.
I tried with nodemon app.js . But facing same error.
I don't know about node.js and so not able to understand what's happening and don't know what will require to run project on Windows.
Any suggestions to trace what's missing or what should I check will be helpful.
Please help and guide to resolve this. Thanks

What does require('..') mean?

I am new to node.js and have been trying to test some code using yarn. At the moment I am using the following code:
const assert = require('assert')
const username = process.env.HDFS_USERNAME || 'webuser'
const endpoint1 = process.env.HDFS_NAMENODE_1 || 'namenode1.lan'
const endpoint2 = process.env.HDFS_NAMENODE_2 || 'namenode2.lan'
const homeDir = `/user/${username}`
const basePath = process.env.HDFS_BASE_PATH || homeDir
const nodeOneBase = `http://${endpoint1}:9870`
const nodeTwoBase = `http://${endpoint2}:9870`
const webhdfs = require('..')
const should = require('should')
const nock = require('nock')
describe('WebHDFSClient', function () {
const oneNodeClient = new (require('..')).WebHDFSClient({
namenode_host: endpoint1
});
})
that I've got from this repo:
https://github.com/ryancole/node-webhdfs/blob/master/test/webhdfs.js
and when I try to run yarn test I get the following error:
Cannot find module '..'
Require stack:
- myrepo/test/lib/hdfs.js
- myrepo/test/tests.js
- myrepo/node_modules/mocha/lib/mocha.js
- myrepo/node_modules/mocha/index.js
- myrepo/node_modules/mocha/bin/_mocha
Error: Cannot find module '..'
As you can see, require('..') is used couple of times in the code and I can not figure out what it means. I've found posts on require('../') which I think is not exactly the same as this one.
The inbuilt node.js require function uses a quite complex package resolution algorithm. So there are lots of things that may influence it.
A. Defaulting to index.js
node.js implicitly requires a file named index.js if no file name is specified.
So require("..") translates to require("../index.js")
B. The main package property.
If you require is inside a module and points to the root of the module it will read the main property from the packages package.json and require the file specified there.
So given this package definition (package.json)
{
"main": "./fileA.js"
}
The call to require("..") will be translated to require("../fileA.js")
Resources
Good explanatory blog entry
Official Docs

Can't read file using nodejs fs module when file name is stored in environment variable

I am running a node app in ubuntu server 16.04. I have set up an environment variable:
export FILE_PATH="file-path"
Then I tried to read the file in my node script:
const fs = require('fs');
console.log(process.env.FILE_PATH); // gives correct path.
const data = fs.readFileSync((process.env.FILE_PATH || ""), 'utf8');
But I'm getting "no such file or directory" error in debugger. The file is existing and has required permissions. If I give the path directly instead of taking from env variable, it will work.
I figured out the root cause of this issue. All the environment variables I set has a ‘\r’ in the end.
console.log(process.env) gives the output:
...
FILE_PATH: '/tmp/file.txt\r',
...
As a quick fix I used trim() to remove the extra character:
const data = fs.readFileSync((process.env.FILE_PATH.trim() || ""), 'utf8');
You may need to parse your path with Node.js's path module. Something like:
const data = fs.readFileSync(path.resolve((process.env.FILE_PATH || "")), 'utf8');

Combine two json files to give a set of variables to use in Gulp

I have seen lots of posts online about how to use a set of variables defined in a file using a require statement.
I want to know how I can use two files.
For example, in pseudo...
gulp --env=prod
if (env):
defaultConfig = require('./config/default.json')
envConfig = require('./config/prod.json')
config = combine(defaultConfig, envConfig)
else:
config = require('./config/default.json')
// Now i can access everything like so...
console.log(config.name)
console.log(config.minify)
This keeps by config DRY and also means I don't have to create a new file for every environment I have.
I'm new to Gulp but i thought this would be a common requirement however, Google hasn't turned up anything for having defaults merged with env specific settings.
Do i need to write a node module?
You can do it with ES6 function Object.assign:
gulp --env=prod
if (env):
defaultConfig = JSON.parse(require('./config/default.json'))
envConfig = JSON.parse(require('./config/prod.json'))
config = Object.assign(defaultConfig, envConfig)
else:
config = JSON.parse(require('./config/default.json'))
// Now i can access everything like so...
console.log(config.name)
console.log(config.minify)
ES6 is supported in Node so you can use it whenever you want.
EDIT: If you have older versions of Node, you can use extend like Sven Schoenung suggest.
Use yargs to parse command line arguments and extend to combine the two config objects:
var gulp = require('gulp');
var argv = require('yargs').argv;
var extend = require('extend');
var config = extend(
require('./config/default.json'),
(argv.env) ? require('./config/' + argv.env + '.json') : {}
);
gulp.task('default', function() {
console.log(config);
});
Running gulp --env=prod will print the combined config, while simply running gulp will print the default config.
Use the following function :
function combine(a,b){
var temp0 = JSON.stringify(a);
var temp1 = temp0.substring(0, temp0.length-1);
var temp2 = (JSON.stringify(b)).substring(1);
var temp3 = temp1 + "," + temp2;
return JSON.parse(temp3);
}

Meteor project path from a smartpackage

I was looking for a way to look up the meteor project path from a smart package (e.g.: obtain the path of the directory where the .meteor folder is ...).
I was not able to do it using node's __dirname and __filename because somehow in meteor they are not avaiable.
Any tips ?
As of Meteor 0.6.0 this would be:
var path = Npm.require('path');
var basepath = path.resolve('.');
From a smartpackage (0.6.5+):
var path = Npm.require('path');
var base = path.resolve('.');
base in this case gets you the position of your package ..
/User/username/projects/project/.meteor/local/programm/server/...
.. might even be deeper
but we want
/User/username/projects/project/
.. so split at .meteor
base = base.split('.meteor')[0];
Or as two-liner
var path = Npm.require('path');
var base = path.resolve('.').split('.meteor')[0];;
This works for me in Meteor 0.5.0:
var require = __meteor_bootstrap__.require;
var path = require('path');
var basepath = (path.resolve('.'));
You can actually get access to node:
var __dirname = __meteor_bootstrap__.__dirname;
You could try (only on server side)
process.env.PWD which returns something like that for me (OSX):
'/Users/myusername/Desktop/myproject'
With that command you get the root of meteor project.

Resources