New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use CanvasRenderer or Projector when I'm using Three from npm #10617

Closed
marcofugaro opened this Issue Jan 20, 2017 · 14 comments

Comments

Projects
None yet
10 participants
@marcofugaro
Copy link

marcofugaro commented Jan 20, 2017

Description of the problem

Here is a reproducible example, I have in my js file just the THREE import and after that the CanvasRenderer code as taken from here:

import * as THREE from 'three';
import './CanvasRenderer'; // or Projector

The error in the console is

Uncaught TypeError: Cannot set property d of #<Object> which has only a getter.

which happens when you assign the function on this line

THREE.CanvasRenderer = function ( parameters ) {

Basically says that THREE.CanvasRenderer already exists and is not configurable, and indeed it does exist as a deprecation warning in Three.Legacy.js.

The same happens for Projector. As a bundler I use Webpack@2.2.0.

Sorry I wouldn't know what to export instead of that function in order to bypass this error.

Three.js version
  • r84
@mrdoob

This comment has been minimized.

Copy link
Owner

mrdoob commented Jan 23, 2017

Hmm, yeah... we still don't know how to modularise the stuff in the examples folder without breaking traditional workflows...

@marcofugaro

This comment has been minimized.

Copy link

marcofugaro commented Jan 23, 2017

What do you mean modularise stuff? Do you need any help?

@cecilemuller

This comment has been minimized.

Copy link
Contributor

cecilemuller commented Jan 23, 2017

@marcofugaro This thread might provide some context about the modules in examples issue: #9562

Basically, js from the examples folder aren't ES Modules, so they can't be be used with the "import" keyword yet.

@marcofugaro

This comment has been minimized.

Copy link

marcofugaro commented Jan 23, 2017

Oh, the other day I did this library because I needed some Three.js addons in my workflow, maybe could be of any help.

Of course the only issue is with the two deprecation notice functions, as this issue reports.

@cecilemuller

This comment has been minimized.

Copy link
Contributor

cecilemuller commented Jan 25, 2017

In the case of CanvasRenderer, the issue here is the conflict with the export from Three.Legacy.js: should CanvasRenderer be part of the core or only be in examples ?


But as for modularising examples in general: as long as we only have one file per example, it won't be usable both as simple <script> tag and as import-able module.

I think the cleanest solution would be to have each example as an ES module (that can be used for "import"), and a build target for each example (to generate a version that can be used for the classic <script> workflow).

The other main constraint is examples inject themselves in the THREE namespace.

ES Modules would reference the functions directly:

import {SVGRenderer} from 'examples/js/renderers/SVGRenderer.module.js';
const myvar = new SVGRenderer();

But classic workflow would expect "THREE.SVGRenderer":

<script src="examples/js/renderers/SVGRenderer.js">
...
var myvar = new THREE.SVGRenderer();

So the build target for classic would have to append append something like "THREE.SVGRenderer = SVGRenderer" to the built file.

@Mugen87

This comment has been minimized.

Copy link
Collaborator

Mugen87 commented Apr 23, 2017

Closing. As @cecilemuller mentioned, #9562 is the leading issue for this topic.

@Mugen87 Mugen87 closed this Apr 23, 2017

@Mugen87 Mugen87 added the Duplicate label Apr 23, 2017

@cecilemuller

This comment has been minimized.

Copy link
Contributor

cecilemuller commented Apr 24, 2017

In the meantime, if you use Webpack, you can manually alias files from "examples" to import this way, so even if it's not as clean as examples being ES Modules, at least it's in the same bundle instead of having to have a <script> for each file:

In webpack.config.js:

resolve: {
	alias: {
		'three/OrbitControls': path.join(__dirname, 'node_modules/three/examples/js/controls/OrbitControls.js'),
		'three/OBJLoader': path.join(__dirname, 'node_modules/three/examples/js/loaders/OBJLoader.js')
		// ...
	}
},

//...

plugins:[
	new webpack.ProvidePlugin({
		'THREE': 'three'
	}),
	//...
]

In application.js:

import 'three';
import 'three/OrbitControls';
/* global THREE */

console.log(THREE.OrbitControls);
@ri

This comment has been minimized.

Copy link

ri commented May 24, 2017

I found that @cecilemuller's excellent workaround only worked with r82 in my situation (with Webpack 2 and using a legacy example).

In particular, cf97517 causes Webpack 2 to export the THREE properties in a way that can not be replaced and CanvasRenderer (unlike OrbitControls in @cecilemuller's example) has a pre-existing definition on THREE.

> THREE.CanvasRenderer
function CanvasRenderer() {

	console.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' );

	this.domElement = document.createElementNS( 'http://www.w3.org/1999/xhtml', …

> THREE.CanvasRenderer = 42
42

> THREE.CanvasRenderer
function CanvasRenderer() {

	console.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' );

	this.domElement = document.createElementNS( 'http://www.w3.org/1999/xhtml', …

As far as I can tell, the builtin THREE functions are exported using getters instead of object properties. In my case, cf97517 is the difference between these two compiled export styles:

/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CanvasRenderer", function() { return CanvasRenderer; });

// or

exports.CanvasRenderer = CanvasRenderer;

To work with r83 and above, I just had to explicitly load the UMD version in the ProvidesPlugin:

new webpack.ProvidePlugin({
  'THREE': 'three/build/three'
}),
@pmaster06

This comment has been minimized.

Copy link

pmaster06 commented Dec 19, 2017

The only way for me without changing the sources or using an outdated 'custom' npm package was (r89, Webpack3, ES6):

window.THREE = Object.unfreeze(require('three'))
require('three/examples/js/renderers/Projector')
require('three/examples/js/renderers/CanvasRenderer')

// After that you can do :
let  renderer = new THREE.CanvasRenderer()

With Object.unfreeze declared before (found : here )

Object.unfreeze = function (o) {
  var oo = undefined
  if (o instanceof Array) {
    oo = []
    var clone = function (v) {
      oo.push(v)
    }
    o.forEach(clone)
  }
  else if (o instanceof String) {
    oo = new String(o).toString()
  }
  else if (typeof o == 'object') {
    oo = {}
    for (var property in o) {
      oo[property] = o[property]
    }
  }
  return oo
}
@zstauber

This comment has been minimized.

Copy link

zstauber commented Feb 15, 2018

I use three.js with RequireJS (my preferred AMD loader) and have been able to successfully reincorporate CanvasRenderer.js and Projector.js into build/three.js in R90 if anyone wants a copy.

My use case was trying to use it to render a model of the solar system in Chrome on a Raspberry Pi 2 Model B, which simply not playing nice with WebGLRenderer in any way, shape, or form, including any of the examples on the threejs.org site, even after enabling the "Software override rendering list." :(

@BennyHinrichs

This comment has been minimized.

Copy link

BennyHinrichs commented Feb 23, 2018

@pmaster06 My dude. I've been working on this for like 4 hours, and your solution is the only thing that's worked!

@zstauber

This comment has been minimized.

Copy link

zstauber commented Feb 23, 2018

I just realized I could attach a file here. Just use CanvasRenderer like you used to.
three.js.zip

@morgansegura

This comment has been minimized.

Copy link

morgansegura commented May 24, 2018

Thank you, very helpful!

@MagicLeeW

This comment has been minimized.

Copy link

MagicLeeW commented Dec 5, 2018

@pmaster06 thx,very helpful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment