How do you do to work with external js classes files and put this on a main.js file with modules?

Hi,

My application seems like that :

├── index.html
└── main.js

My main.js load module like this :

import * as THREE from "https://threejs.org/build/three.module.js";
import
{
	OrbitControls
} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";
import
{
	CSM
} from "https://threejs.org/examples/jsm/csm/CSM.js";
import
{
	TWEEN
} from 'https://unpkg.com/three@0.125.2/examples//jsm/libs/tween.module.min'

i have also class inside my main.js file :

class Player{
  constructor()
  {
    this.geom = new THREE.BoxGeometry(2,2,2);
    this.mat = new THREE.MeshPhongMaterial({
       color: 0xfffff,
    });
    this.mesh = new THREE.Mesh(this.geom, this.mat);
  }
  }

Until now everything works good. But i would to put my class Player in another external js file like this :

├── classes
│   └── player.js
├── index.html
└── main.js

Change in my main.js like this :

...
let player = new Player()
...

And in my index.html i do this :

<script src="js/classes/player.js"></script>

<script type='module' src="js/main.js"></script>

and my error is :
Uncaught ReferenceError: THREE is not defined

How do you do to work with external js classes files and put this on a main.js file with modules ?

Just for clarification: This runtime error happens since your import three.js as an ES6 module. That means the resulting THREE namespace is not available in the global space (and hence not in your Player class). Try the following:

  1. Implement your Player class as an ES6 module like so:
import * as THREE from "https://threejs.org/build/three.module.js";

class Player{
  constructor()
  {
    this.geom = new THREE.BoxGeometry(2,2,2);
    this.mat = new THREE.MeshPhongMaterial({
       color: 0xfffff,
    });
    this.mesh = new THREE.Mesh(this.geom, this.mat);
  }
}

export default Player;
  1. Import the Player class in main.js like so:
import Player from `./classes/player.js`;
  1. Remove the obsolete import in your index.html:
<script src="js/classes/player.js"></script>
1 Like

Okay thanks so you have to import all your modules in each classes! Do you have an easy way?

that is the easy way. you either use global IIFE’s in very specific order. i would suggest you do not because it’s only a matter of time until three casts it out. or modules, which have namespaces. if your module uses something it needs to import it.

of course if you actually want to build something real using esm like that will never work, because you can’t have dependencies. the only thing that makes sense in that case is skypack or bundlers, everything else will hurt you in the process.

With Phaser and it works also with THREE.js i write my classes like this :

//in player.js
class Player{
  constructor(T)
  {
    this.geom = new T.BoxGeometry(2,2,2);
    this.mat = new T.MeshPhongMaterial({
       color: 0xfffff,
    });
    this.mesh = new T.Mesh(this.geom, this.mat);
  }
}

//in main.js
import * as THREE from "https://threejs.org/build/three.module.js";
let player = new Player(THREE)

The advantage is :
One file to load all the modules (main.js) and all the classes load the modules with abbreviations/parameters.

Is not a good way ? and Why ?

you do not normally have to do that with modules, it kind of goes against the whole point of it. seems also limited, what you gonna do with a third party control. but if it works for you then it works …

okay i take your advice(s) (drcmda and Mugen87) as the way to follow :wink: Thanks.

Hi,

I don’t understand why it doesn’t works…

Here my files :

// classes/player.js
import * as THREE from "https://threejs.org/build/three.module.js";

class PLAYER
{
    constructor()
    {
        this.geom = new THREE.BoxGeometry(2, 2, 2);
        this.mat = new THREE.MeshPhongMaterial({
            color: 0xfffff,
        });
        this.mesh = new THREE.Mesh(this.geom, this.mat);
        scene.add(this.mesh)
    }
}
export default PLAYER;

and my main.js

import * as THREE from "https://threejs.org/build/three.module.js";
import
{
    OrbitControls
} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";
import
{
    CSM
} from "https://threejs.org/examples/jsm/csm/CSM.js";
import
{
    TWEEN
} from 'https://unpkg.com/three@0.125.2/examples//jsm/libs/tween.module.min'

import
{
    PLAYER
} from "./classes/player.js"
console.clear();

const params = {
    color_cube: 0xacaaad,
};
let m = {} // materials
let g = {} // geometry
let o = {} // objects
let s = {} // sounds
let startX, startY, my_latest_tap;

let scene, camera, renderer, container, controls; // what to see
let csm, csmHelper; // plugin to have shadows on huge scene 

// // // TOUCH ACTIONS

function init_app()
{
    init()
    //CHANGE KEY TOGGLES

    animate()
    ///////////////////////////////////////////////////////////////////////////////////////////

    function init()
    {
        // init_minimal(this)
        const random = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);

        scene = new THREE.Scene();
        // pour avoir une couleur de fond dans le ciel
        scene.background = new THREE.Color(0xf6ffb9);

        scene.fog = new THREE.Fog(params.color_fog, 0, params.distance_fog);
        // camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.01, 2000);
        camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 2, 2000);

        // for camera with mouse
        // camera.position.set(10, 1, 10);

        // for camera with controls
        camera.position.set(40, 13, 40);
        camera.rotation.order = "YXZ";
        camera.rotation.y = -Math.PI / 2;
        o.direction = new THREE.Vector3(0, 0, 0);
        console.log(o.direction)
        camera.getWorldDirection(o.direction);

        renderer = new THREE.WebGLRenderer({
            antialias: true,
            alpha: true,
        });
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);
        // document.getElementById("canvas").appendChild(renderer.domElement);

        //Shadows
        renderer.shadowMap.enabled = true;
        renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        //  ORBIT
        controls = new OrbitControls(camera, renderer.domElement);
        // controls.target.y = 5


        //  LIGHTS
        var ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
        scene.add(ambientLight);

g.cube = new THREE.BoxGeometry(2, 2, 2);

		m.cube = new THREE.MeshPhongMaterial({

			color: params.color_cube,
			shininess: 100,

		});
        ///////////////////////////////////////////////////////////////////////////////////////////
        o.cube = new THREE.Mesh(g.cube, m.cube);
        o.cube.castShadow = true
        o.cube.receiveShadow = true
        o.cube.outside = true
        scene.add(o.cube);
        let pl = new Player()
    }

    function animate()
    {

        requestAnimationFrame(animate);
        ///////////////////////////////////////////////////////////////////////////////////////////
        camera.updateMatrixWorld();
        renderer.render(scene, camera);
    }

}

init_app()

my error is :
Uncaught SyntaxError: The requested module ‘./classes/player.js’ does not provide an export named ‘PLAYER’

Why ?

Write the import like so:

import PLAYER from "./classes/player.js"
1 Like

Thanks.

Just a last question :

how do you put scene.add(this.mesh) directly in the class ?

import * as THREE from “https://threejs.org/build/three.module.js”;

class PLAYER
{
    constructor()
    {
        this.geom = new THREE.BoxGeometry(2, 2, 2);
        this.mat = new THREE.MeshPhongMaterial({
            color: 0xfffff,
        });
        this.mesh = new THREE.Mesh(this.geom, this.mat);
        // DON'T WORKS
        //scene.add(this.mesh)
    }
}
export default PLAYER;

You could pass in the scene object as a constructor argument.

let pl = new Player(scene);

You could also consider to derive the Player class from Mesh and then add the player object directly to the scene.

scene.add(pl);

this fixed the issue I was having trying to just do the tutorial!
The WebGL Compatibility check in the tutorial was messing up!
So I fixed the import statement to be correctly styled put the check code below the animate function.
Voila! About two hours of bug fixing done!