58

I know that global variables are bad.

But if I am using node's module "util" in 40 files in my framework, isn't it better to just declare it as a global variable like:

util = require('util');

in the index.js file instead of writing that line in 40 files?

Cause I often use the same 5-10 modules in each file, that would save a lot of time instead of copy paste all the time.

Isn't DRY good in this case?

700 Software
  • 85,281
  • 83
  • 234
  • 341
ajsie
  • 77,632
  • 106
  • 276
  • 381
  • **FYI** Use `global` (lowercase) instead of `GLOBAL` (uppercase) per [node's deprecation warning](https://nodejs.org/api/deprecations.html#deprecations_dep0016_global_root) – KyleMit Jan 12 '20 at 04:17

6 Answers6

104

You could just have a common module.

common.js:

Common = {
  util: require('util'),
  fs:   require('fs'),
  path: require('path')
};

module.exports = Common;

app.js:

var Common = require('./common.js');
console.log(Common.util.inspect(Common));
Robin Duckett
  • 2,094
  • 3
  • 16
  • 15
  • 1
    This is an excellent idea. In fact, since require's `exports` object is cached, there would be no extra cost in reading the files for the unused requires. (you can test that it is cached by adding a `console.log` line to your `common.js` and notice that no matter how many times you require it, the `console.log` happens only the first time.) – 700 Software Mar 29 '11 at 19:51
  • I don't understand why this is better than just require(...) on each module, since that is cached? WHat is the difference? – Kato Dec 05 '11 at 20:19
  • 2
    @Kato: This is better (actually brilliant) because you now don't have to include 10 modules in each file, but instead just a single one. As you say, they're cached, so there's absolutely no overheat in doing so. – Sune Rasmussen Jan 29 '12 at 12:16
  • @Kato this is better too as you almost are giving yourself a namespace. – Robin Duckett Feb 03 '12 at 16:49
  • 20
    1. This creates a needless dependency. 2. It's saves little or creates more typing because now you either have "Common.x.whatever" instead of just "x.whatever" every place you use "whatever" or you alias it with "var x = Common.x" which is just like "var x = require(...)" but less clear if you don't already know what "x" is. 3. Refactoring usage of "x" now forces a search for both Common.x and require("x") because you can't be sure everyone used Common.x. If you use it so much why not just make a snippet "rutil > tab"? –  Sep 17 '12 at 19:53
  • I was struggling to get my code working in browser and nodejs, this answer helped me to solve the issue seemlessly, thanks a lot – webjockey May 13 '14 at 05:52
  • 1
    @user170934 1. Its not needless. 2. It saves a lot of headaches from circular dependencies and time spent thinking on what you need to require for each file, while providing a clear namespace which is used throughout the project. `let x = common.x` is also so much cleaner than many lines of `x = require()` statements. – Ricky Boyce Sep 07 '18 at 01:28
  • why i got / retrieve an object not string of the path ? – Yogi Arif Widodo Jan 23 '22 at 22:48
43

Each module is supposed to be independent. The require doesn't cost anything anyways after the first one for each module.

What if you wanted to test one module alone? You'd be having a lot of issues because it wouldn't recognize some "global" requires that you have in your app.

Yes, globals are bad, even in this case. Globals almost always ruin: testability, encapsulation and ease of maintenance.

Updated answer Jan. 2012

The global object is now a global inside each module. So every time you assign to a global variable (no scope) inside a module, that becomes part of the global object of that module.

The global object is therefore still not global, and cannot be used as such.

Updated Dec. 2012

The global object now has the global scope within the application and can be used to store any data/functions that need to be accessed from all modules.

Tor Valamo
  • 33,261
  • 11
  • 73
  • 81
  • @RadagasttheBrown well you should also consider that node doesn't support user made globals. – Tor Valamo Dec 31 '11 at 07:16
  • user made globals? can you elaborate? – Radagast the Brown Jan 10 '12 at 20:06
  • @RadagasttheBrown yeah i mean that node has internal globals but no way for the user to make any. The closest to making global vars is adding elements to the `process` object, but doing that for modules is not optimal, and you'd still have to call `process.modname` every time you wanted to use it. So no, there is no way to make globals. Also see http://stackoverflow.com/questions/4133114/global-object-in-node-js/4134152#4134152 – Tor Valamo Jan 10 '12 at 21:22
  • I think ```global``` object IS global in node according to [docs](http://nodejs.org/api/globals.html#globals_global_objects), although they use a bit confusing wording there. – esp Dec 24 '12 at 11:57
  • @esp You mean this paragraph? Read the last line especially. Also you just have to do a test for yourself (which I did) to confirm that there's no "global" global. "In browsers, the top-level scope is the global scope. That means that in browsers if you're in the global scope var something will define a global variable. **In Node this is different**. The top-level scope is not the global scope; **var something inside a Node module will be local to that module.**" – Tor Valamo Dec 26 '12 at 19:17
  • @TorValamo ```var something``` is local to module, but ```global``` is global and ```global.something``` is global too. Or am I wrong :)? – esp Dec 26 '12 at 21:27
  • @esp global is the object that holds module globals. So no matter where you access the global object, you will only get the global object that is tied to that particular module. – Tor Valamo Dec 26 '12 at 22:14
  • 3
    @TorValamo this does not seem to be correct, I've just made a test. Whatever you assign to ```global.something``` in one module is accessible from another module. So ```global``` holds process (=application) globals, not module globals, and ```global``` is the same object for all sessions. At least that's how it works for me. Can I ask you why do you say that ```global``` is local to a module? Did you make a test and if so then what was the test? – esp Dec 26 '12 at 23:10
  • @esp strange, i'm getting that too now after i upgraded node... but the documentation is incorrect then – Tor Valamo Dec 27 '12 at 00:19
  • 2
    @TorValamo it's a bit confusing indeed. They used only 1 line to say what ```global``` is, sparing us any explanation of how it works, and then 3 lines to rant why it's needed. Still [here](http://nodejs.org/api/globals.html#globals_global_objects) they say: "These objects are available in all modules. Some of these objects aren't actually in the global scope but in the module scope..." And [here](http://nodejs.org/api/globals.html#globals_global): "global: {Object} The global namespace object." ... Anyway, case closed, time to update the answer again :) Will you or should I? – esp Dec 27 '12 at 10:32
  • 2
    @esp feel free to update it, you seem to have more of the latest info about it than me ;) – Tor Valamo Dec 28 '12 at 15:52
  • Anybody have an opinion on global.prop vs process.env.prop? – Scott Silvi Jul 25 '14 at 02:52
  • @TorValamo I'm newbie to programming, Can you share some articles, that explains what is encapsulation and testablity. – Manjesh V Feb 23 '15 at 12:24
  • "Global's are bad" is an argument by assertion. Together use case, namespaces, and JavaScript unique single threaded nature invalidate this. – Ricky Boyce Sep 07 '18 at 01:39
25
global.util = require('util');

There's a section about global objects in the node documentation.

However, globals should be used with care. By adding modules to the global space you reduce testability and encapsulation. But there are cases where using this method is acceptable. For example, I add functions and objects to the global namespace to use within my unit test scripts.

esp
  • 7,314
  • 6
  • 49
  • 79
summatix
  • 577
  • 4
  • 9
  • 1
    the global object isn't the same as the global scope. your assignment basically assigns to nothingness. – Tor Valamo Nov 28 '10 at 02:52
  • 1
    @Kato - In node.js, the global object isn't an actual object you can script against. It's an internal object in the node.js engine. If you want to specifically use globals, you should use `process`, which is the equivalent to `window` in the browser. (although the process does not contain `setTimeout` and other 'globals', as those are global objects themselves). – Tor Valamo Dec 05 '11 at 20:21
22

I'm confused by the answers in this thread.

I am able to do this...

File: test.js

global.mytest = {
    x: 3,
    y: function() { console.log('Works.'); }
};

File: test2.js

console.log('Does this work?');
mytest.y();

File: server.js

require('test.js');
require('test2.js');

And it seems to work as the question needed. The first require places the mytest object into the global scope, then the second require can access that object without any other qualifiers.

I was trying to figure this out (which brought me to this thread from a Google search) and I wanted to post what seems to work for me now. Maybe things have changed since the original answers.

Dustin Graham
  • 2,054
  • 1
  • 20
  • 24
  • Yes, this was indeed changed in a recent version of Node. (Although "recent" is relatively speaking; that version of Node is now rather old.) – Zarel Jun 24 '14 at 04:18
0

I have successfully been using the process object for passing around my configuration object. While in theory suffering from the exact same issues as mentioned above (encapsulation, testability and so forth) it works fine when using only non-state modifying properties (a hash table with primitives, basically).

tedeh
  • 368
  • 2
  • 8
-3

If you wrap your modules in blocks (e.g. anon functions) you can bind to a local name (via parameter or 'var') and then have any arbitrary long (perhaps "package" labeled) name you want (if you even need a global at this point).

For instance, my modules often look similar to:

;(function ($, $exp, other) {
  $(...)
  other.xyz()
  $exp.MyExportedObject = ...;
})(jQuery, window, some_module.other_expression) // end module

I use jQuery with noConflict, this the former, and the latter show you can do this for any expression -- global, require, computed, in-line, whatever... this same "wrapping" approach can be used to eliminate all (or almost all) "special named" globals -- globals must exist at some level, however, removing potentially conflicts is a very big win.