Updates

These posts are aggregated from Svelte GitHub Repository.

  • Svelte Philosophy

    This is an attempt to articulate the Svelte philosophy — our bedrock principles, that guide our design decisions.
  • Add an easier way to pass snippets as render parameters

    I've seen this topic mentioned in https://github.com/sveltejs/svelte/discussions/15822, but I feel it could be better discussed as a potential feature rather than a question.

    Currently, if I need to pass a snippet as a parameter to a @render tag, I need to declare it beforehand, like so:

    {#snippet dataItem(name: string, value: Snippet)}
      <div>
        <dt>{dtValue}:</dt>
        <dd>{@render ddValue()}</dd>
      </div>
    {/snippet}
    
    {#snippet value()}<strong>ipsum</strong>{/snippet}
    {@render dataItem("Lorem", value)}
    

    On top of creating many single-use variables (if rendered more than once), which can lead to mistakes, it's also just a very labored way of doing it. It's problematic to the point where it almost makes more sense to copy-paste the contents of the snippet to avoid those issues.


    One way to fix the problem would be to allow for @render to receive children, like so:

    {#render dataItem("Lorem", value)}
      {#snippet value()}<strong>ipsum</strong>{/snippet}
    {/render}
    

    This approach would have a few problems:

    • Snippets' parameter names currently have no impact on how these parameters are passed, since they're set up like functions. That would need to change in order to receive snippets (and children) by name, which seems like a pretty big undertaking;
    • The @render tag would now need to be written as #render, though it could simply support both ways;
    • If this were to be implemented, there'd be very little separating a snippet from a component other than scale.

    Another way would be to pass anonymous snippets directly in the @render call, like so:

    {@render dataItem(
      "Lorem",
      {#snippet}<strong>ipsum</strong>{/snippet}
    )}
    

    This would circumvent the first two issues above, but it would mean blending HTML into what I think is supposed to only accept JS, which seems to be something Svelte managed to avoid doing up until now.


    I had originally planned to post this as a feature request, but since I'm undecided as to which feature should be introduced, if any at all, I think I'll defer to the more experienced Svelte devs as to how to solve this problem.

  • Recent stability issues

    Hello there!

    Let me start but saying that by no means this is a rant. I have a great respect for the core team and I love working with svelte. I've also got my first contribution approved and was super happy to finally contribute back to the framework!

    Recently (like maybe a couple month) it feels like stability is somewhat declining. Some issues are getting fixed and some new ones appear. There are currently 6 issues with p0 label some of which are dating back to the end of April.

    We are using svelte heavily in production and currently are in a bit of a weird spot. We can't really downgrade because we are using some newer features like attachments and need some newer bugfixes, but we also can't really upgrade to get some of the issues fixed because something new gets broken. Also it gets increasingly difficult to hunt for reproductions. It was never easy, at some point I've spent a week to find what is causing a memory leak, but now it feels like it's even harder.

    We've started using svelte about a year ago and back then it was sort of the opposite. It felt like every new release was providing greater stability and performance.

    Maybe the core team is also noticing this? Are there any opinions on the matter?

    Back in the days it was also extremely helpful when we had some calls with Dominic and he was helping me figure out reproductions for some memory leaks, so he could fix them. I am wondering if something like this could be possible now with other maintainers?

    Thank you!

  • An $attachments() rune alongside with $props()

    Right now the documentation says:

    When used on a component, {@attach ...} will create a prop whose key is a Symbol. If the component then spreads props onto an element, the element will receive those attachments.

    Which makes handling attachments inside the component a bit tricky, basically I'm using this approach:

    <script>
        let { title, text, ...props } = $props();
        let customStylingAttachment = props[Object.getOwnPropertySymbols(props)[0]];
    </script>
    
    <div {@attach customStylingAttachment}>
    ... whatever goes here with {title} and {text}
    </div>
    

    Probably it would be nice to use something like:

    <script>
        let { title, text } = $props();
        let attachments = $attachments();
    </script>
    
    <div {@attach attachments[0]}>
    ... whatever goes here with {title} and {text}
    </div>
    
  • Possible shortcuts for $state/$derived

    I just came across Ripple. While I'm not a fan of the JSX style syntax (one of the reasons I moved away from React), at first glance, I do like the more concise reactive variable declarations:

    let $count = 0;
    let $double = $count * 2;
    

    How feasible would it be for Svelte to support two syntaxes, the current $state/$derived and a way similar to Ripple as above? Alternatively, supporting short aliases ($ = $state, $$ = $derived):

    let count = $(0);
    let double = $$(count * 2);
    
  • Question about Svelte v5 bundled code and rolldown

    Hello, everyone!

    I'm trying to set up some (integration - I guess) tests to test my routing library's "tree-shakability" (it is @wjfe/n-savant, if you're curious). My plan is as follows:

    1. Create base project with only package.json.
    2. Install dev dependencies: rollup, rolldown, rollup-plugin-svelte, plus any other packages to also test bundling with webpack, RsPack, etc.
    3. Create configuration files for each of the bundlers.
    4. Prepare test cases: One index.js file per test case, where I individually import and use each one of the exports of the library.
    5. Create the special test cases base and full, where the former is an index.js with just a console.log() line, and the latter imports and uses every object from the routing library.
    6. Run the test matrix (probably in GH Actions).
    7. Collect file manifest and total bundle sizes.
    8. At least for now, no pass/fail criteria. Just collect data in a nice table and commit a Markdown file.

    This sounds like a solid plan to me but do tell me if I'm wrong/delusional. 😄

    Anyway, I'm testing the project out with rolldown, and to my surprise the base test case creates a bundled index.js of almost 93kb. Examining the bundled file, it is almost all Svelte code.

    Since I'm a noob at tree-shaking and rolldown, my question is: Why does this happen? Or is it even normal for this to happen?

    In contrast, bundling the same project with rollup, the bundled JS file only carries the following before the code from my index.js file:

    // generated during release, do not modify
    
    const PUBLIC_VERSION = '5';
    
    if (typeof window !== 'undefined') {
        // @ts-expect-error
        ((window.__svelte ??= {}).v ??= new Set()).add(PUBLIC_VERSION);
    }
    

    Could it be that I'm making a mistake in my rolldown config? Here it is:

    import { defineConfig } from "rolldown";
    import svelte from "rollup-plugin-svelte"
    
    export default defineConfig({
        input: "index.js",
        output: {
            dir: "bundle"
        },
        treeshake: true,
        plugins: [
            svelte({})
        ]
    });
    
  • Multiple slots/snippets in the layout in svelte 5

    Describe the problem

    In svelte 4, it was not possible to use multiple slots in the layout. Snippets have appeared in svelte 5, which should replace slots, and for myself I found such an option for several snippets in the layout. It works fine, maybe it will be useful to someone. I wanted to ask, how valid is this?

    My store file (store.ts):

    import type { Snippet } from 'svelte';
    import { writable, type Writable } from 'svelte/store';
    
    export let Header: Writable<Snippet> = writable();
    export let Footer: Writable<Snippet> = writable();
    

    My +layout.svelte:

    <script lang="ts">
        import { Footer, Header } from '$lib/scripts/store';
        let { children } = $props();
    </script>
    {@render $Header?.()}
    {@render children?.()}
    {@render $Footer?.()}
    

    My +page.svelte

    <script lang="ts">
        import { Header, Footer } from '$lib/scripts/store';
        $Header = header;
        $Footer = footer;
    </script>
    
    {#snippet header()}
        Header
    {/snippet}
    
    <div>Content</div>
    
    {#snippet footer()}
        Footer
    {/snippet}
    

    Describe the proposed solution

    I wanted to ask, how valid is this?

    Importance

    would make my life easier

  • How to properly read arbitrary element props?

    I updated the global HTMLAttributes interface to add a property like so =>

    declare global {
      namespace svelteHTML {
        interface HTMLAttributes<T> {
          test?: () => void;
        }
      }
    }
    

    Now I was hoping to access and read this like element.test after getting a reference to the element, but element.test is undefined; There is an element.__attributes which has the "test" property inside of it, but I'm not sure if it's a good Idea to use this. What should I do instead? I want to be able to read objects and functions, not just strings, like you would normally do with data-attributes.

  • Using <svelte:boundary> just to be able to define {@const}?

    I'm building a web page with lots of long forms. Is it a good idea to use svelte:boundary around each form element so that I can define consts? Or does it come at a cost?

    For example, instead of:

    <div class="mb-4">
      <label for="fDepartment" class="form-label mb-1">Department</label>
      <select
        id="fDepartment"
        class="form-select"
        bind:value={$modalForm.dept}
        class:border-danger={!!$modalForm.errors.dept}
      >
        <option value="">Please select</option>
        {#each deptOptions as option (option.value)}
          <option value={option.value}>{option.text}</option>
        {/each}
      </select>
      {#if !!$modalForm.errors.dept}
        <div class="invalid-feedback d-block">{$modalForm.errors.dept}</div>
      {/if}
    </div>
    

    I could do:

    <svelte:boundary>
    {@const field = 'dept' }
    {@const label = 'Departament' }
    {@const error = $modalForm.errors[field] }
    <div class="mb-4">
      <label for="f-{field}" class="form-label mb-1">{label}</label>
      <select
        id="f-{field}"
        class="form-select"
        bind:value={$modalForm[field]}
        class:border-danger={!!error}
      >
        <option value="">Please select</option>
        {#each deptOptions as option (option.value)}
          <option value={option.value}>{option.text}</option>
        {/each}
      </select>
      {#if !!error}
        <div class="invalid-feedback d-block">{error}</div>
      {/if}
    </div>
    </svelte:boundary>
    

    Which seems cleaner and less error prone. (It is not practical for me at this point to convert these form fields to components because there are too many small differences and things to take into account).

    Would you advise against it for some reason?

  • JSR registry publish fails with "Unknown module" error for Svelte components

    Describe the bug

    When attempting to publish a Svelte component library to the JSR registry, the publish process fails with the error Expected a JavaScript or TypeScript module, but identified a Unknown module. Importing these types of modules is currently not supported.

    The error appears to be caused by dist/index.js containing references to .svelte files, which JSR doesn't recognize as valid module types. Is the recommended solution to transpile all .svelte files to .js before publishing? Does the Svelte compiler support this?

    Several Svelte libraries are already available on JSR, but the build process for component libraries isn't clear from any of the documentations.

    Reproduction

    https://github.com/kotkoroid/repl-svelte-library-jsr-publish

    Logs

    johndoe@Johns-MacBook-Air repl-svelte-library-jsr-publish % bunx jsr publish
    Downloading JSR release binary...
    [00:01] [#################################################>] 35.7 MiB/36.5 MiB
    error: Expected a JavaScript or TypeScript module, but identified a Unknown module. Importing these types of modules is currently not supported.
      Specifier: file:///Users/johndoe/Workspace/Dev/repl-svelte-library-jsr-publish/dist/components/Heading.svelte
        at file:///Users/johndoe/Workspace/Dev/repl-svelte-library-jsr-publish/dist/index.js:1:36
    Child process exited with: 1
    

    System Info

    System:
        OS: macOS 15.5
        CPU: (8) arm64 Apple M2
        Memory: 90.48 MB / 16.00 GB
        Shell: 5.9 - /bin/zsh
      Binaries:
        Node: 22.14.0 - ~/.nvm/versions/node/v22.14.0/bin/node
        Yarn: 1.22.22 - ~/.nvm/versions/node/v22.14.0/bin/yarn
        npm: 10.9.2 - ~/.nvm/versions/node/v22.14.0/bin/npm
        pnpm: 10.10.0 - ~/.nvm/versions/node/v22.14.0/bin/pnpm
        bun: 1.2.16 - ~/.bun/bin/bun
      Browsers:
        Safari: 18.5
      npmPackages:
        svelte: ^5.34.3 => 5.34.3
    

    Severity

    blocking all usage of svelte

Loading Svelte Themes