I often find my self writing code like the following.
<span on:click={doThing}>The same content</span>
{#if something}
<div>wrapping element <span on:click={doThing}>The same content</span></div>
{/if}
{#each things as thing}
<div>{thing} <span on:click={doThing}>The same content</span></div>
{/each>
For the the purposes of DRY I would normally extract the repeating span to another component but do so can complicate styling and state access. In addition only one component would use the new component.
I propose a way of writing reusable inline blocks. Something like this.
{#block span}
<span on:click={doThing}>The same content</span>
{/block}
{#use span}
{#if something}
<div>wrapping element {#use span}</div>
{/if}
{#each things as thing}
<div>{thing} {#use span}</div>
{/each>
Something like this would be very useful. I wonder if it can be done without introducing new #use syntax, and instead use it like a regular component, ie something like:
{#block Span}
<span on:click={doThing}>The same content</span>
{/block}
<Span />
{#if something}
<div>wrapping element <Span /></div>
{/if}
{#each things as thing}
<div>{thing} <Span /></div>
{/each>
It could simply work like an imported .svelte file, but share the script and style with the rest of the component. That way you鈥檙e more free to refactor your components without having to introduce new files. It could support slots too, though I鈥檓 not sure how props might work.
I can't find the issue right now, but something like this for defining inline mini-components was considered and rejected in the past. This does seem more doable if it's more or less treated as a macro with no special scoping, but at that point this could also be implemented with preprocessors.
There is also this useful proposal: https://github.com/sveltejs/svelte/issues/2940
In case anyone is interested here's a preprocessor to implement this.
svelte({
preprocess: {
markup: input => {
const blocks = {}
const code = input.content
.replace(/<!--block\s+(.+?)\s*-->([^]+?)<!--end-->/g, (_, name, block) => (blocks[name] = block, ''))
.replace(/<!--use\s+(.+?)\s*?-->/g, (_, name) => blocks[name])
return { code }
}
})
Example
<!--block span-->
<span on:click={doThing}>The same content</span>
<!--end-->
<!--use span-->
{#if something}
<div>wrapping element <!--use span--></div>
{/if}
{#each things as thing}
<div>{thing} <!--use span--></div>
{/each>
I used comments so tools such as prettier still work.
Most helpful comment
In case anyone is interested here's a preprocessor to implement this.
Example
I used comments so tools such as prettier still work.