-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Description
Describe the problem
Explanation
Previously in Svelte 3/4, you could just do v instanceof SvelteComponent
, v.constructor === SvelteComponent
, or whatever prototype crawling thing at runtime you decided. However, in Svelte 5, there doesn't seem to be an exposed way to check that a function is a component/snippet, or just a regular function.
Use-case
This makes conditional rendering of polymorphic values difficult, such as if i wanted to provide either a component, or a factory/predicate that returns a component conditionally.
Personally, my use case is to create a component that can render either a parameterless-snippet, propless-component, or a value, for a library.
Describe the proposed solution
Compiler
The Svelte compiler could either brand each component it generates:
// App.js
export const App = ($$anchor, $$props) => { /* ... */ };
$.brand_component(App); // or $.brand_snippet(snippet);
or use a WeakSet
that contains every component/snippet:
// App.js
export const App = ($$anchor, $$props) => { /* ... */ };
$.register_component(App); // or $.register_snippet(snippet);
EDIT: I found snippet_symbol
that Svelte already uses to validate snippets:
const snippet_symbol = Symbol.for('svelte.snippet'); |
Maybe this can be extended to be applied to components as well, & exposed externally to be checked?
Consumer
It could then be checked using a isComponent
/isSnippet
API:
<script>
import { isComponent, isSnippet } from 'svelte';
let { v } = $props();
</script>
{#if isComponent(v)}
<svelte:component this={v} />
{:else if isSnippet(v)}
{@render v()}
{:else}
{v}
{/if}
Alternatives considered
The current hack I'm using just assumes all functions it receives are Svelte components/snippets if it has either 1 or 2 parameters, & simply decide between the render strategy based on that. It does nothing to decide if it's a component/snippet in the first place.
<script>
let { v } = $props();
</script>
{#if typeof v === 'function'}
{#if v.length === 2}
<svelte:component this={v} />
{:else if v.length === 1}
{@render v()}
{:else}
{v}
{/if}
{:else}
{v}
{/if}
If I really would want to decide if it's a component/snippet, I guess I could use 💀runtime source-based reflection💀, or basically:
typeof v === 'function' && String(v).includes('$$anchor');
which STINKS.
Importance
would make my life easier
Activity
dummdidumm commentedon Dec 13, 2023
Duplicate of #9774
sxxov commentedon Dec 13, 2023
@dummdidumm I don’t think this is a duplicate, since this isn’t purely asking to differentiate snippets from components, but rather both from regular functions. At their core, solving either would solve each other partially, I just went ahead & extrapolated the rest based on my use-case.
Feel free to explain to me if I’m mistaken!
dummdidumm commentedon Dec 13, 2023
It's asking basically for the same, but I'll make a note in the other issue