Share variables between files in Node.js?

265,971

Solution 1

Global variables are almost never a good thing (maybe an exception or two out there...). In this case, it looks like you really just want to export your "name" variable. E.g.,

// module.js
var name = "foobar";
// export it
exports.name = name;

Then, in main.js...

//main.js
// get a reference to your required module
var myModule = require('./module');

// name is a member of myModule due to the export above
var name = myModule.name;

Solution 2

I'm unable to find an scenario where a global var is the best option, of course you can have one, but take a look at these examples and you may find a better way to accomplish the same:

Scenario 1: Put the stuff in config files

You need some value that it's the same across the application, but it changes depending on the environment (production, dev or test), the mailer type as example, you'd need:

// File: config/environments/production.json
{
    "mailerType": "SMTP",
    "mailerConfig": {
      "service": "Gmail",
      ....
}

and

// File: config/environments/test.json
{
    "mailerType": "Stub",
    "mailerConfig": {
      "error": false
    }
}

(make a similar config for dev too)

To decide which config will be loaded make a main config file (this will be used all over the application)

// File: config/config.js
var _ = require('underscore');

module.exports = _.extend(
    require(__dirname + '/../config/environments/' + process.env.NODE_ENV + '.json') || {});

And now you can get the data like this:

// File: server.js
...
var config = require('./config/config');
...
mailer.setTransport(nodemailer.createTransport(config.mailerType, config.mailerConfig));

Scenario 2: Use a constants file

// File: constants.js
module.exports = {
  appName: 'My neat app',
  currentAPIVersion: 3
};

And use it this way

// File: config/routes.js

var constants = require('../constants');

module.exports = function(app, passport, auth) {
  var apiroot = '/api/v' + constants.currentAPIVersion;
...
  app.post(apiroot + '/users', users.create);
...

Scenario 3: Use a helper function to get/set the data

Not a big fan of this one, but at least you can track the use of the 'name' (citing the OP's example) and put validations in place.

// File: helpers/nameHelper.js

var _name = 'I shall not be null'

exports.getName = function() {
  return _name;
};

exports.setName = function(name) {
  //validate the name...
  _name = name;
};

And use it

// File: controllers/users.js

var nameHelper = require('../helpers/nameHelper.js');

exports.create = function(req, res, next) {
  var user = new User();
  user.name = req.body.name || nameHelper.getName();
  ...

There could be a use case when there is no other solution than having a global var, but usually you can share the data in your app using one of these scenarios, if you are starting to use node.js (as I was sometime ago) try to organize the way you handle the data over there because it can get messy really quick.

Solution 3

If we need to share multiple variables use the below format

//module.js
   let name='foobar';
   let city='xyz';
   let company='companyName';

   module.exports={
    name,
    city,
    company
  }

Usage

  // main.js
    require('./modules');
    console.log(name); // print 'foobar'

Solution 4

Save any variable that want to be shared as one object. Then pass it to loaded module so it could access the variable through object reference..

// main.js
var myModule = require('./module.js');
var shares = {value:123};

// Initialize module and pass the shareable object
myModule.init(shares);

// The value was changed from init2 on the other file
console.log(shares.value); // 789

On the other file..

// module.js
var shared = null;

function init2(){
    console.log(shared.value); // 123
    shared.value = 789;
}

module.exports = {
    init:function(obj){
        // Save the shared object on current module
        shared = obj;

        // Call something outside
        init2();
    }
}

Solution 5

Not a new approach but a bit optimized. Create a file with global variables and share them by export and require. In this example, Getter and Setter are more dynamic and global variables can be readonly. To define more globals, just add them to globals object.

global.js

const globals = {
  myGlobal: {
    value: 'can be anytype: String, Array, Object, ...'
  },
  aReadonlyGlobal: {
    value: 'this value is readonly',
    protected: true
  },
  dbConnection: {
    value: 'mongoClient.db("database")'
  },
  myHelperFunction: {
    value: function() { console.log('do help') }
  },
}

exports.get = function(global) {
  // return variable or false if not exists
  return globals[global] && globals[global].value ? globals[global].value : false;
};

exports.set = function(global, value) {
  // exists and is protected: return false
  if (globals[global] && globals[global].protected && globals[global].protected === true)
    return false;
  // set global and return true
  globals[global] = { value: value };
  return true;
};

examples to get and set in any-other-file.js

const globals = require('./globals');

console.log(globals.get('myGlobal'));
// output: can be anytype: String, Array, Object, ...

globals.get('myHelperFunction')();
// output: do help

let myHelperFunction = globals.get('myHelperFunction');
myHelperFunction();
// output: do help

console.log(globals.set('myGlobal', 'my new value'));
// output: true
console.log(globals.get('myGlobal'));
// output: my new value

console.log(globals.set('aReadonlyGlobal', 'this shall not work'));
// output: false
console.log(globals.get('aReadonlyGlobal'));
// output: this value is readonly

console.log(globals.get('notExistingGlobal'));
// output: false
Share:
265,971

Related videos on Youtube

never_had_a_name
Author by

never_had_a_name

Updated on August 18, 2021

Comments

  • never_had_a_name
    never_had_a_name almost 3 years

    Here are 2 files:

    // main.js
    require('./modules');
    console.log(name); // prints "foobar"
    
    // module.js
    name = "foobar";
    

    When I don't have "var" it works. But when I have:

    // module.js
    var name = "foobar";
    

    name will be undefined in main.js.

    I have heard that global variables are bad and you better use "var" before the references. But is this a case where global variables are good?

  • appsthatmatter
    appsthatmatter about 11 years
    global variables are bad - I totally agree with that. But I could be, that the module has a dependency to a variable. Is there a way to pass this variable to the other js-file via the require function?
  • jmar777
    jmar777 about 11 years
    @jjoe64 Not sure I follow what you mean. You can effectively share any value you want through the exports object.
  • designermonkey
    designermonkey about 10 years
    The OP is asking whether a variable can be defined in the main.js, and then used in module.js. I have the same requirement to define paths that are used over and over again.
  • jmar777
    jmar777 about 10 years
    @Designermonkey In that case you're probably better off having a config object with those types of values that can also be require()'d into a given file. Note that you can just do global.foo = 'bar' and then access foo anywhere you'd like... but like I said in my original answer, that is almost never a good thing.
  • designermonkey
    designermonkey about 10 years
    Thanks for that, I figured out how to do that, and it works a treat. Thanks for verifying I had the right idea :)
  • Rubén Marrero
    Rubén Marrero almost 10 years
    Why are global variables bad? If I want to treat a module as an object is there any better way to store that object's propoerties/attributes?
  • BaldEagle
    BaldEagle over 6 years
    Do these fragments contradict? 1) "a variable declared with or without the var keyword got attached to the global object." and 2) "variables declared with the var keyword remain local to a module."
  • Mohamed Allal
    Mohamed Allal over 6 years
    just a quick note to left out confusion that can arise at first spot: module.exports is what should be used! whatever your js file is called (ex: global.js). module is a node object that exist in the global scope! [so within global.js we use module.exports=.....]
  • Kashif Ullah
    Kashif Ullah almost 6 years
    I liked Scenario 2, but can these values be changed after we talk build? like most often we do, npm run build. Or do you know some way to be able to change values after build?
  • Felipe Pereira
    Felipe Pereira almost 6 years
    @KashifUllah not sure if I'm able to answer your comment just with the provided info, you may want to add a new question in the site
  • Ahmad Zahabi
    Ahmad Zahabi over 4 years
    it will success if you remove the 'let', and there is no need to the "module.exports.."
  • Mike Kormendy
    Mike Kormendy almost 4 years
    @designermonkey how did you do that, please elaborate?
  • designermonkey
    designermonkey almost 4 years
    It was 10 years ago. I have no idea now. I suspect it was like the answer above.
  • user1063287
    user1063287 over 2 years
    is there a way to update values from module.js (e.g name, city, company) in all files that import it, so that the updated values are accessible to all files that have imported it? is there something like a 'dynamic global variable' that can be accessed and edited by whatever module references it? i have a question with more context here.