What is javascript "global" variable? - javascript

I am trying to get my app that uses BreezeJs to work with Webpack/commonjs.
My app is in typescript that compiles down to commonjs javascript.
There is a line in the breeze code that looks like this:
function __requireLibCore(libName) {
var window = global.window;
if (!window) return; // Must run in a browser. Todo: add commonjs support
The problem is that global is just an empty object ({}). It does not have window in it.
I can use webpack to make global equal to something, but I don't know what this global object is. (Try googling for "javascript global")
Is it a generic typescript construct that somehow is not present in commonjs?
Or something specific to breeze?

Related

How to expose a class to the global scope with esbuild?

Update
user #TKoL suggested defining a property in the window object. This produces the result I wanted to achieve, although I do not know if it is the correct way to proceed. I will be using this method for the time being. Thanks!
I am using esbuild in my project (first time using a bundler / developing JS in this "style").
The project is a small web component for which I developed a class that the end user should be able to utilize in their scripts.
// this is the component, which is then bundled and minified by esbuild.
// i have omitted various imports required in the class here.
export default class Widget extends HTMLElement {
/// code here is not relevant
}
customElements.define('custom-widget', Widget);
As it stands, the end user is able to utilize the widget from HTML like this:
<custom-widget some-custom-attribute="some-value"></custom-widget>
let widget = document.querySelector('custom-widget');
widget.someMethodDefinedInTheClass();
However, I would like to allow the user to do it all via JavaScript as well.
How can I make esbuild expose the Widget class to the global scope? I'd like to do this to enable behaviours such as:
let wOptions = {}; // object of initialization options for the widget
let widget = new Widget(wOptions);
someContainer.append(widget);
widget.someMethodDefinedInTheClass();
To make any way bundled js file to expose anything to the global scope you have to set it as a property of global object (that represents the global scope) like
globalThis.Widget = Widget;
globalThis keyword is a best way to use global object in javascript because it works the same on browser page, nodejs or service worker environment. If your code will be only executed on browser page you can also use window keyword.

Debugging JavaScript code that uses ES6 Modules

TL;DR: How can I access variables/functions/names that are defined in ES Modules from the debugger?
More context: I'm a relatively experienced JavaScript programmer, but new to Modules. I've followed the tutorial at MDN here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules. They have a good set of examples here: https://github.com/mdn/js-examples/tree/master/modules
In that collection, say in the "basic-modules" example, (live code here: https://mdn.github.io/js-examples/modules/basic-modules/) there is, for example, a function called random in the file modules/square.js. Suppose I want to execute that function in the debugger, just to try it out, or because it's my code and I want to test/debug it, or I want to demonstrate to another coder what the function does. All the stuff you expect to do in a REPL or debugger. Is there a way to do that? I've tried both the Firefox debugger and the Chrome debugger, with no luck.
Back in the pre-Modules era, that code would be put into the global namespace (making access easy) or it would be locked up in an IIFE (making access impossible) or maybe in some home-made module system (access depends). I am hoping that the new Modules system still allows the debugger access to the names inside modules.
Thanks.
It says in the docs:
Last but not least, let's make this clear — module features are imported into the scope of a single script — they aren't available in the global scope. Therefore, you will only be able to access imported features in the script they are imported into, and you won't be able to access them from the JavaScript console, for example. You'll still get syntax errors shown in the DevTools, but you'll not be able to use some of the debugging techniques you might have expected to use.
To take your example from before, you'll need to invoke that function from a scope where it is visible, i.e where it's been imported:
import { random } from 'path/to/square.js'
debugger; // you should be able to invoke random() from here

Ignore not declared variables (TypeScript)

I am creating a WebExtension using TypeScript which is later compiled to JavaScript.
My extension depends on one of the APIs the browser (Firefox) offers, specifically the extension API. As an example, I use the getURL() method, which is called like this:
browser.extension.getURL("foo/bar.js");
Of course, TypeScript gives an error "Cannot find name 'browser'". This prevents me from fully compiling the code. I would like to know if there is any way to bypass this. Preferably not only at compile level, but also at the linting level.
I have tried:
Defining browser at the beginning as var browser: any;: breaks the API.
Compiling with --noEmit, --noEmitOnErrors: irrelevant, still complains.
Any suggestions?
If you want to let Typescript know that the variable exists but not actually emit any code for it you can use declare
declare var browser: any;

How to correctly modularize a node.js project?

I'm creating a node.js project following the class constructor pattern:
function my_class(x,y){
this.x = x;
this.y = y;
}
The starting point of the project is the main.js file. Any class of the project must be able to access global objects (such as "world" and "socket") which are defined on main.js. I found 4 options:
I define my classes inside main.js. They'll have access to main.js's globals for being on it's closure, but main.js will become bloated.
I move the class to another file such as my_class.js and require() it. This doesn't work because my_class's instances will lose the closure context and no longer be able to access main.js's globals.
I move the class to another file and manually inject dependencies to it's constructor (ex: my_class(world,socket)). The problem is, code becomes much more complicated and weird semantics such as "my_instance.world" pop on the source, which is nonsense because "world" is not property of my_class.
I move the class to another file and require it using my_class = eval(fs.readFileSync(()) instead of require. This works just fine as my_class gets main.js's closure context, and is the solution I'm using, but seems hacky.
Which is the right way to modularize such node.js project?
If I understood you correctly the possible solution:
main.js:
(function(){
var global = "test"; // this you wanna have as a closure
var my_class = require('./my_class')(global);
my_class.go();
})();
my_class.js:
module.exports = function(global){
return {
go: function(){
console.log(global);
}
};
};
So it's similar to your 3. option
Your problem seems tricky because you have a circular dependency: main.js depends on the functionality of my_class and my_class depends on the data of main.js.
By putting the data of main.js into the global object you resolve the circular dependency:
main.js depends on the functionality of my_class.js
main.js depends on the data in the global object
my_class.js depends on the data in the global object
Now, to get rid of putting the data into the global object, implement a third module in let us say data.js. Then you require the sources like this:
main.js requires data.js
main.js requires my_class.js
my_class.js requires data.js
Since modules in node.js are singletons both main.js and my_class.js will get the same instance of data.js.
If you want to make variables in main.js available anywhere, then you can assign properties to the global object. See node.js global variables? for example. It would work fine as long as you don't over do it. With Neo's solution, you gain a little more flexibility for example with testing, because you can "inject" an arbitrary object into the module. Not every module has to use the same "global" per se.

What is the cross-platform way to add a JavaScript module to the global scope?

I was having a look at the source code of store.js, in particular how it adds itself to the global scope:
if (typeof module != 'undefined') { module.exports = store }
else if (typeof define === 'function' && define.amd) { define(store) }
else { this.store = store }
I understand the last statement this.store = store, but how about the other ones? What are the module and define functions? Won't this.store = store already work on all the browsers?
More generally, what is the correct, cross-browser way, to add a module to the global scope?
The first case is for CommonJS, which is most notably used in Node.js and is a flavor of AMD (Asynchronous Module Definition). A module is a JavaScript file that gets executed with a global module object defined. Whatever that file sets to module.exports will be available to other parts of the app, and everything else in the file will remain private to just that module. Here is a good blog post on it.
The second one is for another flavor of AMD, which is most commonly implemented with requirejs. It's a very similar idea to CommonJs, but is more commonly found in the browser. The Dojo framework is one good example of an amd based framework. The Jquery community is getting behind amd a lot as well. define tells the amd system that you are giving it a module that the rest of the app can pull in by using require.
The final version is the common scenario of running in a plain jane browser. this is most likely DOMWindow, and thus the store object becomes global across the whole webpage.

Categories

Resources