Marko: Deprecate use of constructor

Created on 14 Mar 2017  路  5Comments  路  Source: marko-js/marko

__tldr; Use onCreate instead of constructor because of limitations associated with native ES6 classes.__

With the release of 4.0, we added support for an onCreate lifecycle method which was able to be aliased as constructor when using the class syntax to define a component.

This was implemented as a simple assignment.

Unfortunately, we have discovered that despite the claim that class is just syntactic sugar over typical JS prototypal inheritance, this is not actually the case. There are limitations around how the constructor is implemented. Although the constructor is typeof "function"' and instanceof Function, it cannot be called without the new keyword and cannot use its prototype methods of call and apply. This prevents us from dynamically inheriting from Component (which has a constructor that we would want to call _before_ the user's constructor. Also, Component is actually only inherited from in the browser).

We didn't catch this earlier because we used the ES5 equivalent of classes in our tests because phantomJS (which we use in our test suite) does not support ES6.

Additionally, onCreate is not _quite_ the same as constructor. It is a lifecycle method that is called when the component is created. In the case of a server render, handing off to the browser, it does not get called when mounting in the browser. A component fires create, input and render on the server and then _only_ mount in the browser. The way ES6 classes are implemented would necessitate that constructor be called both on the server and in the browser for these isomorphic renders, which is not what we'd like.

constructor will continue to work in from a single-file component (we already transpile to a plain object with an onCreate method), but we will add a deprecation warning when using constructor.

To summarize, classes have issues and internally, Marko does not use true classes. We really only support the class syntax because it looks nice and you don't have to separate methods with commas.

Most helpful comment

I use a lot of classes outside of Marko specific code and use the onCreate method instead of the constructor method to avoid confusion. I advocate removing the constructor method and standardize the onCreate method across both module.exports and the Marko class component definition.

All 5 comments

On a related note, should class { ... } be renamed to component { ... }? That seems like a more accurate description, fits better with the theme (style { } => style.css, component { } => component.js), and would be less likely to confuse new users who expect it to behave like an ES6 class.

I use a lot of classes outside of Marko specific code and use the onCreate method instead of the constructor method to avoid confusion. I advocate removing the constructor method and standardize the onCreate method across both module.exports and the Marko class component definition.

Is this also why I cannot use the "extend" keyword on a component class? I would have assumed with a transpiler that I could inherit from a base classes, but Marko throws an error about "a component cannot be a function." This kind of sucks as there are methods I find myself having to add to components over and over because I can't just inherit a base component. :( I usually end up with an ugly mixin object.

@jasonmacdonald Yeah, we probably need to make this more clear, but extends is not something we can support. Internally, marko creates its own class for each component that extends our base Component class and components can't extend multiple classes. mixins are the way to go.

Was this page helpful?
0 / 5 - 0 ratings