Three.js: 'THREE is not defined' error using requirejs

Created on 30 Aug 2016  ·  14Comments  ·  Source: mrdoob/three.js

Description of the problem

When I use three.js with 'requirejs' appears 'Uncaught ReferenceError: THREE is not defined' on the parts of the build with a reference like this > var material = new THREE[ json.type ]();

Three.js version
  • [ ] Dev
  • [ x] r80
  • [ ] ...

    Browser
  • [x] All of them

  • [ ] Chrome
  • [ ] Firefox
  • [ ] Internet Explorer

    OS
  • [x] All of them

  • [ ] Windows
  • [ ] Linux
  • [ ] Android
  • [ ] IOS
    Hardware Requirements (graphics card, VR Device, ...)

Most helpful comment

Yeah, I've seen similar problems in the past with RequireJS and things like jQuery plugins. It's basically what happens when you mix AMD modules (the main library) with non-AMD modules (the plugins). I seem to recall it being possible to configure RequireJS to work around these issues, but I can't remember how exactly (haven't used it in many years). Or you can define the three AMD module like this in your app...

define('three', ['./the/actual/three.js'], function ( THREE ) {
  window.THREE = THREE;
  return THREE;
});

...though it might be easier for Three to just always pollute the global namespace:

    exports.ImageUtils = ImageUtils;
    exports.Projector = Projector;
    exports.CanvasRenderer = CanvasRenderer;

    Object.defineProperty(exports, '__esModule', { value: true });

+    if ( typeof window !== 'undefined' ) window.THREE = exports;

})));

Could be done with the outro option in the Rollup config.

All 14 comments

It is the problem with ES6 syntax.
Although es6 has many good features, but it can only be used with all the source code, can't separate the use of one of them, because of the “import” dependence, no previous version flexible!

9539 should be fixing this...

@arturitu how did this disappear for you? I am getting it now that I am upgrading from r76 to r81, this is our require configuration:
Thanks!
screen shot 2016-10-08 at 14 55 10

require.config({
    /*
     * Values in here are for dependencies that more than one module/script requires and/or needs.
     * E.G. If depenedency it's used more than once, it goes in here.
     */
    paths: {
        jquery: "vendor/jquery-1.9.1.min",
        three: 'vendor/three.min',
        d3: 'vendor/d3.min',
        codemirror: "vendor/codemirror.min",
        handlebars: "vendor/handlebars",
        typeahead: "vendor/typeahead.jquery",
        bloodhound: "vendor/bloodhound",
        underscore: 'vendor/underscore.min',
        backbone: 'vendor/backbone.min',
        'backbone-associations': 'vendor/backbone-associations-min',
        geppetto: 'GEPPETTO',
        react: 'vendor/react',
        'react-dom': 'vendor/react-dom',
        griddle: 'vendor/griddle',
        jsx: 'vendor/jsx',
        JSXTransformer: 'vendor/JSXTransformer',
        text: 'vendor/text',
        pako: 'vendor/pako.min',
        mathjs: 'vendor/math.min',
        json: 'vendor/require-json'
    },
    /*
     * Notes what dependencies are needed prior to loading each library, values on the right
     * of colon are dependencies. If dependency was declared in path above, then add it's dependencies
     * to that object in here.
     */
    shim: {
        'vendor/jquery-ui.min': ["jquery"],
        'vendor/postprocessing/EffectComposer': ['three'],
        'vendor/TrackballControls': ["three"],
        'vendor/THREEx.KeyboardState': ['three'],
        'vendor/shaders/ConvolutionShader': ['three'],
        'vendor/shaders/CopyShader': ['three'],
        'vendor/shaders/FilmShader': ['three'],
        'vendor/shaders/FocusShader': ['three'],
        'vendor/postprocessing/MaskPass': ['three', 'vendor/postprocessing/EffectComposer'],
        'vendor/postprocessing/RenderPass': ['three', 'vendor/postprocessing/EffectComposer'],
        'vendor/postprocessing/BloomPass': ['three', 'vendor/postprocessing/EffectComposer'],
        'vendor/postprocessing/ShaderPass': ['three', 'vendor/postprocessing/EffectComposer'],
        'vendor/postprocessing/FilmPass': ['three', 'vendor/postprocessing/EffectComposer'],
        'vendor/ColladaLoader': ['three'],
        'vendor/OBJLoader': ['three'],
        'vendor/ColorConverter': ["three"],
        'vendor/bootstrap.min': ["jquery"],
        'vendor/codemirror-formats.min': ["codemirror"],
        'vendor/backbone-localStorage.min': ["backbone"],
        'vendor/dat.gui.min': ["jquery"],
        'vendor/stats.min': ["jquery"],
        'vendor/Detector': ["jquery"],
        'vendor/jquery.cookie': ["jquery"],
        'vendor/rAF': ["jquery"],
        JSXTransformer: {
            exports: "JSXTransformer"
        },
        typeahead: {
            deps: ['jquery'],
            init: function ($) {
                return require.s.contexts._.registry['typeahead.js'].factory($);
            }
        },
        bloodhound: {
            deps: ['jquery'],
            exports: 'Bloodhound'
        }
    }
});

@tarelli yes, with changes made in r81 works again for me.

@arturitu thanks for the info, do you have a require configuration similar to the above? And are you using stuff from the examples? E.g. postprocessing or shaders or orbitcontrol etc.?

@tarelli I was using browserify but I suppose that the fix works too for requirejs.

@tarelli @arturitu Having the same issue migrating from r77 to r81 with requirejs. I have tried it with r81 release but getting the same issue. Is this something that is fixed in master for r82? If so are there any workarounds?

Edited: I also tried the latest r82dev but get the same error.

@Rich-Harris any ideas if this is related to the module conversion?

What is happening is that after requiring three.min.js THREE as a global var is not defined even if in require.js you put the export configuration in the shim. Which means that in turn when you try to require any of the examples that assume THREE is there the will fail with the message THREE undefined.

Yeah, I've seen similar problems in the past with RequireJS and things like jQuery plugins. It's basically what happens when you mix AMD modules (the main library) with non-AMD modules (the plugins). I seem to recall it being possible to configure RequireJS to work around these issues, but I can't remember how exactly (haven't used it in many years). Or you can define the three AMD module like this in your app...

define('three', ['./the/actual/three.js'], function ( THREE ) {
  window.THREE = THREE;
  return THREE;
});

...though it might be easier for Three to just always pollute the global namespace:

    exports.ImageUtils = ImageUtils;
    exports.Projector = Projector;
    exports.CanvasRenderer = CanvasRenderer;

    Object.defineProperty(exports, '__esModule', { value: true });

+    if ( typeof window !== 'undefined' ) window.THREE = exports;

})));

Could be done with the outro option in the Rollup config.

@Rich-Harris Thanks for your comments. The usual way to mix non-AMD modules with AMD has been to use requirejs 'shim' config as follows. This use to work up until r77 atleast. But with r81 it does not work.

I will play around with it and if I find a solution, I will post it here. Thanks again.

 shim: {
    THREE: {
         exports: 'THREE'
   }
}

@Rich-Harris I can confirm your solution to create the wrapper three define works fine in r81. Pasting the same here 👍

define('three', ['./the/actual/three.js'], function ( THREE ) {
  window.THREE = THREE;
  return THREE;
});

can't you just add something like THREE = {
Vector3: Vector3,
...
} to your code that has 'THREE.' in it, and why can't you delete 'THREE.' in your code?

Using a wrapper worked for me too, thanks @Rich-Harris!

Was this page helpful?
0 / 5 - 0 ratings