44

I can't seem to find a description of the way I should export global variable from ES6 module. Is there a resource where it's defined?

The only solution that seems to work is referencing a global object, like window:

window['v'] = 3;

But what if this scripts runs in Node.js? Then I don't have window; I have global. But this code is not good:

var g = window || global;
g['v'] = 3;

I understand the concept of modules and don't use globals in my applications. However, having global variables during debugging in the console may be beneficial, especially when using bundlers like Webpack instead of loaders like SystemJs where you can easily import a module in a console.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • 2
    Personally, I don't think you should be able to instantiate a global from inside a module, in my mind, they are self-contained. If you want to have access to a variable from a module you need to include that variable in the export. – George Apr 25 '17 at 08:38
  • @George, see my update at the of the question – Max Koretskyi Apr 25 '17 at 08:48
  • So this question has very little to do with modules and is pretty much "What's the best way to define global variables when writing for nodeJS and JS that's run in the browser"? – George Apr 25 '17 at 08:52
  • There is a [global](https://github.com/tc39/proposal-global) proposal ([and polyfill](https://github.com/ljharb/System.global)). But it's been met with skepticism due to the issues George highlighted. If you are asking for Webpack-specific, there is the [DefinePlugin](https://webpack.js.org/plugins/define-plugin/). – CodingIntrigue Apr 25 '17 at 09:02
  • @CodingIntrigue, thanks a lot for the link, that's what I was looking for. You can post it as answer – Max Koretskyi Apr 25 '17 at 09:19
  • @George, as I understand, if the code is being executed as not part of a module, `this` at the top level points to the global object and there is no problems with that. `this` inside a module at the top level is `undefined. So this question is specific to the module functionality – Max Koretskyi Apr 28 '17 at 15:53
  • Possible duplicate of [JavaScript and ES6, "global" variables](https://stackoverflow.com/questions/33875322/javascript-and-es6-global-variables) – totymedli Oct 06 '17 at 01:51
  • There is one standard way to do it with `globalThis`. (cf. [MDM Docs](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/globalThis)) Regards, – 8HoLoN Jul 21 '20 at 15:07

3 Answers3

21

There are several ways to have global values available in your application.

Using ES6 modules, you can create a constant which you export from your module. You can then import this from any other module or component, like so:

/* Constants.js */
export default {
    VALUE_1: 123,
    VALUE_2: "abc"
};

/* OtherModule.js */
import Constants from '../Constants';

console.log(Constants.VALUE_1);
console.log(Constants.VALUE_2);

Alternatively, some JS bundling tools provide a way to pass values into your components at build time.

For example, if you're using Webpack, you can use DefinePlugin to configure a few constants available at compile time, like so:

/* Webpack configuration */
const webpack = require('webpack');

/* Webpack plugins definition */
new webpack.DefinePlugin({
    'VALUE_1': 123,
    'VALUE_2': 'abc'
});

/* SomeComponent.js */
if (VALUE_1 === 123) {
    // do something
}
Shishir
  • 2,488
  • 20
  • 22
4

You can grab the global object with an indirect eval call.

// this weird syntax grabs the global object
const global = (0,eval)("this");
// (0,eval) === eval; but the first one is an indirect evaluation
// inside indirect evaluation of eval, "this" is global object
// this takes advantage of that fact to identify "global"

// then set whatever global values you need
global.VALUE_1 = 123;
global.VALUE_2 = "abc";

You'll have to take care with the way your modules are loaded to ensure proper ordering.

more info: (1, eval)('this') vs eval('this') in JavaScript?

Rich Remer
  • 2,123
  • 1
  • 21
  • 22
  • 4
    <3 Me: oh wow ES6 modules came out. Step 1) how do I declare a global variable. ES6: not allowed. Let me get this straight. Vanilla JS: allowed. ES6: Not. ES6: If we gave you global variables all the miscreants would couple all their code together like spaghetti. Me: What if you're an FP software architect that knows better? ES6: middle finger. Seriously? Their decision to not allow globals is as bad as C#'s prohibition of no static defs outside of classes and namespaces. I code generate. A lot. Importing everything is a no go. It's like an inductive proof with no base case. Depressing. – Chris C Mar 07 '20 at 15:34
  • @ChrisC I would like to see an example of a valid use case for global variables (thats **variables**, not constants). My understanding is that global variables are responsible for most of Javascript's security vulnerabilities. – diachedelic Sep 27 '20 at 23:51
  • 2
    Let's say I have a service bus in module A. It has two methods bus.send(msg) and bus.receive(callback). Everywhere I use that bus, I need to import it. Could be hundreds of times. DRY tells us this is ridiculous. Useless noisy boilerplate. The security vulnerabilities don't come from global variables, they come from having them keyed as strings where anybody can muck with them willy nilly. If we had symbolic globals, where when I type "Bus" anywhere in MY modules I am referencing only my Bus definition and no other 3rdparty crap jammed into the global namespace it would work fine. – Chris C Sep 29 '20 at 01:32
  • module A: export global bus | module B: bus.Send("hi") | Basically the module system is just inserting an automatic import in each file that references bus. Not super controversial as far as I can tell... – Chris C Sep 29 '20 at 01:43
  • 2
    One area you commonly find globals in JavaScript is in test frameworks. The mocha library - for example - declares global functions "describe" and "it". It allows you to build a DSL-like language without muddling the code. – Rich Remer Nov 11 '20 at 19:07
  • Here's a valid use case: detecting that you are not in a browser and behaving differently. This isn't modifying the global - but it still needs to read it to check for `window`. (then again, I'm still looking for another way, if it can be done) – Lazerbeak12345 Feb 21 '22 at 01:56
4

You can use globalThis:

function test(h) {
    globalThis.testVar = h
}

test("This is a global var")
console.log(testVar)
KetZoomer
  • 2,701
  • 3
  • 15
  • 43