rfcs
rfcs copied to clipboard
Add `<svelte:this />` tag
I wouldn't deprecated the current API because your design suffers from one limitation: you can only get a single reference to each of the things. But there are pre-processors that dynamically need to use things like onDestroy
(e.g. https://github.com/zodern/melte). If the old API is removed and you cannot import onDestroy
this would become a mess.
I propose one <svelte:this />
tag, but you can get multiple references. Preprocessors by definition run before the compiler and can modify markup as needed.
<svelte:this
on:destroy={localHandler}
on:destroy={preprocessorHandler}
on:destroy
bind:props={localProps}
bind:props={preprocessorPropVar}/>
<svelte:this on:destroy={localHandler} on:destroy={preprocessorHandler} on:destroy bind:props={localProps} bind:props={preprocessorPropVar}/>
This is not valid. I don't know what parser Svelte uses, but none of setAttribute
, getAttribute
or removeAttribute
can work with duplicates. As far as I'm aware nowhere in Svelte are duplicate attributes currently used or allowed. You get a "Attributes need to be unique" error. And since Svelte tries to be as close to valid HTML as possible I don't see this happen.
Lifecycle functions also don't have to be inside a .svelte
file, as long as they run synchronously on component creation. This is not only relevant for preprocessors but also useful for other abstractions, e.g. https://github.com/zodern/melte/blob/8884995a9dc27af2852f838bea15ea09f21b7ea2/tracker.js#L8-L12
Binding to DOM elements needs attributes to be unique because setAttribute
/getAttribute
would overwrite each other. So far $feature
APIs in Svelte have largely been readonly which means they're not bound by the uniqueness constraint.
I'm not sure if there's a technical reason why bind:clientWidth
and bind:offsetWidth
are required to be unique even though they're readonly. Perhaps for onsistency with other attributes? 🤷
That said, I agree there is a case to be made for external code doing their own clean up and handling lifecycle events imperatively.
I have a suggestion for dispatch
:
<script>
function sayHello() {
testevent({
test: 'food'
});
}
</script>.
<svelte:this dispatch:testevent />
<div on:click={sayHello}>test</div>.
That is with dispatch:testevent={testevent}
or dispatch:testevent
and WITHOUT e.g. let testevent = _=>{};
.
With bind:name
you need let name;
, but this is a different syntax and can be simplified.
Giving the name already in the attribute also makes it clearer.
<svelte:this on:destroy={localHandler} on:destroy={preprocessorHandler} on:destroy bind:props={localProps} bind:props={preprocessorPropVar}/>
Instead of that, it could be possible that multiple bindings on atributes are seperated by commas. ie:
<svelte:this
on:destroy={localHandler, preprocessorHandler}
bind:props={localProps, preprocessorPropVar}/>
The comma is already an operator in JavaScript. Comma separated values returns the last value in a list.
let foo = ("bar", "baz");
console.log(foo); // baz
Tangentially, a debugging tip: do on:destroy={console.log(handler), handler}
when want to log inline expressions in the Svelte curly braces to see what's what.
The comma is already an operator in JavaScript. Comma separated values returns the last value in a list.
let foo = ("bar", "baz"); console.log(foo); // baz
Tangentially, a debugging tip: do
on:destroy={console.log(handler), handler}
when want to log inline expressions in the Svelte curly braces to see what's what.
or make it possible for on:destroy
etc. to accept an array aswel.
This would make it so that the both following possibilities are valid.
-
on:destroy={handler}
-
on:destroy={[handler, preprocessorHandler]
<svelte:this>
+ SvelteKit
I think it would be interesting to add stores $app/stores
from SvelteKit as a <svelte:this>
parameter:
<script>
let pathname = 'untracked';
function start_subscribing() {
page.subscribe($page => {
pathname = $page.url.pathname;
});
}
</script>
<svelte:this
stores:navigatin
stores:page
stores:session
stores:updated
/>
Benefit: Avoids the special case with getStores()
that you need to use, if you need to defer store subscription until after the component has mounted, for some reason. With <svelte:this stores:page>
the behavior is always the same.
I don't know how feasible it would be to contain the SvelteKit part inside <svelte:this>
, but the whole <svelte:this>
is also only theoretical for now...
I wonder if anything else could be moved to <svelte:this>
...