-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Description
Describe the problem
One of the things that empowers Svelte is its compiler, which gives it superpowers, and I was wondering why, when Svelte is a compiler, we can't have support for JSX-like syntax. Snippets are one of the best features of Svelte 5, and I was wondering if Svelte's compiler can turn HTML written inside the script tag to createRawSnippet functions, which could help the compiler shine.
Describe the proposed solution
Let's say we have an object with a bunch of properties that are all Snippets. Right now, we should either manually create the Snippets using createRawSnippet or create them inside the template using #snippet block. Let's say we have similar-looking snippets that we want to pass to this object, so we would do something like =>
<script lang="ts">
const someObj = $state({
firstItem: redLi,
secondItem: blueLi,
});
</script>
{#snippet redLi()}
<li style="background: red;">red list item</li>
{/snippet}
{#snippet blueLi()}
<li style="background: blue;">blue list item</li>
{/snippet}
Now, you might immediately say, make a single snippet and use parameters for dynamic parts. Let's do that =>
<script lang="ts">
const someObj = $state({
firstItem: listItem,
secondItem: listItem,
});
</script>
{#snippet listItem(color: string)}
<li style="background: {color};">{color} list item</li>
{/snippet}
But now the issue is, we are leaving it to the renderer of the snippet to decide on the color, but we don't want that, so we try doing something like =>
<script lang="ts">
const someObj = $state({
firstItem: () => listItem("red"),
secondItem: () => listItem("blue"),
});
</script>
{#snippet listItem(color: string)}
<li style="background: {color};">{color} list item</li>
{/snippet}
{@render someObj.firstItem()}
But as we all know, you can't do this or any similar way, such as func.bind
Now you are left with using createRawSnippet which results in something like =>
<script lang="ts">
import { createRawSnippet } from "svelte";
function getListItemSnippet(color: string) {
return createRawSnippet(() => ({
render: () => `<li style="background: ${color};">${color} list item</li>`,
setup(element) {
$effect(() => {
(element as HTMLElement).style.setProperty("background", color);
});
$effect(() => {
element.innerHTML = `${color} list item`;
});
},
}));
}
const someObj = $state({
firstItem: getListItemSnippet("red"),
secondItem: getListItemSnippet("blue"),
});
</script>
{@render someObj.firstItem()}
{@render someObj.secondItem()}
Now don't you think it would be really nice if the Svelte compiler could turn the following code =>
<script lang="ts">
const someObj = $state({
firstItem: <li style="background: red;">red list item</li>,
secondItem: <li style="background: blue;">blue list item</li>,
});
</script>
Into =>
<script lang="ts">
import { createRawSnippet } from "svelte";
const someObj = $state({
firstItem: createRawSnippet(() => ({ render: () => `<li style="background: red;">red list item</li>` })),
secondItem: createRawSnippet(() => ({ render: () => `<li style="background: blue;">blue list item</li>` })),
});
</script>
Under the hood.
It would be nice to have this. The compiler can be put to great use in a scenario like this, and I believe this would make working with loops a lot easier, just like JSX. It is kind of like what Svelte already does for the template, but in the script section.
Of course, the example above is pretty simple, but in real applications, you would need to generate stuff like AST, server and client codes, hydration code and other things like that. That's why I was hoping the Svelte's compiler could actually do the creation of the raw snippet for me since it's already doing it for the HTML section.
Importance
nice to have