1

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!

Manuel Graf
  • 462
  • 5
  • 20
  • could you provide the error? maybe a code sample of what you do – mast3rd3mon Dec 19 '17 at 09:56
  • 2
    This might help you: https://stackoverflow.com/questions/17575790/environment-detection-node-js-or-browser Webbrowsers have a global object called `window`, node.js and the like have a global object called `global`. – connexo Dec 19 '17 at 09:58
  • Yeah I was also thinking it has something to do with node. But still, that lib is used so often without a node setup... every example only uses a script tag with three.min.js and it works... – Manuel Graf Dec 19 '17 at 10:41

3 Answers3

3

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.

Louis
  • 146,715
  • 28
  • 274
  • 320
  • Thanks for the explanation! Appreciated! RIght now, I am just having a gulp/babel workflow and I am fetching an angular app by including a js file in index.html. if I don't care about the dependancy i can just remove the commonjs boilerplate and set global = window? Or is babel messing that up? – Manuel Graf Dec 22 '17 at 12:53
  • 1
    If Babel is processing your THREE.js file, I suggest you'd exclude it from Babel processing. You could set `global = window` but I'd advise against it unless there's a overriding consideration that needs to be satisfied. Otherwise, it's like a leaky boat that you fix by bailing water out continually. Ok, the boat may not be sinking anymore but the solution is to patch the hole rather than bailing out water. – Louis Dec 22 '17 at 17:36
0

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';
Mikepote
  • 6,042
  • 3
  • 34
  • 38
-1

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.

Michael Lee
  • 467
  • 5
  • 14
  • I guess the problem is not the global scope but this (first few lines 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 = {}))); }(this, (function (exports) { 'use strict'; – Manuel Graf Dec 22 '17 at 09:59