Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Svelte 5: Creating snippets in .svelte.js / .svelte.ts files #11261

Open
rChaoz opened this issue Apr 20, 2024 · 4 comments
Open

Svelte 5: Creating snippets in .svelte.js / .svelte.ts files #11261

rChaoz opened this issue Apr 20, 2024 · 4 comments
Milestone

Comments

@rChaoz
Copy link
Contributor

rChaoz commented Apr 20, 2024

Describe the problem

I would say that, undoubtedly, the biggest (and only?) advantage React has over Svelte, is jsx. Just open any js/ts file and write:

const myFunc = (arg) => (<p>{arg}</p>)

No need to create a component. This is incredibly helpful, for example, when using libraries like Storybook, with decorator functions. A decorator function in Storybook in React might look like this:

(Story, ctx) => <div style={{ margin: ctx.globals.marginSize + "rem" }}><Story/></div>

To implement this feature in Svelte, decorator functions return a component in Svelte Storybook. To do the same, one would have to write this as the decorator:

import MarginDecorator from './MarginDecorator.svelte'
import { setContext } from 'svelte'

(_, ctx) => {
    setContext("marginDecoratorSize", ctx.globals.marginSize + "rem")
    return MarginDecorator
}

and

// MarginDecorator.svelte

<script>
    import { getContext } from 'svelte'
    const size = getContext("marginDecoratorSize")
</script>

<div style="margin: {size}"><slot/></div>

Generally, to bridge the gap between Svelte and regular JS/TS, one has to write a Svelte component file for everything. This is one of the less fun parts of Svelte - sometimes, you need to be able to write some Svelte code, and writing a new component file, giving it a name, figuring out where to place it just sucks. This is also a lot of work for library authors - for example, to this day, Storybook still doesn't support creating stories of components with slots. Additionally, just to make the feature above work, they inject the decorator code into an actual Svelte component, which allowed calling setContext from withing the decorator function.

Describe the proposed solution

Since snippets, under the hood, are just plain JS values/functions, it would be awesome to be able to write snippets directly in .svelte.ts / .svelte.js files. Then, one could write a decorator like this:

(Story, ctx) => {
    const decorator = $snippet`
        <div style="margin: ${ctx.globals.marginSize}rem">
            {@render Story()}
        </div>
    `
    return decorator
}

Snippets with arguments could look like so:

const s = $snippet.args((a, b) => $snippet`
    <div>${a}</div>
`)
// even like this:
$snippet((a, b) => `
    <div>${a}</div>
`)
// if tag function is not needed for implementation

The possibilities would be endless!

Alternative syntax

const decorator = $snippet`
// Maybe skip name - {#snippet()}
{#snippet s()}
...
{/snippet}    
`

Regardless, I think the requirements for any syntax are:

  • must be regular JS syntax since the file extension still is .js/.ts
  • able to include arguments - a/b above
  • able to use local variables - ctx.globals.marginSize above

Questions

How should ${...} be treated/used? There are a couple of possibilities here:

  • For the first syntax - treat ${} the same as {} is normally treated in .svelte files
  • For the alternative syntax:
    const a = 1
    $snippet`
    {#snippet s(b = 2)}
    // requires compiler magic
    <Component prop={a + b} />
    // or
    <Component prop={${a} + b} />
    // ${a + b} would error statically because b is not defined
    {/snippet}
    `

Importance

would make my life easier

@rChaoz rChaoz changed the title Creating snippets in .svelte.js / .svelte.ts files Svelte 5: Creating snippets in .svelte.js / .svelte.ts files Apr 20, 2024
@7nik
Copy link

7nik commented Apr 20, 2024

This will mean that neither JS/TS parsers nor JSX parsers will be able to understand .svelte.js/ts files, which is not acceptable. In addition, in VSCode, you cannot preprocess .js/ts files, which will break even more things.
Plus, you cannot @render a component and mount() a snippet.

Maybe #10350 and #10678 could simplify your life.

@rChaoz
Copy link
Contributor Author

rChaoz commented Apr 20, 2024

@7nik My bad! True, .svelte.ts is still just a .ts file. Updated the post accordingly, to use a rune instead with regular JS syntax.

@Rich-Harris Rich-Harris added this to the 5.0 milestone Apr 21, 2024
@ssssota
Copy link
Contributor

ssssota commented May 7, 2024

Hi! I made svelte-jsx-snippet to create snippets with JSX.

@trueadm trueadm modified the milestones: 5.0, 5.x Jun 4, 2024
@ssssota
Copy link
Contributor

ssssota commented Jul 17, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants