Node.js global variables

Javascriptnode.jsExpress

Javascript Problem Overview


I asked here: https://stackoverflow.com/questions/5348685/node-js-require-inheritance

And I was told that I can set variables to the global scope by leaving out the variable.

This does not work for me.

That is, the following does not make the _ available on required files.

_ = require('underscore');

I can set with Express.js's app.set and have it available elsewhere though.

Is that how this is supposed to work?

Javascript Solutions


Solution 1 - Javascript

You can use global like so:

global._ = require('underscore')

Solution 2 - Javascript

In Node.js, you can set global variables via the "global" or "GLOBAL" object:

GLOBAL._ = require('underscore'); // But you "shouldn't" do this! (see note below)

or more usefully...

GLOBAL.window = GLOBAL;  // Like in the browser

From the Node.js source, you can see that these are aliased to each other:

node-v0.6.6/src/node.js:
28:     global = this;
128:    global.GLOBAL = global;

In the code above, "this" is the global context. With the CommonJS module system (which Node.js uses), the "this" object inside of a module (i.e., "your code") is not the global context. For proof of this, see below where I spew the "this" object and then the giant "GLOBAL" object.

console.log("\nTHIS:");
console.log(this);
console.log("\nGLOBAL:");
console.log(global);




/* Outputs ...




THIS:
{}




GLOBAL:
{ ArrayBuffer: [Function: ArrayBuffer],
Int8Array: { [Function] BYTES_PER_ELEMENT: 1 },
Uint8Array: { [Function] BYTES_PER_ELEMENT: 1 },
Int16Array: { [Function] BYTES_PER_ELEMENT: 2 },
Uint16Array: { [Function] BYTES_PER_ELEMENT: 2 },
Int32Array: { [Function] BYTES_PER_ELEMENT: 4 },
Uint32Array: { [Function] BYTES_PER_ELEMENT: 4 },
Float32Array: { [Function] BYTES_PER_ELEMENT: 4 },
Float64Array: { [Function] BYTES_PER_ELEMENT: 8 },
DataView: [Function: DataView],
global: [Circular],
process:
{ EventEmitter: [Function: EventEmitter],
title: 'node',
assert: [Function],
version: 'v0.6.5',
_tickCallback: [Function],
moduleLoadList:
[ 'Binding evals',
'Binding natives',
'NativeModule events',
'NativeModule buffer',
'Binding buffer',
'NativeModule assert',
'NativeModule util',
'NativeModule path',
'NativeModule module',
'NativeModule fs',
'Binding fs',
'Binding constants',
'NativeModule stream',
'NativeModule console',
'Binding tty_wrap',
'NativeModule tty',
'NativeModule net',
'NativeModule timers',
'Binding timer_wrap',
'NativeModule _linklist' ],
versions:
{ node: '0.6.5',
v8: '3.6.6.11',
ares: '1.7.5-DEV',
uv: '0.6',
openssl: '0.9.8n' },
nextTick: [Function],
stdout: [Getter],
arch: 'x64',
stderr: [Getter],
platform: 'darwin',
argv: [ 'node', '/workspace/zd/zgap/darwin-js/index.js' ],
stdin: [Getter],
env:
{ TERM_PROGRAM: 'iTerm.app',
'COM_GOOGLE_CHROME_FRAMEWORK_SERVICE_PROCESS/USERS/DDOPSON/LIBRARY/APPLICATION_SUPPORT/GOOGLE/CHROME_SOCKET': '/tmp/launch-nNl1vo/ServiceProcessSocket',
TERM: 'xterm',
SHELL: '/bin/bash',
TMPDIR: '/var/folders/2h/2hQmtmXlFT4yVGtr5DBpdl9LAiQ/-Tmp-/',
Apple_PubSub_Socket_Render: '/tmp/launch-9Ga0PT/Render',
USER: 'ddopson',
COMMAND_MODE: 'unix2003',
SSH_AUTH_SOCK: '/tmp/launch-sD905b/Listeners',
__CF_USER_TEXT_ENCODING: '0x12D732E7:0:0',
PATH: '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:~/bin:/usr/X11/bin',
PWD: '/workspace/zd/zgap/darwin-js',
LANG: 'en_US.UTF-8',
ITERM_PROFILE: 'Default',
SHLVL: '1',
COLORFGBG: '7;0',
HOME: '/Users/ddopson',
ITERM_SESSION_ID: 'w0t0p0',
LOGNAME: 'ddopson',
DISPLAY: '/tmp/launch-l9RQXI/org.x:0',
OLDPWD: '/workspace/zd/zgap/darwin-js/external',
_: './index.js' },
openStdin: [Function],
exit: [Function],
pid: 10321,
features:
{ debug: false,
uv: true,
ipv6: true,
tls_npn: false,
tls_sni: true,
tls: true },
kill: [Function],
execPath: '/usr/local/bin/node',
addListener: [Function],
_needTickCallback: [Function],
on: [Function],
removeListener: [Function],
reallyExit: [Function],
chdir: [Function],
debug: [Function],
error: [Function],
cwd: [Function],
watchFile: [Function],
umask: [Function],
getuid: [Function],
unwatchFile: [Function],
mixin: [Function],
setuid: [Function],
setgid: [Function],
createChildProcess: [Function],
getgid: [Function],
inherits: [Function],
_kill: [Function],
_byteLength: [Function],
mainModule:
{ id: '.',
exports: {},
parent: null,
filename: '/workspace/zd/zgap/darwin-js/index.js',
loaded: false,
exited: false,
children: [],
paths: [Object] },
_debugProcess: [Function],
dlopen: [Function],
uptime: [Function],
memoryUsage: [Function],
uvCounters: [Function],
binding: [Function] },
GLOBAL: [Circular],
root: [Circular],
Buffer:
{ [Function: Buffer]
poolSize: 8192,
isBuffer: [Function: isBuffer],
byteLength: [Function],
_charsWritten: 8 },
setTimeout: [Function],
setInterval: [Function],
clearTimeout: [Function],
clearInterval: [Function],
console: [Getter],
window: [Circular],
navigator: {} }
*/

GLOBAL: { ArrayBuffer: [Function: ArrayBuffer], Int8Array: { [Function] BYTES_PER_ELEMENT: 1 }, Uint8Array: { [Function] BYTES_PER_ELEMENT: 1 }, Int16Array: { [Function] BYTES_PER_ELEMENT: 2 }, Uint16Array: { [Function] BYTES_PER_ELEMENT: 2 }, Int32Array: { [Function] BYTES_PER_ELEMENT: 4 }, Uint32Array: { [Function] BYTES_PER_ELEMENT: 4 }, Float32Array: { [Function] BYTES_PER_ELEMENT: 4 }, Float64Array: { [Function] BYTES_PER_ELEMENT: 8 }, DataView: [Function: DataView], global: [Circular], process: { EventEmitter: [Function: EventEmitter], title: 'node', assert: [Function], version: 'v0.6.5', _tickCallback: [Function], moduleLoadList: [ 'Binding evals', 'Binding natives', 'NativeModule events', 'NativeModule buffer', 'Binding buffer', 'NativeModule assert', 'NativeModule util', 'NativeModule path', 'NativeModule module', 'NativeModule fs', 'Binding fs', 'Binding constants', 'NativeModule stream', 'NativeModule console', 'Binding tty_wrap', 'NativeModule tty', 'NativeModule net', 'NativeModule timers', 'Binding timer_wrap', 'NativeModule _linklist' ], versions: { node: '0.6.5', v8: '3.6.6.11', ares: '1.7.5-DEV', uv: '0.6', openssl: '0.9.8n' }, nextTick: [Function], stdout: [Getter], arch: 'x64', stderr: [Getter], platform: 'darwin', argv: [ 'node', '/workspace/zd/zgap/darwin-js/index.js' ], stdin: [Getter], env: { TERM_PROGRAM: 'iTerm.app', 'COM_GOOGLE_CHROME_FRAMEWORK_SERVICE_PROCESS/USERS/DDOPSON/LIBRARY/APPLICATION_SUPPORT/GOOGLE/CHROME_SOCKET': '/tmp/launch-nNl1vo/ServiceProcessSocket', TERM: 'xterm', SHELL: '/bin/bash', TMPDIR: '/var/folders/2h/2hQmtmXlFT4yVGtr5DBpdl9LAiQ/-Tmp-/', Apple_PubSub_Socket_Render: '/tmp/launch-9Ga0PT/Render', USER: 'ddopson', COMMAND_MODE: 'unix2003', SSH_AUTH_SOCK: '/tmp/launch-sD905b/Listeners', __CF_USER_TEXT_ENCODING: '0x12D732E7:0:0', PATH: '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:~/bin:/usr/X11/bin', PWD: '/workspace/zd/zgap/darwin-js', LANG: 'en_US.UTF-8', ITERM_PROFILE: 'Default', SHLVL: '1', COLORFGBG: '7;0', HOME: '/Users/ddopson', ITERM_SESSION_ID: 'w0t0p0', LOGNAME: 'ddopson', DISPLAY: '/tmp/launch-l9RQXI/org.x:0', OLDPWD: '/workspace/zd/zgap/darwin-js/external', _: './index.js' }, openStdin: [Function], exit: [Function], pid: 10321, features: { debug: false, uv: true, ipv6: true, tls_npn: false, tls_sni: true, tls: true }, kill: [Function], execPath: '/usr/local/bin/node', addListener: [Function], _needTickCallback: [Function], on: [Function], removeListener: [Function], reallyExit: [Function], chdir: [Function], debug: [Function], error: [Function], cwd: [Function], watchFile: [Function], umask: [Function], getuid: [Function], unwatchFile: [Function], mixin: [Function], setuid: [Function], setgid: [Function], createChildProcess: [Function], getgid: [Function], inherits: [Function], _kill: [Function], _byteLength: [Function], mainModule: { id: '.', exports: {}, parent: null, filename: '/workspace/zd/zgap/darwin-js/index.js', loaded: false, exited: false, children: [], paths: [Object] }, _debugProcess: [Function], dlopen: [Function], uptime: [Function], memoryUsage: [Function], uvCounters: [Function], binding: [Function] }, GLOBAL: [Circular], root: [Circular], Buffer: { [Function: Buffer] poolSize: 8192, isBuffer: [Function: isBuffer], byteLength: [Function], _charsWritten: 8 }, setTimeout: [Function], setInterval: [Function], clearTimeout: [Function], clearInterval: [Function], console: [Getter], window: [Circular], navigator: {} } */

** Note: regarding setting "GLOBAL._", in general you should just do var _ = require('underscore');. Yes, you do that in every single file that uses Underscore.js, just like how in Java you do import com.foo.bar;. This makes it easier to figure out what your code is doing because the linkages between files are 'explicit'. It is mildly annoying, but a good thing. .... That's the preaching.

There is an exception to every rule. I have had precisely exactly one instance where I needed to set "GLOBAL._". I was creating a system for defining "configuration" files which were basically JSON, but were "written in JavaScript" to allow a bit more flexibility. Such configuration files had no 'require' statements, but I wanted them to have access to Underscore.js (the entire system was predicated on Underscore.js and Underscore.js templates), so before evaluating the "configuration", I would set "GLOBAL._". So yeah, for every rule, there's an exception somewhere. But you had better have a darn good reason and not just "I get tired of typing 'require', so I want to break with the convention".

Solution 3 - Javascript

The other solutions that use the GLOBAL keyword are a nightmare to maintain/readability (+namespace pollution and bugs) when the project gets bigger. I've seen this mistake many times and had the hassle of fixing it.

Use a JavaScript file and then use module exports.

Example:

File globals.js
var Globals = {
    'domain':'www.MrGlobal.com';
}

module.exports = Globals;

Then if you want to use these, use require.

var globals = require('globals'); // << globals.js path
globals.domain // << Domain.

Solution 4 - Javascript

Use a global namespace like global.MYAPI = {}:

global.MYAPI._ = require('underscore')

All other posters talk about the bad pattern involved. So leaving that discussion aside, the best way to have a variable defined globally (OP's question) is through namespaces.

Tip: Development Using Namespaces

Solution 5 - Javascript

You can just use the global object.

var X = ['a', 'b', 'c'];
global.x = X;

console.log(x);
//['a', 'b', 'c']

Solution 6 - Javascript

I agree that using the global/GLOBAL namespace for setting anything global is bad practice and don't use it at all in theory (in theory being the operative word). However (yes, the operative) I do use it for setting custom Error classes:

// Some global/configuration file that gets called in initialisation

global.MyError = [Function of MyError];

Yes, it is taboo here, but if your site/project uses custom errors throughout the place, you would basically need to define it everywhere, or at least somewhere to:

  1. Define the Error class in the first place
  2. In the script where you're throwing it
  3. In the script where you're catching it

Defining my custom errors in the global namespace saves me the hassle of require'ing my customer error library. Imaging throwing a custom error where that custom error is undefined.

Solution 7 - Javascript

In case you are trying to access strings globally, I recommend using dotenv:

Install with:

npm i dotenv

Then create the file .env in the project's root directory and set all of the variables you want to be global, for example:

DB_HOST='localhost'
DB_DATABASE='my_database'
DB_USER='my_user'
DB_PASSWORD='my_password'

ADMIN_EMAIL='[email protected]'
CITY='Some city'
# ... etc

You can even set these variables by the command line when starting the server like this:

NODE_ENV=dev PORT=5000 npm run start-dev

Also, if you use git, you likely want to add .env to your .gitignore to make sure you don't accidentally commit sensitive information.

Then just include the following at the beginning of your server.js file (or whatever the first file to be executed is)

require('dotenv').config()

To use these variables anywhere in your code, just use process.env.VARIABLE_NAME.

For example:

app.listen(process.env.PORT, () => {
    console.log(`Server is running on port ${process.env.PORT}.`)
})

Note: I understand this doesn't directly answer the question since it is about storing strings globally instead of Underscore.js, but I thought I would include it for completeness.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHarryView Question on Stackoverflow
Solution 1 - JavascriptmasylumView Answer on Stackoverflow
Solution 2 - JavascriptDave DopsonView Answer on Stackoverflow
Solution 3 - JavascriptOliver DixonView Answer on Stackoverflow
Solution 4 - JavascriptIgor ParraView Answer on Stackoverflow
Solution 5 - JavascriptJoao FalcaoView Answer on Stackoverflow
Solution 6 - JavascriptDrunkenBeetleView Answer on Stackoverflow
Solution 7 - JavascriptMikeView Answer on Stackoverflow