Three.js: Moving to ES6 Classes

Created on 2 Aug 2020  ·  88Comments  ·  Source: mrdoob/three.js

Hi all,

I felt it appropriate to create a new issue (instead of continuing #11552) to further aid everyone in keeping track and update-to-date on the issues and progress surrounding the move to ES6 classes. This should also come in handy for the release doc.

To those wishing to help, look through the list below and let us know what you'd like to work on. A PR per class is favoured however some folders can be done all at once. If a particular file cannot be converted, make a note at the top of the file, or ping me from your PR and I'll note it below.

Notes:

  • for Class.prototype.is** use Object.defineProperty( this, 'is**', { value: true } );
  • class fields are also available if appropriate #20395
  • new this.contructor() != new Foo() ... related discussion.
  • Will tick after merged and complete.

Part 1: src

  • [ ] src

    • [ ] animation ( #19964, #20014, #20016 )

    • [ ] tracks ( #20013 )

    • [x] audio ( #19975, #20003 )

    • [ ] cameras ( #20102 )

    • [ ] core ( #19976, #19977, #19978, #19984, #20008 )

    • [x] extras ( #19979 )

    • [ ] core ( #20656 )



      • Curve leave out as extended within examples



    • [ ] curves ( #20140 )

    • [ ] objects ( )



      • Used in examples/objects/MarchingCubes.js, will have to wait. ref #20030



    • [x] geometries ( #19994 )

    • [x] helpers ( #19996 )

    • [ ] lights ( #20018 )

    • [ ] loaders ( #19985 )

    • Base loader cannot be done yet

    • [ ] materials ( #20100 )

    • [x] math ( #19980, #19997, #20076, #20089)

    • Interpolants will wait till we tackle examples/js

    • [ ] objects (#20658 )

    • [ ] renderers ( #20101 )

    • [ ] webgl ( #20070 )

    • [ ] webxr ( #20038 )

    • [x] scenes ( #20007 )

    • [ ] textures ( #20009 )

We're not ready for Part 2 yet. Discussion is needed.

Part 2: examples

  • [ ] examples

    • [ ] animation

    • [ ] cameras

    • [ ] controls

    • [ ] curves

    • [ ] effects

    • [ ] exporters

    • [ ] geometries

    • [ ] interactive

    • [ ] lights

    • [ ] lines

    • [ ] loaders

    • [ ] math

    • [ ] misc

    • [ ] modifiers

    • [ ] objects

    • [ ] postprocessing

    • [ ] renderers

    • [ ] shaders

Part 3: Loose ends and tidy up

  • [ ] src/core/Object3D
    ...

Most helpful comment

@ianpurvis great! are you using rollup, right? could you share your config?

@mrdoob I finally got around to do some testing. I personally use webpack, so I did some tests with it, my config is this if anyone is interested.

I tested this code

import * as THREE from 'three'

console.log(THREE.WebGLRenderer)

0.119.1

0 119 1

0.120.1

0 120 1

So something is being tree-shaked, great!

Looking into it more, it looks like the class AudioListener isn't in the bundle, great news!

Screenshot 2020-09-01 at 16 49 22

Screenshot 2020-09-01 at 16 50 07

Webpack also automatically removes the unused variables pointed out by @ianpurvis.


After this, I decided to test static methods defined outside the class

Screenshot 2020-09-01 at 16 50 37

and unfortunately, this makes the class non tree-shakeable

Screenshot 2020-09-01 at 16 51 04


After doing some more digging, I noticed geometry classes like DodecahedronGeometry, which weren't used anywhere, were still in the bundle

Screenshot 2020-09-01 at 16 51 29

Screenshot 2020-09-01 at 16 52 08

Later I discovered, this was due to this Geometries object in the three.module.js bundle

Screenshot 2020-09-01 at 17 18 32

Which is generated automatically when using patterns like this in the ObjectLoader. This will probably go away when we make ObjectLoader a class, and src/geometries will be tree-shakeable.

All 88 comments

I'll call dibs on the rest of the audio folder 🔈

hey @mrdoob, could you please clarify how you'd like us to handle the scripts within the examples folder?

I'm liking #19989 going straight for the conversion but I realize in doing so the utils/modularize.js can no longer be used on the examples/js folder without overwriting that work. Does this mark the end of us maintaining the examples/js and the beginning of just examples/jsm?

edit: see comment

Could I work on the rest of the math folder?

Could I work on the rest of the math folder?

I'm all for you giving it a shot. I remember trying to a while ago but @Mugen87 ended up telling me off for it. Quick summary of that was test as you go because converting the whole folder in one go might be setting yourself up for a rough ride. A partial, or even file by file, would be welcome I'm sure.

@DefinitelyMaybe I'll see what else can be migrated under src/animation/

nice. I think that folder is almost done. Might be just src/core/Object3D.js and src/core/BufferGeometry.js left?

Might be just src/core/Object3D.js and src/core/BufferGeometry.js left?

Yes, There are much ES5 class depend on Object3D and BufferGeometry.

Shoot, there has been some amazing progress on this 🎉

Gonna call dibs on src/lights. Opened up the src/extras and src/renderers in the listing above, turns out there's a couple of folders in each to work through.

Hey all,

what were we doing with regards to this pattern?

foo.prototype = Object.assign( Object.create( bar.prototype ), {
    ...
    isDirectionalLight: true,
    ...
} );

is it now:

class foo extends bar {
  static isDirectionalLight = true;
  constructor(  ) {
    ...
  }
}

or

class foo extends bar {
  constructor(  ) {
    this.isDirectionalLight = true;
  }
}

currently, I've been doing the second one but looking at it, I'd say the intention of this might've been closer to the first.

does anyone know what was using these variables in the first place?

class foo extends bar {
  constructor(  ) {
    this.isDirectionalLight = true;
  }
}

☝️ This is right. isDirectionalLight is a good example, it gets used like this:

$ git grep 'isDirectionalLight\b' src/ examples/js ':!*.ts'
examples/js/exporters/GLTFExporter.js:                  if ( light.isDirectionalLight ) {
examples/js/exporters/GLTFExporter.js:                  } else if ( object.isDirectionalLight || object.isPointLight || object.isSpotLight ) {
examples/js/renderers/SVGRenderer.js:                   } else if ( light.isDirectionalLight ) {
examples/js/renderers/SVGRenderer.js:                   if ( light.isDirectionalLight ) {
src/lights/DirectionalLight.js: isDirectionalLight: true,
src/renderers/webgl/WebGLLights.js:                     } else if ( light.isDirectionalLight ) {

That said, there could be performance gains by retaining some prototype properties...

class foo extends bar {
}
foo.prototype.baz = heavyThing;

Maybe we can review those in the PR on a case by case basis.

I'll take a shot at src/renderers/webgl 👍 👍

good luck, have fun. that one's got a fair bit going on in it

Hey all- I've got src/renderers/webgl converted. It was crazy. I'll keep reviewing everything and wait for #20039 before I start pushing the PRs.

👍
looking forward to it

I noticed @yomotsu used read-only getters for is* properties in the math PR... Maybe that's the best!

class foo extends bar {
  get isDirectionalLight() {
    return true;
  }
}

hmm it might be. I know others have tried in places to make variables unchangeable. This looks like a pretty decent pattern to me.

quick jsfiddle show case

Seems like this is the way to go:

foo.prototype.isDirectionalLight = true;

going to look into src/objects. will see how far I can get without breaking things.

The math folder was just completed.
(Interpolates classes are excluded.)

hey all,
I'm going to pull back on working through src/objects, someone else is more than welcome to pick it up in the mean time.

Hey, good job with this guys! 💪

Just one issue, foo.prototype.isDirectionalLight = true; doesn't allow for tree-shaking still, since the class is modified in place.
Also at this point I would strongly suggest not to touch the prototype anymore since we're using classes now and the prototype can be abstracted.

What about this pattern? It looks the most explicit to me.

constructor( x = 0, y = 0, z = 0 ) {

  Object.defineProperty( this, 'isVector3', {
    value: true,
    enumerable: false,
    writable: false,
    configurable: false,
  } );

There is also the short version, which does the same thing but is a bit more implicit.

constructor( x = 0, y = 0, z = 0 ) {

  Object.defineProperty( this, 'isVector3', { value: true } );

@marcofugaro the short version looks good to me 👍

Ok, did PR.

Also, I just noticed we can't use class fields because we're blocked by this PR.

I can update the build pipeline to use the more popular @rollup/plugin-babel
and fix that issue if you guys want.

I can update the build pipeline to use the more popular @rollup/plugin-babel
and fix that issue if you guys want.

Yeah, it would be great if you could do a PR 🙏

@marcofugaro , @mrdoob yay! yes please

Hey everybody, quick heads-up that I've updated #20014 with Object.defineProperty and also fixed the subclassing of AnimationClip. If anyone has time to review it, I would appreciate the extra 👀 🙇 🙇

Okay. Now that r120 is out... could someone check that things are being tree-shaked properly?

Seems it kinda works for me, but slightly.
I don't see ArrowHelper anymore in my bundle file with webpack. but many unnecessary code are still exist😢

how about bundle size? before and after

Hey everybody, I had an idea and spiked a tool called shakediff. You can run it like this:

$ shakediff builds/three.module.js Color

That will generate a small module importing Color, bundle it with three, and then create a diff of three from rollup's metadata. You can either work with the detailed diff or just pipe it to diffstat to get the high level:

$ shakediff build/three.module.js Color | diffstat 
 three.module.js | 2878 --------------------------------------------------------
 1 file changed, 1 insertion(+), 2877 deletions(-)

Right now there's no package, but you can install it from my repo if you want to try it out. Feedback appreciated! ✌️

npm -g i ianpurvis/shakediff.git

hey @mrdoob, could you please clarify how you'd like us to handle the scripts within the examples folder?
I'm liking #19989 going straight for the conversion but I realize in doing so the utils/modularize.js can no longer be used on the examples/js folder without overwriting that work. Does this mark the end of us maintaining the examples/js and the beginning of just examples/jsm?

What is the verdict on this one @mrdoob? Would it make sense to make jsm the source of truth so we can convert examples to ES6 classes? Perhaps we can make utils/demodularize.js to support conversion in the other direction?

The examples/js folder will be removed in December 2020. Until then, we should leave the folder as it is, without upgrading its contents — or the examples/jsm files generated from its contents — to ES6 Classes. After that date, The examples/jsm files will become the source of truth, and can be updated to ES6 Classes.

I noticed that module-scope variables are not being removed during shaking. You can see the behavior with these four vars, build/three.module.js:43059

const _position$3 = new Vector3();
const _quaternion$4 = new Quaternion();
const _scale$2 = new Vector3();
const _orientation$1 = new Vector3();

Looks like we should mark these pure with the special comment-

const _position = /*@__PURE__*/ new Vector3();

Does that work for everybody?

Sounds good to me 👌

Nice, that deletes another 144 lines when tree shaking with Color 🥳

Please everyone give your open PRs the /*@__PURE__*/ treatment when you have time!

@ianpurvis great! are you using rollup, right? could you share your config?

@mrdoob I finally got around to do some testing. I personally use webpack, so I did some tests with it, my config is this if anyone is interested.

I tested this code

import * as THREE from 'three'

console.log(THREE.WebGLRenderer)

0.119.1

0 119 1

0.120.1

0 120 1

So something is being tree-shaked, great!

Looking into it more, it looks like the class AudioListener isn't in the bundle, great news!

Screenshot 2020-09-01 at 16 49 22

Screenshot 2020-09-01 at 16 50 07

Webpack also automatically removes the unused variables pointed out by @ianpurvis.


After this, I decided to test static methods defined outside the class

Screenshot 2020-09-01 at 16 50 37

and unfortunately, this makes the class non tree-shakeable

Screenshot 2020-09-01 at 16 51 04


After doing some more digging, I noticed geometry classes like DodecahedronGeometry, which weren't used anywhere, were still in the bundle

Screenshot 2020-09-01 at 16 51 29

Screenshot 2020-09-01 at 16 52 08

Later I discovered, this was due to this Geometries object in the three.module.js bundle

Screenshot 2020-09-01 at 17 18 32

Which is generated automatically when using patterns like this in the ObjectLoader. This will probably go away when we make ObjectLoader a class, and src/geometries will be tree-shakeable.

@marcofugaro No problem, here's the rollup config

@marcofugaro Hi, I added webpack support to shakediff... does this webpack config seem ok to you? Since terser is responsible for dead code elimination in webpack's tree-shaking, it is difficult to prevent some transformation artifacts in those outputs. But if you diff using a histogram algorithm with whitespace disabled it is manageable. From a quick test tonight, webpack seems to accept both /*@__PURE__*/ and /*#__PURE__*/. I think we can standardize on one or the other. More tomorrow...

@ianpurvis I don't think I'm allowed to install shakediff on my machine...

Screen Shot 2020-09-22 at 9 59 04 AM

Anyway, I did a simple test:

import { WebGLRenderer } from './src/renderers/WebGLRenderer.js';
console.log( new WebGLRenderer() );

And noticed that Geometry was not being tree-shaked. https://github.com/mrdoob/three.js/pull/20394 fixes it.

I then tried doing:

import { Vector3 } from './src/math/Vector3.js';
console.log( new Vector3() );

And noticed that rollup doesn't tree-shake unused methods... 😕

@mrdoob unfortunately, in the foreseeable future, class methods are never gonna be tree-shakeable by any tool. Heck, they can't even be minified!

This is because in javascript, you can access methods like this['I am a string'], just like you can access dynamically object properties. For this reason, tools don't know in advance if and how you're gonna call a method (could be this[variable]).

This is the same for both ES6 Classes and Function classes. For example, in three.min.js, the methods are left untouched, just like any object property 🙂

And no one has proposed a builder "strict" mode, where you're expected not to call methods like this['I am a string']?

No idea 🤷‍♂️

Here is a discussion about this topic regarding rollup: https://github.com/rollup/rollup/issues/349

class methods are never gonna be tree-shakeable by any tool. Heck, they can't even be minified!

Sorry for going off topic, but you can get minification to work if you give the compiler some hint as to what's "public" vs. "private". In the past I've used "_" prefixes on methods for this. See https://github.com/developit/microbundle/wiki/mangle.json. But, unfortunately, I also have no idea whether anything similar is possible for tree-shaking. 😕

Wooh! #20395 merged! good stuff @marcofugaro

Awesome news about babel and geometry!

@ianpurvis I don't think I'm allowed to install shakediff on my machine...

@mrdoob Hm, looks like Parcel has a dependency on that version of fsevents... maybe I can pin that to something higher.

Fyi, good info here about tree-shaking improvements in Webpack 5...

Fyi, good info here about tree-shaking improvements in Webpack 5...

Progress... I hope Rollup implements this too...

Hi all,

What are the goals of .is**Classname** property and this.type = **Classname** exactly?
Isn't it a rest of old pseudo class pattern?
Why don't get rid totally of it and replace this usage by the normal type checking way?

obj instanceof Vector3  // prefer this one for inheritance
// or
obj.constructor === Vector3  // prefer this for no inheritance

I mean, as part of moving to ES classes, objects will have correct types already checkable...

The library used obj instanceof Vector3 before.
But Rich Harris implemented and changed all the checks to is* to allow tree-shaking: #9310

The library used obj instanceof Vector3 before.
But Rich Harris implemented and changed all the checks to is* to allow tree-shaking: #9310

Thanks for the answer, I had read the thread, btw I don't understand why a class have to be avoided to be in the output if some other class needs to type-check it... I mean if, bundled class X needs to be aware that an object is a class B, then class B is used (at least to create the said object somehow) and have to be bundled, isn't it?

For example, WebGLRenderer needs to check whether a geometry it renders is BufferGeometry or Geometry, but it never creates Geometry instances. Most three.js applications should only use BufferGeometry, and so we want tree-shaking to eliminate Geometry (and its subclasses) from the bundle when possible.

In a visual way...

This pattern makes WebGLRenderer always include Geometry when bundling:

import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';

if ( geometry instanceof Geometry ) {
} else if ( geometry instanceof BufferGeometry ) {
}

This pattern does not:

if ( geometry.isGeometry === true ) {
} else if ( geometry.isBufferGeometry === true ) {
}

hey all,

given this what's our thoughts on moving forward from here?

I don't think there's any change, yet. Anything that (1) isn't in examples/js and (2) isn't extended by something in examples/js can be converted to ES6 Classes. If that process is wrapping up, we should decide when to begin switching examples/js to classes.

From memory, and after a quick look we've done a fair bit and there's still some PR's ready in waiting.

I might try re-compile my dependencies/extended-in-examples list.

@DefinitelyMaybe Hey! That sounds great, your list was super helpful. And @donmccurdy's strategy makes sense to me. 👍 I think it would be best to get closure on the work we've already done. #20070 would be a great PR to attack because it can give strategy for migrating private/hidden vars to ES6 (we need this for migration of renderers/webgl to ES6). If everybody can run the benchmarks or chime in to the discussion there, I would appreciate it. I think we have some decent options, just need to make sure performance is good.

Okay,
I may start some PR for examples rewrite to ES classes...
@mrdoob is it a problem for you doing the jsm to js script or not? (I think not but tell me if you prefer us to wait it)

Before converting the example code to classes, #20527, #20529 or a different solution should be merged first. Except for the code that meets the conditions mentioned in https://github.com/mrdoob/three.js/issues/19986#issuecomment-718308451.

@DefinitelyMaybe You said in 1st comment :

  • use class fields

1) Does it means we can use class fields for everything ?
Like so :

class Light extends Object3D {

    type = 'Light';
    isLight = true;

    color = new Color;
    intensity = 1;

    constructor(color, intensity = 1) {

        super();

        this.color = new Color(color);
        this.intensity = intensity;

    }

    copy() {
        ...
    }
}

... or it's for .is* property only ?

So then, 2) what about empty constructors? ES2015 spec said constructors with only a super() call is implicit if not provided, so some child classes can be really defined easier :

class MapControls extends OrbitControls {

    screenSpacePanning = false; // pan orthogonal to world-space direction camera.up

    mouseButtons = { LEFT: MOUSE.PAN, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.ROTATE };

    touches = { ONE: TOUCH.PAN, TWO: TOUCH.DOLLY_ROTATE };

}

And 3) what about private class fields ?

class OrbitControls extends EventDispatcher {
    ...

    #offset = new Vector3();

    // so camera.up is the orbit axis
    #quat = new Quaternion().setFromUnitVectors( object.up, new Vector3( 0, 1, 0 ) ); <= this will go in constructor because of object.up
    #quatInverse = this.#quat.clone().inverse();

    #lastPosition = new Vector3();
    #lastQuaternion = new Quaternion();

    #twoPI = 2 * Math.PI;

    update() {
        ... ( no more closure and return function here )
    }

}

Latest Chrome is supporting both public and private class fields natively now...

20395

The first key is to pass all the tests.

You will run into less trouble initially by changing less.

@marcofugaro I believe there are still some variables that can be changed into class fields, right?
I'm looking at things like:

class EdgesGeometry extends BufferGeometry {

    constructor( geometry, thresholdAngle ) {

        super();

        this.type = 'EdgesGeometry';

changed to:

class EdgesGeometry extends BufferGeometry {

    type = 'EdgesGeometry';

    constructor( geometry, thresholdAngle ) {

        super();

It is likely that we'll run into some other caveats around the place, like how I ran into "new this.contructor() != new Foo()".

private class fields

this is an on-going discussion. It'll be a while before we use it if we use it. I'm not sure of a issue or PR that I can point you towards.

@marcofugaro I believe there are still some variables that can be changed into class fields, right?
I'm looking at things like:

Yeah that can be done now. However we can't do that for .is* properties since they have to be non-enumerable and non-writable, for those we have to use Object.defineProperty(this, ....

how is it checked again? would it be possible for us to use the static keyword instead of Object.defineProperty(this, ...?

how is it checked again? would it be possible for us to use the static keyword instead of Object.defineProperty(this, ...?

I don't think so, because obj.is* have to be on instances, not on the class itself...

I'm not sure what does babel transpile exactly in current config, but we may use decorators to set a class field as non-enumerable/non-writtable:

import { unwrittable, unenumerable } from 'some/decorator/helpers.js'

class Foo {
    @unwrittable@unenumerable
    isFoo = true;
}

@DefinitelyMaybe static properties are different, they aren't accessible from the instance, rather from the class itself.

class Test {
  static staticProp = true

  constructor() {
    Object.defineProperty(this, 'definedProp', { value: true })
  }
}
const test = new Test()

console.log(test.staticProp, test.definedProp)

result:

undefined true


Edit: never mind what I was saying...
yes, yes.

My main point being that if we were to adjust the code that checks this property we could go from:

class Test {
  constructor() {
    Object.defineProperty(this, 'definedProp', { value: true })
  }
}

to

class Test {
  static definedProp = true
  constructor() {
  }
}

So I was wondering where and why this check takes place and whether or not we could change it.

@DefinitelyMaybe The problem is getting the information of an instance type. So if you could access the class of the instance to get its static prop, then why having a static prop? You already have the name of the class...

obj.constructor.isFoo == true
obj.constructor.name == 'Foo'

Edit: writing this I could figure out that having several .is* can be useful to test on each inheritance chain finally, compared to only the single final class name...

obj.constructor.isFoo || obj.constructor.isBar || obj.constructor.isBaz

Edit2: yes also the same can be achieved with classes names finally, but more complicated to test...

let types = getInheritanceNames(obj) // looping each .constructor.prototype.constructor.name
types.contains( 'Foo' ) || types.contains( 'Bar' ) || types.contains( 'Baz' ) 

from the instance

oops. re-read that one. yup, never mind what I was saying.

if ( scope.object.isPerspectiveCamera ) {
...
}
if ( geometry.isBufferGeometry ) {
...
}
if ( material.isShaderMaterial ) {
...
}

right. Two things.

  • What have we got left?

we should decide when to begin switching examples/js to classes.

  • Getting closer to needing to discuss this in order to progress.

I don't know whether we should wait for #20527 or #20529 because both of them will be trying to re-create the examples/js in it's current form, which is not where we're aiming for. My initial suggestion is to start converting examples/js as is. The question is, what troubles are we in for...

I also wanted to re-iterate something that @mrdoob said recently

I would hate forcing newbies to learn about polyfills or bundlers in order to render their first cube.

As someone who's been working with modules for the last wee while, the workflow is clear and I understand the various concepts needed to get something working. We don't need bundlers and polyfills but we will need to adjust how Three.js is initially described.

Also, perhaps the addition of a REPL but geared for Three.js could help in this area? An example being svelte's

We will need also to clarify how to replace some non-class patterns like:

function Foo() {

    this.update = function () {

        var priv = 'foo'

        return function update() {
            ...
        };

    }();

}

IMHO we could use private class fields, and make the rollup/babel transpile to old pattern for certain old browser don't implementing this natively...

IMHO we could use private class fields, and make the rollup/babel transpile to old pattern for certain old browser don't implementing this natively...

I agree with this strategy, but the decision of course depends on the core maintainers that will need to maintain that code.

cool. It might be an idea to show this off within src first, i.e. find a similarly strange pattern to what @devingfx described within src, make a PR that uses private variables instead and show what babel does with it.

any suggestions on which script?

searches: internal, private, readonly 👀

wait on, were all of the _* variables meant to be private?

...

An elephant in this room might be src/renderers/WebGLRenderer.js

How about WebGLAnimation, it's a nice small class... https://github.com/mrdoob/three.js/pull/20070

any suggestions on which script?

I'm focused on exemples/js and I found this on OrbitControls ...

show what babel does with it.

I'm pretty sure it won't output something matching mrDoob's syntax thought 😅

to right.

and oops. Where is my brain at... we will need one of #20527 or #20529 (or other) to merge in order to begin transforming the examples folder. examples/js is sticking around for the foreseeable future which means touching the examples/js folder with classes is an absolute no no. that'd break compatibility with IE... sigh.

make the rollup/babel transpile to old pattern

Guess its thinking through and supporting those JSM to JS PR's. We can take aim at the examples/jsm once a decision is reached.

Adding private variables into src is still a good idea as it would be good solution to the long standing issue of "please don't play with those variables, they've got a specific purpose"

touching the examples/js folder with classes is an absolute no no.

Ooops, my bad, I was talking about digging into exemples/jsm of course, exemples/js will be the "built" version in near future...

that'd break compatibility with IE... sigh.

What??? Are we still talking about Internet Explorer in 2020 ? Are we talking about the compatibility of a WebGL library on this 7yr old dinosaur? Seriously !! 1.4% ...
_(we should add a statistics collecter in the lib to gather if any THREE user is planing a use under IE)_

😞 BTW, it's why babel exists...

The build files three.js and three.min.js as well as all files in examples/js should still support older browsers like IE 11.

There was a PR last year that should stop support for IE 11 (#18091) but it turned out that there are still users relying on this browser. And the current policy of the project is to provide respective files for the user so they don't to perform the ES6 to ES5 conversion by themselves. This was also discussed in #20455.

the current policy of the project is to provide respective files for the user so they don't to perform the ES6 to ES5 conversion by themselves.

Okay, no problems with that policy if the source can be developed a modern way, and if resulting builds are not supposed to be readable but just working...
Because transpilers outputs such ugly code !
So I see no problems for src being written in ESnext, and builds being ugly, BUT it's a potential problem with exemples/js if this files should be readable, commented and well formed...

BTW I'm asking myself for several time why some exemples are exemples and not main core sources !?
Exemple: controls are usualy used as is, copied like optional addons and not used as a real exemple you read and draw inspiration from to write your projects, like a rotating cube exemple for instance...

_(I started my journey with THREE by a search: "webgl rotating cube" and an exemple of it leading to a 1 night code marathon developing a small game with a cube moving on platforms ^^)_

When using a proper build then it does not matter what files are in the core and what in the examples directory. As long as tree shaking properly works you only have the source files in your build which are actually required.

To me, the distinction of core and examples comes from a time where this kind of workflow was not yet available. The core should be small and compact since you had to import it completely as a single component. Only the most _important_ files should be included. What files ended up in the core was in some sense a case-by-case decision.

When using a proper build then it does not matter what files are in the core and what in the examples directory. As long as tree shaking properly works you only have the source files in your build which are actually required.

This is true for ES modules users only ;)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

filharvey picture filharvey  ·  3Comments

fuzihaofzh picture fuzihaofzh  ·  3Comments

ghost picture ghost  ·  3Comments

Bandit picture Bandit  ·  3Comments

jack-jun picture jack-jun  ·  3Comments