In my node app, I want to set production and development in my config.js file.
For that I have all most set all thing but I'm still missing something.
I want to get config data like database credential from config file based on my development mode. If I upload on live then app will use live cred. On other hand if I used local then it should be use local cred.
module.exports = function () {
console.log("Process env is ::: ", process.env.NODE_ENV);
if (process.env.NODE_ENV == 'production') {
return {
db : {
host:'localhost',
batabase:'dbname',
username:'',
password:''
}
}
} else {
return {
db : {
host:'localhost',
batabase:'dbname',
username:'',
password:''
}
}
}
};
I have taken ref from this answer
Just try this way.
module.exports = (function () {
process.env.NODE_ENV='development';
if(process.env.NODE_ENV === 'production'){
// Config data of Live
}else{
//Config data of Local
}
})()
This works for me. :)
process.env refers to the Environment Variables exists at the time you start you nodejs app . (it's part of the os)
When you deploy to cloud , usually it's handled for you already (process.env.NODE_ENV = production) .
Some cloud providers even give you the option to control it via a GUI .
But for local environment , you can use .dotenv package . (https://github.com/motdotla/dotenv)
With this package you create a .env file at the top of your project ,
and just write down NODE_ENV = local/staging/production
Please note that you can always run in shell:
export NODE_ENV=production
(WATCH FOR WHITESPACES !)
before you start you nodejs app which will also give you the effect
of controlling process.env
Using the config files in other files, just by requiring it .
const config = require('path/to/config.js');
then config.data.host will be changed depend on the NODE_ENV
Related
Is there any way to externalize completely environment variables (secret keys included) in a React app in a DevOps context?
We want to automate our builds for different environments (each environment has its own environment variables).
We have looked into environment variables in React using Webpack, but it doesn't quite satisfy our need and we can't externalize environment variables with this approach. Besides, we would have to explicitly declare all these variables inside webpack config file, which would be bloated if we did this.
We think that the best way to go is to put api secrets in Firebase and runtime specifics inside a jenkins script.
We are using Jenkins as our CI/CD server and the app runs is deployed with nginx in a Docker container.
You may create two .env files, .env and .env.prod at the root level and can define your particular 'variables' related to specific environment into these env files. Then in your code you should be able to access them through process.env.NODE_ENV
if(process.env.NODE_ENV === "production"){
//Execute this in production environment
var url= `${process.env.REACT_APP_AC_ORIGIN}/`;
url = url + ...,
}else{
//Execute this in dev environment
var url= `${process.env.REACT_APP_AC_ORIGIN}/`;
url = url + ...,
}
.env
REACT_APP_AC_ORIGIN=https://example1.com
.env.prod
REACT_APP_AC_ORIGIN=https://example2.com
If you have multiple environments, say, production, staging, QA, and so on, you may even consider generating dynamic URLS assuming that different environments will be accessed by different hostnames in the browser, Something like this:
api-config.js
let backendHost;
const apiVersion = 'v1';
const hostname = window && window.location && window.location.hostname;
if(hostname === 'realsite.com') {
backendHost = 'https://api.realsite.com';
} else if(hostname === 'staging.realsite.com') {
backendHost = 'https://staging.api.realsite.com';
} else if(/^qa/.test(hostname)) {
backendHost = `https://api.${hostname}`;
} else {
backendHost = process.env.REACT_APP_BACKEND_HOST || 'http://localhost:8080';
}
export const API_ROOT = `${backendHost}/api/${apiVersion}`;
And then you can import it like this:
import { API_ROOT } from './api-config';
function getUsers() {
return fetch(`${API_ROOT}/users`)
.then(res => res.json)
.then(json => json.data.users);
}
OR, you can define your variables at run time on different environments.
$ REACT_APP_API_HOST=example.com yarn run build
# The resulting app would have
# process.env.REACT_APP_API_HOST === "example.com"
# process.env.NODE_ENV === "production"
Ref : https://daveceddia.com/multiple-environments-with-react/
in server code I have this:
import express from "express";
const server = express();
import path from "path";
// const expressStaticGzip = require("express-static-gzip");
import expressStaticGzip from "express-static-gzip";
import webpack from "webpack";
import webpackHotServerMiddleware from "webpack-hot-server-middleware";
import configDevClient from "../../config/webpack.dev-client";
import configDevServer from "../../config/webpack.dev-server.js";
import configProdClient from "../../config/webpack.prod-client.js";
import configProdServer from "../../config/webpack.prod-server.js";
const isProd = process.env.NODE_ENV === "production";
const isDev = !isProd;
const PORT = process.env.PORT || 8000;
let isBuilt = false;
const done = () => {
!isBuilt &&
server.listen(PORT, () => {
isBuilt = true;
console.log(
`Server listening on http://localhost:${PORT} in ${process.env.NODE_ENV}`
);
});
};
if (isDev) {
const compiler = webpack([configDevClient, configDevServer]);
const clientCompiler = compiler.compilers[0];
const serverCompiler = compiler.compilers[1];
const webpackDevMiddleware = require("webpack-dev-middleware")(
compiler,
configDevClient.devServer
);
const webpackHotMiddlware = require("webpack-hot-middleware")(
clientCompiler,
configDevClient.devServer
);
server.use(webpackDevMiddleware);
server.use(webpackHotMiddlware);
console.log("process.env.NODE_ENV",process.env.NODE_ENV);//RETURNS UNDEFINED
server.use(webpackHotServerMiddleware(compiler));
console.log("Middleware enabled");
done();
} else {
webpack([configProdClient, configProdServer]).run((err, stats) => {
const clientStats = stats.toJson().children[0];
const render = require("../../build/prod-server-bundle.js").default;
server.use(
expressStaticGzip("dist", {
enableBrotli: true
})
);
server.use(render({ clientStats }));
done();
});
}
I client and server config files I have this plugin enabled:
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify("development"),
WEBPACK: true
}
but this is the output
process.env.NODE_ENV undefined
Server listening on http://localhost:8000 in undefined
in client side it is working BUT express side process.env.NODE_ENV returns undefined
Assuming you using Webpack-Dev-Server, you can use this call syntax witch is proper :
const dev = Boolean( process.env.WEBPACK_DEV_SERVER )
You will no longer need to pass environment type parameters, because I think you pass parameters in your script run in packages.json
I'm writing my experience to help anyone out there with this problem, though I did not actually solve it. I had the same problem with setting the environment variables in my server-side project.
apparently, after you set the environment variables they are completely accessible in the building process, which is in the build tools like webpack config or even .babelrc.js.
but after the build process, the environment variables get overwritten AND there is a time gap between build process and overwriting environment variables.
I used many webpack or babel plugins but neither of them could hold on to environment variables after the build process ON the server-side but they were immediately defined on the client-side.
since I'm using ReactJs, I tried adding REACT_APP_ to the beginning of variables, but still no luck.
some other plugins I used: webpack dotenv, webpack.DefinePlugin, webpack.EnvironmentPlugin, babel-plugin-transform-define, babel-plugin-transform-inline-environment-variables
so it made me use the good old-fashion way of setting environment.js on DEPLOY but not on the BUILD process.
in case someone is not familiar: you have one main environment.js and (in my case) 2 other files, one for staging environment.staging.js and one for production environment.prod.js. On each deploy, you copy the related js to environment.js, the main environment file, and in your code, you always read global CONSTs,baseUrl for APIs and ... from environment.js.
hope it helps someone out there.
Looking for elegant and simple solution to have "local configuration override" files.
The idea is to be able to have local configuration that will not ask to be added to git repository every time.
For that I need to include local.config.js if it exists.
I have global app configuration in config.js with configuration like
export const config = {
API_URL="https://some.host",
}
and config.local.js
export const config = {
API_URL="https://other.address",
}
there's .gitignore:
config.local.js
Difficulty:
I do not want to add a node module to project just for this one thing. I believe there should be an elegant way to do this in one or few lines, but have not found any so far.
Things that I tried:
1.
try {
const {
apiUrl: API_URL,
} = require('./config.local.js');
config. API_URL =apiUrl;
} catch (e) {
}
require does not work inside try{} block.
2.
const requireCustomFile = require.context('./', false, /config.local.js$/);
requireCustomFile.keys().forEach(fileName => {
requireCustomFile(fileName);
});
does not work.
3.
export const config = require('./config.local.js') || {default:'config = {...}'}
does not work.
4.
Using .env and settings environment variable: I need to override whole array of configuration values. Not one by one.
This solution uses process.argv. It is native to node as documented here and does not use .env
It inspects the command values used to start the app. Since these should be different between your local and production environments, it's an easy way to switch with no additional modules required.
command prompt to start your node app:
(this might also be in package.json and incurred via npm start if you're using that approach.)
$ node index.js local
index.js of your node app:
var express = require('express');
var config = require('./config');
if (process.argv[2] === 'local') {
// the 3rd argument provided at startup (2nd index) was 'local', so here we are!
config = require('./config_local');
}
var app = express();
// rest of owl…
I'm trying to find out there the best solution about how to store environment vars for Node using Express. Many tutorials suggest to move the data into a .json file, here is an example but the don't config environment vars, they define new vars such as:
{
"test": {
"facebook_app_id": "facebook_dummy_dev_app_id",
"facebook_app_secret": "facebook_dummy_dev_app_secret",
},
"development": {
"facebook_app_id": "facebook_dummy_dev_app_id",
"facebook_app_secret": "facebook_dummy_dev_app_secret",
},
"production": {
"facebook_app_id": "facebook_dummy_prod_app_id",
"facebook_app_secret": "facebook_dummy_prod_app_secret",
}
}
The problem I've find to this approach is that I can't define vars in it, because all elements must be inside double quotes ( " ) so I can't do:
{
process.env.PORT = 3000,
process.env.NODE_APP = XXX
....
}
I've tried to do some tricky things like defining a .js file and store there the vars, something like this:
module.exports = {
env: {
USER:"www-data",
NODE_ENV:"development",
PORT:"3002",
....
LOG_FILE:"error.log"
}
}
In this case, I have not found the way to use those vars inside env, something like:
module.exports = {
env: {
...
process.env.APP_NAME:"application.name",
process.env.NODEJS_DIR:"/var/nodejs",
process.env.APP_DIR: `${this.NODEJS_DIR}/${this.APP_NAME}/current`, //Not working
process.env.APP_DIR:process.env.NODEJS_DIR}/${this.APP_NAME}/current`, //Not working, and verbose, ugly code
....
}
}
Is there a better way to solve this?
Thanks
You can use dotenv module to achieve this.
So in your root directory, create 2 files (depending on how many different environments you might have) named development.env and production.env
In your app, do this:
var env = process.env.NODE_ENV || 'development';
require('dotenv').config({
path: './' + env + '.env'
});
Then you could access all the environment variables you have defined in the respective env file.
Something like this you are looking for.
app.configure('production', function(){
// production env. specific settings
});
As another example of forming the config file
// config file in /config/general.js
var path = require('path'),
rootPath = path.normalize(__dirname + '/..'),
env = process.env.NODE_ENV || 'development';
if (env == 'development') {
process.env.DEBUG = 'http';
}
var config = {
development: {
name : 'development',
root: rootPath,
port: 3000
},
production: {
name : 'prod',
root: rootPath,
port: 3000
}
};
module.exports = config[env];
Think about the dev-ops team, how they will deploy your software? They won't touch the code, and the configuration file should not contain any logic. So the .js file containing configurations is wrong. You have to provide them an interface to configure the execution. That may be a parameter, or if the configuration is complex, then it should be extracted to a configuration file.
My approach is to load app.json by default. If the dev-ops engeneer provides NODE_ENV=customenv, then load app.customenv.json configuration file. This way the .json file won't expose non-relevant development configurations to the users.
APP_NAME is not part of the environment, but part of your software configuration. This parameter should be configured in the .json configuration file.
Directories can be relevant to the software directory, it defined in the __dirname variable.
The app.json file should be loaded by a configuration module. You can use one of the open-source projects available, for example nconf.
hi am new to nodejs environment.
am using nodeJs + compoundjs.
am having three database environment development. production and test. my question in when i run the NODE_ENV=production node . command, all url's,port number and other things should get from production.js. when i shift the node environment by giving command NODE_ENV=development node . all things need to run should get from development.js.
any notes for this also helpful for me.
if anybody has any idea please share with me.
You have to set the Environment and then you can configure your app like:
(This is a mongoose db and express, but you can find similar configurations.)
Simply set up three environment configurations
app.configure('development', function () {
mongoose.connect(devConfig.db.path, function onMongooseError(err) {
});
});
app.configure('production', function () {
mongoose.connect(proConfig.db.path, function onMongooseError(err) {
});
});
a configuration example (config.js) :
var config = {};
// Database (MongoDB) configurations
config.db = {
path : 'mongodb://localhost/sampleDatabase'
};
module.exports = config;
I require this file in my app.js by var config = require('config')
You could do the Environment detection in the config file as well.