Manuel Graf
Manuel Graf

Reputation: 528

THREE.js TypeError: 'global' is undefined in Firefox

So I tried to include threejs as a drop-in script into my code. No webpack, no browserify, no requirejs. Just a simple gulp/browsersync serve. I load an external angular app and extend it. Now I need my own THREEjs Version within the codebase.

It gets loaded - but right in the first line they try to set the variable 'global' which doesn't seem to be defined. What am I missing?


// edit:

I am using a js api from another company. I don't know if they set the 'global' var, but Threejs definitely tries to use the var 'global' although I don't use it in a node setup. but in all examples it just works as a drop-in script.

If I use the minified version the error changes to

TypeError: global is undefined *three.min.js:2:168

anonymous https://localhost:9000/scripts/three.min.js:2:168

anonymous https://localhost:9000/scripts/three.min.js:2:2*

and this originates from the following first lines of the three.js file:

function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.THREE = {}))); }(this, (function (exports) { 'use strict'; ...

//EDIT 2:

I finally maaged to find the error which is causing all this. if youre using gulp-babel and include scripts with that snippet on top, babel tries to replace THIS with the current context, which is - of course - undefined. and thats why bable literally replaces this with undefined. so: never babel() your final vendor files!

Upvotes: 1

Views: 2195

Answers (3)

Mikepote
Mikepote

Reputation: 6553

Since "just getting babel to ignore certain files" is by no means trivial when working in gulp, a quick and dirty fix for this error is to swap this with window on the 5th line of three.js:

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
  (factory((global.THREE = {})));
}(window, (function (exports) { 'use strict';

Upvotes: 0

Louis
Louis

Reputation: 151461

The part of THREE.js that you show in your question is not a problem. If we focus only on the problem you've been having, and eliminate the code for the CommonJS and AMD cases, it boils down to this:

(function (global, factory) {
  factory(global.THREE = {}); 
}(this, (function (exports) { 'use strict';
  // ...
})));

This is a common pattern. Note that the first anonymous function is called with this as the first argument. So global is set to the value that this has in the global space. If the code above executes in a top-level execution context, then this will automatically have the value of the global object for the environment in which you run the code. In Node, that object is named global. So open a Node session and type:

global === this

You'll get true. In a browser the global object is named window. Open the console in debugging and type:

window === this

You'll get true. So what the code snippet with the anonymous function does is that it uses this to grab a reference to the global object irrespective of where the code executes. It does not have to check whether window exits or global exist, or self or anything else. Instead, it just passes this to the anonymous function and, this way, automatically gets a reference to the global object. There's nothing wrong with that method. It is super common and generally works.

However, it is possible to prevent the code from working properly. For instance if the code above is wrapped in another function and that function uses "use strict", then this will be undefined, and global will be undefined too. Here's an example:

(function() {
  "use strict";
  (function(global, factory) {
    console.log("XXX", global); // You'll get "XXX undefined" here
  }(this, (function(exports) {
    'use strict';
  })));
}());

Sometimes, build processes or code loading tools add such wrapping code, and then they mess up the original code.

Upvotes: 3

Michael Lee
Michael Lee

Reputation: 477

Is this what you need? Just add this one-liner at the very head of your code, in the global scope:

if (typeof global === "undefined"){global=window;}

This is going to reference the global object to the window object, which is the object containing all global variables in browser.

Upvotes: -1

Related Questions