Skip to content

Nodes module uses class names to register nodes (addNodeClass) which crashes in production #26518

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

Closed
njarraud opened this issue Aug 1, 2023 · 13 comments · Fixed by #26846
Closed
Assignees
Labels

Comments

@njarraud
Copy link
Contributor

njarraud commented Aug 1, 2023

Description

The addNodeClass function exported from nodes/core/Nodes.js uses the name property of the nodes classes to register the nodes. The node module works well in development however when the code is packed for production, class names are often modified by the compiler and therefore the whole module crashes.

I believe that this function is mainly used by NodeLoader, but because of this test

if ( NodeClasses.has( nodeClass.name ) ) throw new Error( `Redefinition of node class ${ nodeClass.name }` );

it crashes as soon as any call to this module is made which makes it unusable for production.

Reproduction steps

  1. Import the node module in a file and build for production e.g. webpack

Code

None

Live example

None

Screenshots

No response

Version

r155

Device

No response

Browser

No response

OS

No response

@Mugen87 Mugen87 added the Nodes label Aug 1, 2023
@njarraud
Copy link
Contributor Author

njarraud commented Aug 1, 2023

Would it be acceptable to use a static property for each node class?

class BitangentNode extends Node {
    static type = "BitangentNode";
    
}

and then for addNodeClass -

export function addNodeClass( nodeClass ) {

    if ( typeof nodeClass !== 'function' || ! nodeClass.type ) throw new Error( `Node class ${ nodeClass.type } is not a class` );
    if ( NodeClasses.has( nodeClass.type ) ) throw new Error( `Redefinition of node class ${ nodeClass.type }` );

    NodeClasses.set( nodeClass.type, nodeClass );

}

createNodeFromType would be working the same way.

Therefore, the code would not require predefined class names and the node loader would be unchanged.

@sunag sunag self-assigned this Aug 1, 2023
@njarraud
Copy link
Contributor Author

njarraud commented Aug 3, 2023

There is the same issue with addLightNode and addNodeMaterial.

@danrossi
Copy link
Contributor

danrossi commented Aug 5, 2023

Terser removes the class name entirely. Here is my work around for now placing them in an exemption list.

https://github.com/danrossi/three-webgpu-renderer/blob/master/rollup.config.js#L75

@njarraud
Copy link
Contributor Author

Terser settings are not always available. e.g. NextJS

Repository owner deleted a comment from Alexander-103 Aug 11, 2023
@danrossi
Copy link
Contributor

That does use Terser also so there should be a config for adding something like this

keep_classnames: /ArrayUniformNode/

@njarraud
Copy link
Contributor Author

Nextjs actually now uses SWC by default but like for Terser, the options are handled internally by the framework and cannot be changed. I know that this is not threejs problem, but I have the feeling that this small change would make the life easier and save troubleshooting time for anybody willing to use the node system seriously in production at the moment.

@LeviPesin
Copy link
Contributor

LeviPesin commented Sep 4, 2023

I think we can do it like so:

export function addNodeClass( nodeClass, name ) {

    if ( typeof nodeClass !== 'function' || ! name ) throw new Error( `Node class ${ name } is not a class` );
    if ( NodeClasses.has( name ) ) throw new Error( `Redefinition of node class ${ name }` );

    NodeClasses.set( name, nodeClass );

}

addNodeClass( BitangentNode, 'BitangentNode' );

@njarraud Would this solve your issue?

@njarraud
Copy link
Contributor Author

njarraud commented Sep 4, 2023

Just looking at it, yes I believe I would work.

@sunag
Copy link
Collaborator

sunag commented Sep 4, 2023

We must consider serialization in this fix as well.

get type() {
return this.constructor.name;
}

@verekia
Copy link

verekia commented Sep 26, 2023

It's not much, but I am offering a $50 bounty for fixing WebGPU minification-related issues. Hopefully this is the only one!

That's the last missing bit for shipping WebGPU support to MiniMana.io :)

@verekia
Copy link

verekia commented Sep 28, 2023

With r157, running in production is now causing a new kind of bug.

It works fine in development mode, but when I build the app in production mode (with Next.js), I am now getting:

Error: NodeMaterial: Material "MeshStandardMaterial" is not compatible.

This is coming from:
https://github.com/mrdoob/three.js/blob/181e04eea8b569dc09048f9dc644310ed6b745a6/examples/jsm/nodes/materials/NodeMaterial.js#L506C22-L506C84

Does that seem minification-related?

@verekia
Copy link

verekia commented Sep 28, 2023

I'll send the bounty either way. @LeviPesin, is it fine to send the money to your GH sponsor account? If not please get in touch! On Twitter or Discord as verekia, or the email on verekia.com.

@LeviPesin
Copy link
Contributor

Does that seem minification-related?

I think it could happen from tree-shaking node materials (and addNodeMaterial calls, maybe they could be somehow specifically marked as containing side-effects).

is it fine to send the money to your GH sponsor account?

Sure!

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

Successfully merging a pull request may close this issue.

6 participants