The documentation does not indicate if component inheritance can be done with Svelte.
Is it possible for a component at definition time (before the compilation, not at instantiation time) to inherit the default data, methods, helpers, hooks, components and events from another component or to overwrite them ?
Is the HTML part of a component and the style a property that could be inherited or overwritten too ?
Thanks for the nice repository.
+1 to this!
At least in the react community, composition and higher-order-components are preferred instead of inheritance. I opened #195 for some features that could make HOC a lot simpler in svelte.
Would love to see this as well!
I think there are three relevant concepts here: modules, composition and inheritance.
Modules allow for separating, organizing and avoiding the duplication of code. Composition allows for nesting or mixing components together, and inheritance allows for a meaningful and hierarchical organization of components (which helps too for the non-duplication of code).
To me, they all are helpful and have their own usage, they are complementary. But some trouble may come when one uses them for the finality of the others, because one mixes their purposes which gets confusing. Inheritance makes the components better self-contained and there is less guessing about what they are. Because components are objects, they are instantiated, so inheritance makes sense.
High-order components seem more like an attempt to do inheritance based on composition principles (from top to bottom). But composition and inheritance have different purposes.
That's why I like, personally, to have both in my code. This allows for a better thinking about the application, and finally, a better organization too.
I'm of the 'favour composition over inheritance' school – in my experience, inheritance is more trouble than it's worth. Your components become less predictable (because you have to understand the inheritance chain before you can get a handle on how a component behaves – just reading the code in a single file no longer suffices), and you have to either mess around with transpilers (which not everyone wants to do) or implement a non-standard super.method() equivalent.
That said, I'd be curious to know more about where you'd want to use inheritance so we can understand the problem more fully.
What comes to mind is the following: prototyping the DOM helpers, observe method, and other things that are common to all components into a base class component could be a way of introducing inheritance that would reduce code duplication (#9) as well as answer to the need for scaling up the application with many components that are hierarchically related, but not necessarily "composited".
In simpler words, the idea would be to extend a base component class like so:
<div>Hello!</div>
<script>
export default class Hello extends Base {
data () {
},
methods:{
sayHello(){}
}
render(){}
};
</script>
Then, the Hello component itself could be extended like so:
<div>Hello Plus!</div>
<script>
import Hello from 'Hello.html'
export default class HelloPlus extends Hello {
methods:{
sayHelloPlus(){}
}
render(){}
};
</script>
Like the importing of nested components, one would import the component to extend, so there would not be more separation than with nested components. In both cases, one would import a component either for compositing either for extending either for both...(#51)
One component could extend another by simply modifying its HTML, CSS, just adding some methods to it or even completely changing it while keeping the parent component events and data. There would be much flexibility.
That is just an idea that came naturally in mind when looking at the structure of the components while reading the documentation and the examples.
Exporting a class doesn't really work, because classes can only have methods. It also introduces a hard requirement to transpile your code. Realistically, inheritance would work more like this...
<script>
import Base from './Base.html';
export default {
base: Base,
// ...
};
</script>
...but without a real world use case I'm still not convinced it's desirable. It doesn't really add any expressive power, because you could easily share methods like so:
<script>
import sayHello from './sayHello.js';
export default {
methods: {
sayHello,
sayHelloPlus () {}
}
};
</script>
This is much clearer in my opinion.
Yes, one meaned more something like that:
<div>Hello {{who}}! {{what}}</div>
<script>
import helpers from './helpers.js';
import Base from './Base.html';
export default class Hello extends Base {
constructor(what, who){
this.helpers = helpers;
this.data = {
what:what,
who:who
};
this.events = {};
},
sayHello() {},
render(){}
};
</script>
and
<div>Hello Plus {{who}} !
<super duber="cool">{{what}}</super>
</div>
<script>
import super from 'super.html'
import Hello from 'Hello.html'
export default class HelloPlus extends Hello {
sayHelloPlus() {}
}
</script>
That is much more concise :)
That won't work – it needs to be an object literal for the sake of static analysis.
Alright, I thought one could have used some es6 introspection functionalities on this.
So, unleashing the power of POJOs, that would give the nicer and more functional:
Hello.html:
<div>Hello {{who}}! {{what}}</div>
<script>
import helpers from './helpers.js';
import Base from './Base.html';
export default Object.create(Base).assign({
data() {
return {
what:"",
who:""
}
},
helpers : helpers,
events: {},
sayHello() {},
render(){}
});
</script>
and HelloPlus.html:
<div>Hello Plus {{who}} !
<zuper duber="cool">{{what}}</zuper>
</div>
<script>
import zuper from 'zuper.html'
import Hello from 'Hello.html'
export default Object.create(Hello).assign({
sayHelloPlus() {},
components: {
zuper
}
});
</script>
Not sure how that would work into the svelte internals though :)
I'm wondering now, as it is simply a POJO, perhaps does it already work out of the box ?
It's not about whether it's a POJO, it's about whether it's an object literal, by which I mean that the declaration property of the default export is a node of type ObjectExpression. See http://astexplorer.net/#/FiqmTmmpOG.
I'm going to close this though as I don't think there's a good argument in favour of implementing inheritance.
Alright, so that is quite restrictive... As there is no inheritance and no will to implement it, I won't bother you more with it. Thanks for the time explaining.