Skip to content
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

Material: use class properties #24237

Merged
merged 1 commit into from
Dec 21, 2022

Conversation

marcofugaro
Copy link
Contributor

@marcofugaro marcofugaro commented Jun 15, 2022

Related issue: #22437

Description

1 year has passed since last time we tried. Maybe it's time to test the waters again? 🤓

create-react-app has since released version 5, which uses Webpack 5. So it doesn't error there anymore.

@LeviPesin
Copy link
Contributor

Shouldn't we then also do the same with MeshPhysicalMaterial (#clearcoat and #transmission)?

@Mugen87
Copy link
Collaborator

Mugen87 commented Jun 15, 2022

What are the benefits of doing this? Is it only syntactic sugar?

I have the feeling it's still too early for this. We should not assume that all devs use the latest versions of their bundlers. And depending on the project, it's not always possible to upgrade to the latest bundler version.

@marcofugaro
Copy link
Contributor Author

What are the benefits of doing this? Is it only syntactic sugar?

Better tree-shaking for other bundlers that are not rollup.

I have the feeling it's still too early for this. We should not assume that all devs use the latest versions of their bundlers. And depending on the project, it's not always possible to upgrade to the latest bundler version.

Ok, what timeline are you proposing?

@Mugen87
Copy link
Collaborator

Mugen87 commented Jun 15, 2022

I wish I could make a precise suggestion here...

The problem is that this kind of syntax potentially breaks builds. And there is normally no other solution than upgrading the build-tool (which might not be possible in all scenarios).

I think I would only introduce this kind of syntax if there is a compelling reason. Just further improving tree-shaking capabilities seems not appropriate to me if we risk to break other projects.

@marcofugaro
Copy link
Contributor Author

I agree that it might break some builds. But my point of view is that if people are willing to upgrade three in their existing projects, they are willing to upgrade their bundler as well.

Webpack 5 has been out since Oct 2020.
create-react-app 5 has been out since last December, but upgrading create-react-app to 5 is just a dependency bump.

@mrdoob
Copy link
Owner

mrdoob commented Jun 17, 2022

10 months have passed since last time we tried. Maybe it's time to test the waters again? 🤓

I remember Safari being a problem too 🫠

@mrdoob
Copy link
Owner

mrdoob commented Jun 17, 2022

@Mugen87

I think I would only introduce this kind of syntax if there is a compelling reason. Just further improving tree-shaking capabilities seems not appropriate to me if we risk to break other projects.

One benefit of this is that we don't pollute the class and when the dev console.logs and object the list of properties is cleaner.

@Mugen87
Copy link
Collaborator

Mugen87 commented Jun 17, 2022

That's true! I'm just afraid about the breaking character of this change.

@mrdoob
Copy link
Owner

mrdoob commented Jun 17, 2022

Oh yeah, definitely...
I wouldn't mind giving it a try, but first we would have to check what's the support on iOS.

@marcofugaro
Copy link
Contributor Author

Ok, iOS Safari supports class fields since version 14.5 released on April 26, 2021.

image

Safari for desktop support it from version 14.1 which has been released around the same time.

image

Keep in mind that in term of support there is no distinction between private, public or static. It's all supported the same.

Source

@ycw
Copy link
Contributor

ycw commented Jun 19, 2022

@Mugen87

What are the benefits of doing this? Is it only syntactic sugar?

I think it's a good move for code robustness.

e.g. Vector3 uses Euler's privates by accident

setFromEuler( e ) {
this.x = e._x;
this.y = e._y;
this.z = e._z;
return this;
}

would be better to declare them as private fields in Euler:

class Euler {
  #x = 0
  #y = 0
  #z = 0

so err can be detected by lsp, or on running tests

e.g. WebglBindingStates sets a InstancedBufferGeometry's private which is not even declared

if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {
geometry._maxInstanceCount = data.meshPerAttribute * data.count;
}

would be better to declare it as internal public field in InstancedBufferGeometry, like

class InstancedBufferGeometry {
  /** @internal **/
  maxInstanceCount = undefined
}

or, serialization-friendlyer:

class InstancedBufferGeometry {
  #maxInstanceCount = undefined 
  setMax(v) {..}
  getMax() {..}
}

@CodyJasonBennett
Copy link
Contributor

@Mugen87, would you be more comfortable with this change if we tested for compat with previously problematic tools? Are there any besides Webpack 4-5 (CRA) and Safari? This is stable in Node itself since v12, so this isn't imposed on the runtime, as far as tooling. This is a reoccurring question, and one might want a https://caniuse.com for the state of tooling.

CDNs and services like https://skypack.dev and https://bundlephobia.com could also be of note. Importantly, I've found the latter to break on optional chaining (es2020 -- see esbuild's guide on JS features/version), so I had to transpile to es2018. If this is still the case, it would be good to report ahead of time for a smooth rollout.

@marcofugaro
Copy link
Contributor Author

For Bundlephobia it has already been reported: pastelsky/bundlephobia#559 (they are using webpack 4).

I don't think that tool is being maintained that much...

@donmccurdy
Copy link
Collaborator

I don't have any particular opinion about class properties, but I wish we could address these discussions with a policy on browser and bundler support, and (ideally) set up tests against that. For example:

  • support last 1-2 versions of modern web browsers
  • support last 1-2 major releases of popular bundlers
  • support current Node.js LTS release (language features, not platform APIs)

@CodyJasonBennett
Copy link
Contributor

CodyJasonBennett commented Dec 15, 2022

We still transpile to es2018 around pmndrs for things like class properties, nullish coalescing, etc. (this is an issue for Webpack 4 and older Node versions), but there might be related tooling that accepts a browserslist with a policy you're describing. The real point of tension is that this isn't automated via transpilation for addons, so we have to resort to lint rules (#23763) and integration tests (not implemented AFAIK) whereas it can be automatic for the core. I'm not sure how helpful the linter has been, but I hoped it would enforce a policy like this.

@donmccurdy
Copy link
Collaborator

donmccurdy commented Dec 15, 2022

I'm glad to have the linter, it simplifies these conversations generally. I guess the issue here is that we're discussing a feature the listed browsers already support, but the bundlers maybe don't, so we're flying blind on that a bit.

If targeting a particular EcmaScript version would work better i'm all for that, but wasn't sure if it'd line up cleanly enough with browser and/or bundler support.

@WestLangley
Copy link
Collaborator

Is there someone who will volunteer to manually test this PR (and #25104) against Webpack, Parcel, Vite, ESBuild?

That way we know, and we can move forward.

@CodyJasonBennett
Copy link
Contributor

CodyJasonBennett commented Dec 15, 2022

I have a similar repo that was testing tree-shaking with a bunch of different tooling in troika https://github.com/CodyJasonBennett/treeshaking (inspired by efforts over here), but this PR still doesn't play nice with Webpack 4. I resolved similar with pmndrs/meshline today for Webpack 4 (CRA, Storybook) specifically.

@marcofugaro
Copy link
Contributor Author

We still transpile to es2018 around pmndrs for things like class properties

Transpilation was brought up in the past, the core maintainers are against it.

Is there someone who will volunteer to manually test this PR (and #25104) against Webpack, Parcel, Vite, ESBuild?

Ok! I tested and confirm that this PR (and #25104) works with all current versions of the bundlers. ✅

Bundler Current version Works since version Works since date
Webpack v5.75.0 v5.0.0 Oct 2020
create-react-app v5.0.1 v5.0.0 Dec 2021
Next.js v13.0.6 v10.0.0 Oct 2020
Rollup v3.7.4 v2.4.0 Apr 2020
esbuild v0.16.7 v0.8.13 Nov 2020*
Vite v4.0.1 v2.0.0 Feb 2021*

*Or even before, I wasn't able to test previous versions because old esbuild doesn't support arm64 mac.

I'll let @mrdoob and @Mugen87 decide which version back they want to support, like @donmccurdy proposed.

@CodyJasonBennett
Copy link
Contributor

CodyJasonBennett commented Dec 15, 2022

You're completely ignoring my comment and Don's. This comes across as misleading and needlessly contrarian, and I've seen a history of this from you. I apologize if there's a language barrier but this is burning me out of further discussion.

@LeviPesin
Copy link
Contributor

I have a similar repo that was testing tree-shaking with a bunch of different tooling in troika https://github.com/CodyJasonBennett/treeshaking (inspired by efforts over here), but this PR still doesn't play nice with Webpack 4.

But is Webpack 4 currently used much (except in Bundlephobia)?

@CodyJasonBennett
Copy link
Contributor

But is Webpack 4 currently used much (except in Bundlephobia)?

Yes, and this is a constant conversation with big frameworks being likely culprits. I'm happy to go over trends to gauge progress or timeline. https://twitter.com/devongovett/status/1602459843784282113

This is something we deal with everywhere which is why I focus on this issue since it's treated so haphazardly in three, and only previously due to lack of observability or tooling. This would otherwise be automated (via an ES version, browserslist) if addons weren't shipped as source code, which I believe is the main issue here; this is automatic for the core and there's still a myriad of ways of doing this for addons with a policy in place, such as the linter or ideally automated as a bundle.

@LeviPesin
Copy link
Contributor

(Some) addons already use class fields, so they already don't support Webpack 4, but nobody has complained, so maybe we still can use class fields in addons.
And maybe we can potentially use a transpiler for core builds? @mrdoob

@CodyJasonBennett
Copy link
Contributor

(Some) addons already use class fields, so they already don't support Webpack 4, but nobody has complained, so maybe we still can use class fields in addons.

pmndrs/three-stdlib

@LeviPesin
Copy link
Contributor

Then if somebody wants to use addons witn Webpack 4 they can use three-stdlib.

@CodyJasonBennett
Copy link
Contributor

CodyJasonBennett commented Dec 16, 2022

What I was saying is that the comment is wrong and irresponsible. That project exists because of the mismanagement of addons which I've been trying to resolve here by means of tooling, discussion, or code change. It doesn't matter whether you want to support Webpack 4 as much that this is codified in the first place. Doing this after the fact by means of damage control is not okay.

@mrdoob
Copy link
Owner

mrdoob commented Dec 20, 2022

@marcofugaro

Do you know if this would still breaks bundlephobia?

And, if so... maybe we can just add a transpilation step for the builds to avoid breaking it?

@marcofugaro
Copy link
Contributor Author

Do you know if this would still breaks bundlephobia?

@mrdoob apparently it was fixed. Did a quick test and it works fine!

https://bundlephobia.com/package/[email protected]

@mrdoob
Copy link
Owner

mrdoob commented Dec 21, 2022

Alright! Lets give it a try.

@mrdoob mrdoob added this to the r148 milestone Dec 21, 2022
@mrdoob mrdoob merged commit 1dc9d43 into mrdoob:dev Dec 21, 2022
@LeviPesin
Copy link
Contributor

And, if so... maybe we can just add a transpilation step for the builds to avoid breaking it?

But maybe we should still add a transpiler to account for the usage of Webpack 4?

@mrdoob
Copy link
Owner

mrdoob commented Dec 21, 2022

I rather wait to see how many people complain.

@mrdoob
Copy link
Owner

mrdoob commented Dec 21, 2022

However, all builds except three.module.js are already being transpiled: 69b4ef2

@LeviPesin
Copy link
Contributor

Can we also enable transpilation for three.module.js?

@mrdoob
Copy link
Owner

mrdoob commented Dec 21, 2022

If we did, when do you think we should remove it?

@LeviPesin
Copy link
Contributor

When the number of downloads of Webpack 4 per week will become significanfly less than that of Webpack 5.

@mrdoob
Copy link
Owner

mrdoob commented Dec 21, 2022

Ah... Where can I see that info? 👀

@LeviPesin
Copy link
Contributor

Here: https://www.npmjs.com/package/webpack?activeTab=versions. Currently the number of Webpack 4 downloads is more than twice of Webpack 5's.

@drcmda
Copy link
Contributor

drcmda commented Dec 21, 2022

If we did, when do you think we should remove it?

transpilation is a necessary step, there's no incentive to remove it. babel grows with javascript and incorporates all new specs and features, then makes sure the code can run everywhere.

threes current setup says browserslist > 1%, we can exclude really old browsers, modern only, and it specifically marks class props for transpile.

not doing that for addons (and/or three.module) will bar people from using this library. but why? it would just be an additional rollup entry without any downsides. 🤷‍♂️

@Mugen87
Copy link
Collaborator

Mugen87 commented Dec 21, 2022

transpilation is a necessary step, there's no incentive to remove it.

That is unfortunately not true. We always have tried to keep the number of dev dependencies to a minimum for easier maintenance. One major reason for three.js's success is simplicity and complexity avoidance. I actually wanted to suggest to remove the entire Babel stack as soon as we get rid of the three.cjs, three.min.js and three.js build targets.

With canisue and listings like #24237 (comment) (@marcofugaro thanks again!), I think we can estimate when is the right time to introduce new JS language features.

Sidenote: Personally, I believe transpilation is an awful thing in the web context. JavaScript is easy to use and learn because you write code that is 1:1 executed in the browser. That is what the web makes exciting. When we use language features that common browsers and build tools can understand, we don't have to give up this great feature.

Of course we should also encourage users and devs to upgrade their browsers and tools as far as possible.

@LeviPesin
Copy link
Contributor

But if we are going to use a feature that less than a third of Webpack users can work with, isn't it more of breaking their tools rather than encouraging an upgrade?

@Mugen87
Copy link
Collaborator

Mugen87 commented Dec 21, 2022

Yes, I think the introduction of class properties comes too early. I don't think there is an urgent reason to rely on this syntax right now. Same for stuff like nullish coalescing.

Mugen87 added a commit that referenced this pull request Dec 21, 2022
@drcmda
Copy link
Contributor

drcmda commented Dec 21, 2022

@Mugen87 i think there some major misconceptions ...

  • dev dependencies don't affect the end user
  • babel is inlined and won't contribute to extra dependencies
  • the overhead is either nothing, or a tiny shim
  • whatever shim there is gets eliminated as babel flags browser usage as < 1%
  • people inspecting source still read the original, because source maps
  • there are zero downsides, it just allows threejs to run safely everywhere

Sidenote: Personally, I believe transpilation is an awful thing in the web context

shipping code that only few browsers can handle is making it harder for any individual or professional entity to publish software. and this all seems more ideologically motivated rather than objective. this is an open source library, people who want to study source come here. out there the only thing this library has to accomplish is to be used.

With canisue and listings like #24237 (comment) (@marcofugaro thanks again!), I think we can estimate when is the right time to introduce new JS language features.

this is what babel is for, and it is excellent at it. and you are using it already for that exact purpose, but only for that file, and not for another.

One major reason for three.js's success is simplicity and complexity avoidance. I actually wanted to suggest to remove the entire Babel stack as soon as we get rid of the three.cjs, three.min.js and three.js build targets.

a build process is there to avoid complexity. not having it would only delegate the complexity towards end users, as it already does, and oss contributors with arbitrary rules like "you can't use nullish coalescing just ...yet".

mrdoob pushed a commit that referenced this pull request Dec 22, 2022
@donmccurdy
Copy link
Collaborator

donmccurdy commented Dec 22, 2022

The current proposals are:

  • (A) Write ESNext and transpile to ES2018
  • (B) Write ES2018, and lint to enforce it

Both choices are fine, and there are downsides to each, including Babel1 and ESBuild. Either way, the output is ES2018, and the difference is only in maintainer-facing tools. The decision on class properties appears to be made: we are not using them at this time. (#25168)

I don't think class properties are going be a winning argument for transpiling the whole codebase, they don't matter to maintainers that much; this isn't a good context to rehash it again. If anyone would like to make a broader proposal about improving three/addons/ in relation to three-stdlib, or the build process in general, let's make that in a new ticket with clearly framed goals, RFC-style.


1 predictable performance in hot code paths, predictable size, not mucking with regenerator-runtime dependencies, ...

@mrdoob
Copy link
Owner

mrdoob commented Dec 22, 2022

It's funny how the problem that transpilers were supposed to solve is now worse because of... transpilers.

We've reverted this change (#25168). We can give it another go next year.

@Mugen87
Copy link
Collaborator

Mugen87 commented Dec 22, 2022

Write ES2018, and lint to enforce it

How can we update the linter so this is automatically checked? When writing #25172, I've used the search to find the respective syntax.

@CodyJasonBennett
Copy link
Contributor

CodyJasonBennett commented Dec 23, 2022

predictable performance in hot code paths, predictable size, not mucking with regenerator-runtime dependencies, ...

This doesn't affect us and is why we choose es2018, either handwritten or via transpiler. ESBuild has a good breakdown of syntax-to-version if you're unsure of what this changes: https://esbuild.github.io/content-types/#javascript.

How can we update the linter so this is automatically checked? When writing #25172, I've used the search to find the respective syntax.

I added notes and am tracking it in #25185.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants