marko-js-archive / marko-widgets

[LEGACY] Module to support binding of behavior to rendered UI components rendered on the server or client
http://v3.markojs.com/docs/marko-widgets/
MIT License
142 stars 40 forks source link

Proposal: Template as entry point for UI components #167

Closed patrick-steele-idem closed 7 years ago

patrick-steele-idem commented 7 years ago

Current setup:

src/components/my-component/

index.js

module.exports = require('marko-widgets').defineComponent({
    template: require('./template.marko'),
    getTemplateData: function(state) { ... },
    ...
});

template.marko

<div w-bind>
    ...
</div>

Proposed solution

The above setup is not bad, but there is some boilerplate that we would like to remove by making the following changes:

Marko Widgets will detect that the template is the entry point and compile the template differently such that it no longer exports a Template instance, but rather it will be a module that exports two methods:

The previous setup would now be simplified as shown below:

src/components/my-component/

component.js

module.exports = {
    getTemplateData: function(state) { ... },
    ...
};

index.marko

<div w-bind>
    ...
</div>

Additional thoughts

Future improvements

By making the template the entry point, we can do a lot more things that were not previously possible. This is because we have full control over how a Marko template is compiled while we don't have control how the user writes the JavaScript code.

Single file component

We could easily support inlining the JavaScript code for the component into the template as shown below:

<div w-bind>
    ...
</div>

<script marko-component>
var Component = {
    getTemplateData: function(state) { ... },
    ...
};
</script>

No references to marko-widgets

With the new setup, there are no references to the marko-widgets module when building a UI component. This is a good thing since it makes it easier to merge Marko Widgets functionality into the core marko package (future proposal).

Backwards compatibility

We intend to maintain backwards compatibility. Developers could start to use the new, simplified setup, but old code would continue to work.

Related proposals

yomed commented 7 years ago

Would there be any proposed changes to defineRenderer and defineWidget in this case? Are you looking to phase those out?

patrick-steele-idem commented 7 years ago

@yomed

Would there be any proposed changes to defineRenderer and defineWidget in this case? Are you looking to phase those out?

To keep things simple I didn't want to go into the split renderer case, but we would also like to simplify that as well by removing the calls to defineRenderer and defineWidget:

Split widget/renderer

src/components/my-component/

renderer.js

module.exports = {
    getTemplateData: function(state) { ... },
    ...
};

widget.js

module.exports = {
    handleFooClick: function() { ... },
    ...
};

index.marko

<div w-bind>
    ...
</div>
philidem commented 7 years ago

I would very much look forward to this change.

basickarl commented 7 years ago

Ah, this looks amazing!

Also:

module.exports = {
    getTemplateData: function(state) { ... },
    ...
};

Not?:

export default {
    getTemplateData: function(state) { ... },
    ...
};
patrick-steele-idem commented 7 years ago

@basickarl You are free to use ES6 (you'll need to use babel on both the server and the browser if you use import/export though). We plan on allowing the following as well:

export default class {
    handleFooClick() { ... }
    handleBarClick() { ... }    
    ...
};

The only good reason to use class is that you don't have to worry about comma separators, which is kind of nice.

patrick-steele-idem commented 7 years ago

Closing this issue in favor of the issue created on the marko repo: https://github.com/marko-js/marko/issues/416