2

I'm writing a socket.io app, and I'm getting annoyed at having to chance a line in my frontend scripts.js file every time I push to heroku, from

var socket = io.connect('http://localhost');

to

var socket = io.connect('http://ersatz-elephant-1337.herokuapp.com/');

I know I can use process.env.VAR to access those variables on the backend, but I'm wondering if there's any way to programmatically determine which to use in my frontend scripts? I'd rather leave the scripts as static aside from this, but maybe that's not possible?

EDIT: I'm not really looking for a solution on the backend... I'm looking for a way that my /public/scripts.js file can connect to the right thing. I guess maybe the only way to do that is by specifying something special in server.js for the frontend script file, rather than serving it statically, but if so, then that's the instruction I'm looking for, not how to actually access the env vars on the server. Sorry for any confusion!

MalcolmOcean
  • 2,807
  • 2
  • 29
  • 38
  • It's not clear from your question as to when you determine which you wish to push to, either during execution or pre-execution. Do you decide which path while the script is running or do you know before hand? – Metalskin Jul 11 '13 at 02:55
  • ummm, pre-execution. Like it's a static file, it just needs to be something different on heroku than locally. – MalcolmOcean Jul 11 '13 at 03:55
  • 1
    I'd personally suggest using runtime parameters in that case. I don't like using environment variables, it always gets messy. If you use runtime params then you can always use a shell script to utilise environment variables if you wish. This is more a personal taste thing though. – Metalskin Jul 14 '13 at 22:07

4 Answers4

2

It's very possible. Either use foreman or use a configuration script like this one:

var url = require('url');
var config = {};
var dbUrl;

if (typeof(process.env.DATABASE_URL) !== 'undefined') {
    dbUrl = url.parse(process.env.DATABASE_URL);
}
else {
    dbUrl = url.parse('tcp://postgres:postgres@127.0.0.1:5432/db');
}

config.dialect = 'postgres';
config.protocol = dbUrl.protocol.substr(0, dbUrl.protocol.length - 1); // Remove trailing ':'
config.username = dbUrl.auth.split(':')[0];
config.password = dbUrl.auth.split(':')[1];
config.host = dbUrl.hostname;
config.port = dbUrl.port;
config.database = dbUrl.path.substring(1);

console.log('Using database ' + config.database);
module.exports = config;
Dan Kohn
  • 33,811
  • 9
  • 84
  • 100
  • but where does process.env.DATABASE_URL get set? – Dingredient Nov 12 '14 at 19:12
  • Set `DATABASE_URL` using foreman in development, and through other means on your production and CI hosts. For example, see https://devcenter.heroku.com/articles/config-vars – Dan Kohn Nov 12 '14 at 19:54
2

I just found this question 2.5 years later because SO told me it hit 1k views. I think the way I'd now solve this problem would be to say something like

var isLocal = ~location.href.indexOf('://localhost');

and then to just base my other variables off of that. It doesn't actually gives me the environment variables, but it solves the problem I had, of automatically knowing which path to use. (In this case, probably just saying io.connect('/') would have sufficed.)

MalcolmOcean
  • 2,807
  • 2
  • 29
  • 38
2

a way to do that is to use a conf.js file and a env.js file that will depend on the machine.

.gitignore

# it depends on the environement
env.js

conf.js

import ENV from './env.js'
const conf = {
  "dev": {
     url: '/'
  },
  "prod": {
     url: 'www.example.com'
  },
  "test": {
     url: 'www.example-test.com'
  }
}
export default conf[ENV]

env.js

// dev
export default "dev"

env.js

// prod
export default "prod"

that's it. now you can use it where you want.

index.js

import conf from './conf'
console.log("my env url is ", conf.url)

you can also make everything more automatic using grunt.js

Gruntfile.js

module.exports = function(grunt) {
  grunt.initConfig({});
  grunt.registerTask("env", function(envValue = 'dev') {
    grunt.file.write(
        "env.js",
        `/* AUTO GENERATED FILE FROM GRUNT */\n

        export default envValue;
        `
    );
});

}

now you have to change your script in package.json

{
  ...
  "scripts": {
     "build": "node scripts/build.js",
     "buildProd": "npm run grunt env:prod && npm run build",
      "buildTest": "npm run grunt env:test && npm run build"
  }
  ...
}

then run on command line

npm run buildProd
user3550446
  • 405
  • 3
  • 10
0

I know you asked for a solution using environment variables, however my view is that using runtime parameters is a better solution as it provides better flexibility.

As I stated above, you can then always use a shell script (as appropriate for the OS that your using) to set the runtime params based on environment variables if you so wish.

To use args, you use process.argv. you can do a forEach on this and iterate through the arguments (refer node.js manual process argv). Personally I would use a module. The one I like is called opt. It has lots of nice features and makes processing command line arguments very simple. You can specify defaults, define help messages for each param, etc. It even supports config files. I think you may find this appealing.

However, if you like the KISS approach, then I would suggest using process.argv.

If you are set on utilising environment variables within your script then you can always just use process.env.MY_ENV_VARIABLE where MY_ENV_VARIABLE is the environment variable (refer how to read environment variable in node js).

Community
  • 1
  • 1
Metalskin
  • 3,998
  • 5
  • 37
  • 61