rfcs icon indicating copy to clipboard operation
rfcs copied to clipboard

Add `<svelte:this />` tag

Open kwangure opened this issue 3 years ago • 9 comments

Rendered

kwangure avatar Aug 19 '21 08:08 kwangure

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.

Prinzhorn avatar Sep 29 '21 16:09 Prinzhorn

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}/>

kwangure avatar Oct 04 '21 20:10 kwangure

<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

Prinzhorn avatar Oct 05 '21 09:10 Prinzhorn

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.

kwangure avatar Oct 05 '21 11:10 kwangure

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.

lukaszpolowczyk avatar Dec 03 '21 17:12 lukaszpolowczyk

<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}/>

winstonDeGreef avatar Mar 20 '22 16:03 winstonDeGreef

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.

kwangure avatar Mar 20 '22 16:03 kwangure

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.

  1. on:destroy={handler}
  2. on:destroy={[handler, preprocessorHandler]

winstonDeGreef avatar Mar 20 '22 22:03 winstonDeGreef

<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>...

lukaszpolowczyk avatar Apr 07 '22 04:04 lukaszpolowczyk