mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
101.99k stars 35.33k forks source link

Evaluate ES6 classes #11552

Closed arctwelve closed 3 years ago

arctwelve commented 7 years ago

Why is this 'idiom' of inheritance being introduced into the code:

PointLight.prototype = Object.assign( Object.create( Light.prototype ), {

Seriously? Function(nested Function(ParentPrototype) COMMA SHOTGUN BRACKET?

The faithful two line style still in, for example, the Materials classes are much clearer and cleaner. Assign the prototype and then set the constructor. The end. Please don't ruin the library by catching JavaScript disease - the bizarre need to masturbate the way objects and inheritance are coded. One style throughout the library. No need to change it.

bhouston commented 5 years ago

We also need to get all all examples integrated into /src with some type of tree shaking.

Right now the code structure for Three.JS is so 2014 and just a pain to work with.

pailhead commented 5 years ago

All of the examples?

bhouston commented 5 years ago

Examples/js

On Mon, Jan 7, 2019, 10:25 AM Dusan Bosnjak <notifications@github.com wrote:

All of the examples?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mrdoob/three.js/issues/11552#issuecomment-451970482, or mute the thread https://github.com/notifications/unsubscribe-auth/AAj6_Q3Kakb5Qn2DqGbMVvLkW_28cOyaks5vA2b5gaJpZM4N9vH8 .

mrdoob commented 5 years ago

@bhouston

A good half way step to TypeScript woudl be to add type files beside every JavaScript file. Thus there would be both:

Vector3.js Vector3.d.ts

Would .d.ts files act as .h files in c?

bhouston commented 5 years ago

Would .d.ts files act as .h files in c?

That is a very good analogy. Interesting someone has done most of this already here: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/three Thus really it would just taking ownership of these type files and integrating it into Three.js. If you want we can create a PR that integrates this into Three.js and splits its up proper.

bhouston commented 5 years ago

To show how popular Typescript is look at how many @Types/three is downloaded per week:

https://www.npmjs.com/package/@types/three - 63,000 downloads per week.

mrdoob commented 5 years ago

Impressive!

If you want we can create a PR that integrates this into Three.js and splits its up proper.

Sounds good to me 👍

donmccurdy commented 5 years ago

Is it possible to run a commandline check, similar to eslint, ensuring that the type files and source .js files align? If we're taking ownership of the d.ts files, it would be strongly preferable to have some way of regularly verifying that they match.

bunnybones1 commented 5 years ago

To show how popular Typescript is look at how many @Types/three is downloaded per week:

https://www.npmjs.com/package/@types/three - 63,000 downloads per week.

I would attribute this more to the popularity of Visual Studio Code, because it happens automatically when you use Visual Studio Code, via their Automatic Type Acquisition feature. That said, it can't be ignored.

tschoartschi commented 5 years ago

@flyover @bunnybones1 @mrdoob @looeee @donmccurdy @bhouston @roomle-build @pkieltyka @FriOne @joejordanbrown since you all seem to be interested in TypeScript I wanted to note that I created a new issue concerning TypeScript. I think it makes sense to move all the TS discussions there. If you are interested you can find it here: https://github.com/mrdoob/three.js/issues/15545

corbanbrook commented 5 years ago

I am willing to commit time to port to ES6 classes. I think this will be a good bridge solution to one day supporting Typescript.

mrdoob commented 5 years ago

The first step is to convert some of the add-ons to ES6.

https://github.com/mrdoob/three.js/tree/dev/examples/jsm

Controls, Loaders and Exporters are good candidates. Feel free to help!

donmccurdy commented 5 years ago

@mrdoob just to confirm, you mean converting them to ES modules but not using other ES6 features yet, right?

I assume the process of doing that conversion is:

  1. Use modularize.js script to convert the original file to an ES module.
  2. Clean up issues if needed.
  3. At some point (this release, or in the near future) we'll start using rollup-examples.config.js to convert the ES modules to UMD modules, at which point the version in examples/js is no longer maintained by hand.
  4. Once that is stable, we can consider other changes like introducing ES6 features.
mrdoob commented 5 years ago

@mrdoob just to confirm, you mean converting them to ES modules but not using other ES6 features yet, right?

Yeah, sorry. I should have specified.

LuWang9018 commented 5 years ago

I and @bhouston have created the promised PR that contributes the *.d.ts files for most of the Three.JS project. https://github.com/mrdoob/three.js/pull/15597

dionysiusmarquis commented 5 years ago

I just can‘t wait for ES6 classes and Typescript definitions. Everytime I‘m working with three.js i have to copy paste hundred of code lines to reimplement one function that lies in an unaccessable scope. It’s really not an elegant way to work if you have to optimize your scenes. It would take the workflow to a new level to finaly be able to extend and override functions. So please make class functions at least „protected“ and accessable without exception 🤗

donmccurdy commented 5 years ago

Everytime I‘m working with three.js i have to copy paste hundred of code lines to reimplement one function that lies in an unaccessable scope. ... So please make class functions at least „protected“ and accessable without exception.

@dionysiusmarquis I'm not sure I understand what you mean here ... the existing TS typings have functions you want to use incorrectly marked as private? Or something about the current prototype-style class definitions makes use in TS hard? Could you share an example?

dionysiusmarquis commented 5 years ago

Everytime I‘m working with three.js i have to copy paste hundred of code lines to reimplement one function that lies in an unaccessable scope. ... So please make class functions at least „protected“ and accessable without exception.

@dionysiusmarquis I'm not sure I understand what you mean here ... the existing TS typings have functions you want to use incorrectly marked as private? Or something about the current prototype-style class definitions makes use in TS hard? Could you share an example?

I just wanted to implement a specific shadow map for a specific scenario. It would have helped to be able to override getDepthMaterial for example. At the moment i inject my own WebGLShadowMap in the build process with a copy/paste version including my desired changes. It would be so nice if every single three.js class would expose as much as possible. With typescript you can easily flag functions as private or protected to describe the intended purpose. My ES6 Class/Typescript ShadowMap for example looks like this:

interface MaterialCache {
  [uuid: string]: {[uuid: string]: MeshDepthMaterial}
}

class ShadowMap {
  public enabled: boolean = false
  public autoUpdate: boolean = true
  public needsUpdate: boolean = false
  public type: ShadowMapType

  …

  protected depthMaterials: MeshDepthMaterial[]
  protected materialCache: MaterialCache

  constructor (renderer: WebGLRenderer, objects: WebGLObjects, maxTextureSize: any) {
    …
  }

  protected getDepthMaterial (object: Object3D, material: Material) {
    …
  }
}

export { ShadowMap as WebGLShadowMap }

It just feels like home if you are allowed to modify "low level" classes

EliasHasle commented 5 years ago

I have a question in context of classes. How would we transfer methods like Vector3.unproject into the class syntax? The method actually uses a closure in order to create a new scope. This is an important mechanism that keeps the amount of object creations as low as possible.

Do we need Object.assign in these cases? @Mugen87

You can do closures with classes now. It's just not obvious how to navigate in that syntactic sugar. See my answer on StackOverflow: https://stackoverflow.com/questions/39297258/iife-in-es6-class-literal/56077521#56077521 (I must be humble and admit that I don't fully understand how/why it works.)

Mugen87 commented 5 years ago

Sorry, but this code looks like an anti-pattern and we should not adapt this in the project. There are proper solutions for managing variables in module scope. I suggest to go this route.

tschoartschi commented 5 years ago

@Mugen87 yes I also think we should make good use of module-scope. This would also help for things like tree-shaking. This was already discussed in many other issues like this one: https://github.com/mrdoob/three.js/issues/6241#issuecomment-398703521

EliasHasle commented 5 years ago

Sorry, but this code looks like an anti-pattern and we should not adapt this in the project. There are proper solutions for managing variables in module scope. I suggest to go this route.

No problem. I just mentioned the possibility. If you have a better/cleaner solution under way, I am eager to see it in action. The Three.js project (usage, source, discussions etc.) has been my main source of JS knowledge, so introducing new and better programming patterns to Three.js will probably benefit me and my projects too. Nothing to be sorry for . ;-)

gkjohnson commented 5 years ago

@Mugen87 Can you elaborate a little on why you consider class-IIFEs an anti pattern if only so I can learn and understand a bit more? I understand that modules scope variables inherently but that's no different than how core was being built previously. And with so many functions using cache variables it's going to be really important to make sure none of the functions collide or use variables at the same time -- the function scoping makes this easier to manage and maintain, which is why I don't see it as an anti-pattern (at least when compared to throwing all the cache variables in the module scope).

Mugen87 commented 5 years ago

Can you elaborate a little on why you consider class-IIFEs an anti pattern

I would not use an approach that potentially impede tree-shaking like mentioned here: https://github.com/mrdoob/three.js/pull/14695. Besides, I think the entire pattern looks like a hack. Using less "fancy" approaches usually work better. Avoiding unnecessary closures should also improve the code execution performance in general (can't prove this with a reference but I've heard it on a talk some time ago).

And with so many functions using cache variables it's going to be really important to make sure none of the functions collide or use variables at the same time.

The IIFEs are mainly used in the math classes. Since we have a good amount of test coverage there (@gero3 did a great job lately by adding more unit tests), it should be easier to make the removal of them robust.

bhouston commented 5 years ago

It is fine to remove IIFEs. I think I am responsible for it back in 2013. It was to get rid of a static variable pattern that was hard to maintain. It was done in this PR:

https://github.com/mrdoob/three.js/pull/2941

https://github.com/mrdoob/three.js/issues/2936

And discussed even earlier here:

https://github.com/mrdoob/three.js/pull/2920#issuecomment-12217793

bhouston commented 5 years ago

Interesting fact, when we put these in, there was not a code performance difference.

DefinitelyMaybe commented 4 years ago

I assume the process of doing that conversion is:

  1. Use modularize.js script to convert the original file to an ES module.
  2. Clean up issues if needed.
  3. At some point (this release, or in the near future) we'll start using rollup-examples.config.js to convert the ES modules to UMD modules, at which point the version in examples/js is no longer maintained by hand.
  4. Once that is stable, we can consider other changes like introducing ES6 features.

hey. might've missed it but what was this our incremental steps towards classes?

donmccurdy commented 4 years ago
  1. [x] Use modularize.js script to convert the original file to an ES module.
  2. [x] Clean up issues if needed.
  3. [ ] At some point (this release, or in the near future) we'll start using rollup-examples.config.js to convert the ES modules to UMD modules, at which point the version in examples/js is no longer maintained by hand.
  4. [ ] Once that is stable, we can consider other changes like introducing ES6 features.

In the steps above, we've essentially finished steps (1) and (2).

Step (3) we are not doing that way any more, but will instead deprecate and remove the examples/js folder at some point (see https://github.com/mrdoob/three.js/pull/18749).

I think that means that step (4), introducing ES6 classes to examples/jsm can only be done (for now) on the very few examples that aren't generated from examples/js source versions. Once examples/js is removed, we can do the rest.

^But I might be reading too much between the lines here, maybe @Mugen87 or @mrdoob can confirm?

Mugen87 commented 4 years ago

IMO, the project should focus on the deprecation and removal of examples/js in order to achieve a module only code base. In the next step, I would recommend to move on with the class migration. Starting with the examples and then migrating the core.

DefinitelyMaybe commented 4 years ago

perfect. thank you. will take a closer look those ways

DefinitelyMaybe commented 4 years ago

Reposted from closed issue. Hi there,

I wanted to create this issue to try and tease out everyone's thoughts on how we'd like to move forward with class migration.

My quick summary of what I've come across so far:

Have I missed anything?

donmccurdy commented 4 years ago

We should deprecate the examples folder before doing anything else

I'm not sure who is responsible for any specific next step on the examples/js folder. Unless we can articulate that plan, I'd prefer that this didn't block converting things to ES classes. For that reason, I somewhat disagree with https://github.com/mrdoob/three.js/issues/11552#issuecomment-592768708. 🙂

DefinitelyMaybe commented 4 years ago

further to that, it appears that we're just waiting on a date to be set

DefinitelyMaybe commented 4 years ago

Also, as part of a bit of revision I did, I found this comment about how other ES2015 features could be introduced via the current rollup build process. There is even an example given.

edit: here's a gist of a another quick example

DefinitelyMaybe commented 4 years ago

Let's start the conversion train. File dependencies comment.

ianpurvis commented 4 years ago

@DefinitelyMaybe I've got some time and I'd love to help. Can I take some items on the dependencies.json list?

DefinitelyMaybe commented 4 years ago

👍

let's call dibs on things

ianpurvis commented 4 years ago

@DefinitelyMaybe What is the best way to deal with inheritance from a deep ancestor like Object3D? For example, I ran into breakage converting src/audio/AudioListener.js:

[ROLLUP] bundles src/Three.js → build/three.js...
[ROLLUP] (!) Error when using sourcemap for reporting an error: Can't resolve original location of error.
[ROLLUP] src/audio/AudioListener.js: (137:1)
[ROLLUP] [!] Error: 'return' outside of function
[ROLLUP] src/audio/AudioListener.js (137:1)
[ROLLUP] 135:   };
[ROLLUP] 136: 
[ROLLUP] 137:   return AudioListener;
[ROLLUP]        ^
[ROLLUP] 138: }(Object3D));
[ROLLUP] Error: 'return' outside of function
DefinitelyMaybe commented 4 years ago

we were going to make a note at the top of the file about any issues we run into, if Im remembering correctly.

ianpurvis commented 4 years ago

I misunderstood what was happening with AudioListener... After some debugging, I think there is a matching issue in the bubleCleanup transform. See https://github.com/mrdoob/three.js/pull/19934#issuecomment-667411997 for some more info. I ran into this with a few different classes, so we'll probably have to get it sorted before going much further.

DefinitelyMaybe commented 4 years ago

this will be the case for some of the files but not all. We were anticipating such an issue.

DefinitelyMaybe commented 4 years ago

For those following along, please have a quick read of the discussion over here.

In the mean time, dibs on src/loaders!

Mugen87 commented 3 years ago

Closing in favor of #19986.