-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Scripts 2.1 (Class support) #5910
Conversation
Maybe I understand wrong, what is new about that? @aidinabedi implemented that and showcased it as example in his 2020 PR: #1908 I also use bundler-free ESM in combination with Anyway, what I like is established and introducing the static name for registering script's - allowing bundlers/minifiers to change all class names, but sticking to this custom name 👍 |
Unfortunately that PR has not been merged. |
Updated slightly description. class Rotator extends pc.ScriptType {
static name = 'rotator';
update(dt) {
this.entity.rotate(dt * this.speed, 0, 0);
}
}
pc.registerScript(Rotator);
Rotator.attributes.add('speed', { type: 'number', default: 42 }); Attributes are parsing as expected as well. |
This looks nice, and seems like a worthwhile improvement to the existing script system. Any thoughts @willeastcott @slimbuck @marklundin It does not go as far as #5764 is going with the new scripting system, but it's a nice improvement for existing system, and I think both should be considered for the inclusion in the engine. The ESM Script PR is aiming at engine being fully imported by the module scripts (for example like https://github.com/playcanvas/model-viewer), allowing unused parts of the engine to be three-shaken out during a bundling step (follow up PRs) |
@Maksims Presumably you didn't mean to include the update to |
// add script component | ||
box.addComponent('script'); | ||
// add rotator script to the entity | ||
box.script?.create('rotator'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use ?.
here? Isn't the script component guaranteed to be present?
@@ -640,6 +640,8 @@ class ScriptComponent extends Component { | |||
if (typeof scriptType === 'string') { | |||
scriptType = this.system.app.scripts.get(scriptType); | |||
} else if (scriptType) { | |||
if (scriptType.__name === null) | |||
scriptType.__name = scriptType.name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing; the Class.name
can be mangled in bundling and shouldn't be relied upon to be stable.
Mozilla: Minifiers and bundling name prop
Ideally we don't rely on name
. Can __name
be a required member instead of relying on the inferred name
? Does this have any implication for existing scripts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minifier will be impactful when static name
is not set on a class.
Basically there are multiple ways to specify a name for a script:
Current:
let Test = pc.createScript('test');
Using a static name property:
class Test extends pc.ScriptType {
static name = 'test';
}
Using pc.registerScript
:
class Test extends pc.ScriptType {
}
pc.registerScript(Test, 'test');
And this also works even right now, but not pretty:
class Test extends pc.ScriptType {
static __name = 'test';
}
We could define a different name for the static property to avoid collision with built-in property name
on the prototype. E.g. scriptName
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can check if the name property was explicitly defined as a static member rather than inferred using getOwnPropertyDescriptor
, which could be useful, but would need to verify. I wonder if for ES Modules, which are more likely to be minified/mangled, that we require/enforce that a name
or similar is specifically defined 🤔
This PR seems to break the class Test extends pc.ScriptType {
swap(old){
console.log('does not call')
}
}
pc.registerScript(Test, 'test') |
This may be related to the above, but I tried a var Test = class extends pc.ScriptType {
initialize(){}
update(){}
} Is there maybe a better way of doing this? |
Yes, they are related. Unfortunately as scripts are executed on load in global context, const collisions (class collisions are same) are happening. With ESM modules, this won't be a problem, as when you import script it wont collide. As |
One thing that feels a little strange, when you define class attribute properties it's not immediately clear what the default would be: class MyClass { speed = 2 }
MyClass.attributes.add('speed', { default: 1 }) Ideally, we ignore the |
I'd vote for the attribute (which is processed later) to override the variable value on the class. |
It would be good if |
I've looked into issue of conflicting attributes with class properties. Because attributes are declared as a prototype accessors after class definition, but properties are not defined as accessors (get/set), there is no way in javascript to detect if a property exists on a class definition. class Test {
foo = 42;
set bar(value) {
this.foo = value;
}
get buz() {
return this.foo;
}
}
Test.prototype.hasOwnProperty('foo') === false;
Test.prototype.hasOwnProperty('bar') === true;
Test.prototype.hasOwnProperty('buz') === true; So there are a few things we can do:
I'm afraid there is no easy solution to this here. There is also a problem for users, that we handle all parsing of raw data, in async way for attributes. If we encourage them to use their own accessors, they won't have automatic data handling. And will require their own parsers. |
Hey @Maksims, sorry for taking so long on this. Just reviewing now, is this PR still required? it seems like the |
If current implementation already works well with the name, and even if name is not provided (defaults to name of a class), then yep, its fine to close it. |
Improves
ScriptType
to be extendible byclass
, while preserving current scripting features (attributes, events, components).This allows you to define scripts as classes.
This does not change any current behavior only adds support for
class
.Scripts-related data in the hierarchy and templates will work as before, even if the old script is replaced with a new definition.
Example:
Attributes work as before:
You can use this notation in Editor already, by registering the script (before attributes):
You can define multiple scripts per file and import them as needed:
Currently
pc.createScript
automatically adds it to the script registry.So module scripts when loaded, should be added to the script registry:
I confirm I have read the contributing guidelines and signed the Contributor License Agreement.