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.
  • API and language feature requests Svelte & SvelteKit

    Hi, I have some language and API feature request regarding some concepts in svelte and also in sveltekit. I came across some parts when developing with sveltekit that were tricky to achieve with the current way svelte works.

    Svelte features

    1. Snippets vs Components I know snippets are different from components but why are they exactly? I know you can use them to define some inline UI and even programmatically via createRawSnippet. However, when it comes to passing UI around via functions, props etc. it becomes extremely difficult to differentiate between a Snippet and a Component.

    Question: So can Snippets and Components actually just be one thing: Components only. This way you always know what you will end up with and perhaps even make a way to create components programmatically. This is very handy when building components libraries and generic components.

    SvelteKit features

    1. app.html vs an App.svelte The reason why I come up with this one is because in (nearly) every other frontend framework an App shell is just as well a component. In SvelteKit this is app.html. Now I do like the fact that it is all very vanilla but the use of placeholders like %sveltekit.head%, %sveltekit.body%, %sveltekit.assets% and the new %sveltekit.version% could have soo much more potential when they are capable of being used within svelte components just as much. That way you don't have to hack your way around getting the svelte version, asset directory base etc. and the hooks version of transformPageChunk becomes unnecessary.

    2. API features in SvelteKit When browsing the new features in the SvelteKit docs I saw the base and resolveRoute import from '$app/paths' was replaced with resolve. This is absolutely awesome however, I had some situations where I needed base as a variable to replace in a path. This may not be the best example but I would think a more preferred option is to either have a method that aside from resolve returns the base path.

    These features I tried hacking my way around but I keep finding myself copy-pasting alot of these "hacks" to make them work in other sveltekit projects so I thought they may be a great addition to be adopted natively.

  • `effect_orphan` Error When Importing `.svelte` Files from Another Package in Svelte 5 with esbuild

    I'm running into issues using Svelte 5 with esbuild when importing .svelte files from another package. This setup worked fine in Svelte 4, but in Svelte 5 I'm seeing the following error:

    effect_orphan: `$effect` can only be used inside an effect
    

    My Setup

    • I'm using esbuild with esbuild-svelte and svelte-preprocess
    • I import .svelte components directly from another package (uncompiled .svelte files)
    • The imported components use $effect internally

    In Svelte 4, this worked without problems. In Svelte 5, I consistently hit this effect_orphan error — which seems to suggest that effects are not properly registered or that component code isn't being compiled in the expected context.

    Workaround

    If I copy the component into my app instead of importing it from the package, it works.

    Questions

    Is there something special required to support $effect/Svelte 5 reactivity when importing non-precompiled .svelte files using esbuild?

  • Proper design for externally synced state

    Hi all, I was wondering what the nicest way in Svelte 5 with runes of the following would be: I have a let myState = $state("some string") which is synced via websocket. When a websocket message is received, the value should be updated. I also want to be able to bind it to an input field. Whenever the user types in the field or some other logic on the UI updates the value, it should be sent to the backend via websocket. Ideas I have considered:

    Using $effect

    If I use a $effect(() => sendViaWebsocket(myState), this triggers also after an incoming websocket message and sends the value back, although this is not neccessary :-(

    Using a wrapper class with a value copy

    untested pseudocode in a something.svelte.ts file:

    class MyStateWrapper<T> {
        private readonly state = $state();
        private copy: T;
        constructor(initialValue: T) {
            state = $state("some string");
            copy = initialValue;
            $effect(() => {
                if (copy != state) {
                    sendViaWebsocket(state);
                    copy = state;
                }
            });
        }
        public updateFromWebsocket(value: T) {
            copy = value;
            state = value;
        }
    }
    

    this just feels complicated, and I always have to write wrapper.state instead of state.

    Manually sending the websocket message

    I could also just use a onchange for the input field, update the state there and also send the websocket message. However, then I loose the syntactical niceness of bind:value...


    I think syncing state via websocket is quite a common usecase. Therefore, does anyone have an idea on how to do this properly? Thanks in advance!

  • Generic Component binding feature parity

    Hi, I have a problem that I've spent the past week thinking about/working on that I cannot find a solution for. I've asked a few parts of this piecemeal in the Discord, but haven't gotten responses or a complete solution.

    The problem

    I have built a component layout manager library that deals with generic components. A simplified example of how I am handling components is as follows:

    interface ComponentContainer<T extends Component<any> = Component<any>> {
        component: T;
        props: ComponentProps<T>;
    }
    
    let components: ComponentContainer[] = $state([
        { component: Foo, props: { a: 1, b: 2, c: 3 }},
        { component: Bar, props: { a: 1, b: 2, c: 3 }},
        { component: Baz, props: { a: 1, b: 2, c: 3 }},
    ]);
    

    And rendered as

    {#each components as c}
        <c.component {...c.props} />
    {/each}
    

    The problem I'm running into is the inability to support two way binding. My library supports persisting layouts, which provides unexpected results when bindable props aren't propagated back to the root layout structure.

    Approach 1 (Unsupported)

    The ideal approach to solving this problem is unsupported: Supporting the bind: directive for prop spreads. I've seen this discussion goes back years without much movement so I'm not expecting it to be a viable solution.

    On top of the lack of movement, the discussion I've seen also seems be lacking any way to selectively bind props - it's all or nothing. The proposals also seem to be mostly concerned with ergonomics, rather than enabling feature parity for generic components. Unlike with concrete components, this is no alternative to spreading with generic components.

    Approach 2

    The second approach is to bypass the svelte template syntax and use the imperative component API. The approach I've come it with for this is

    1. Pull out the bindable properties from the Component<T> type
    type ComponentBindables<Comp extends Component<any, any, any>> =
        Comp extends Component<any, any, infer Bindable> ? Bindable : never;
    
    1. Accept an array of properties to bind
    interface ComponentContainer<T extends Component<any> = Component<any>> {
        component: T;
        props: ComponentProps<T>;
    +    bindings?: ComponentBindables<T>[];
    }
    
    1. Mimic the bind: behaviour by transforming each bound property into a { get; set; } pair.
    2. Render/mount/hydrate the component with our { get; set; } pairs as needed.

    I have tested, in the most basic case, that this approach can work. However I have some issues, some minor and some blockers:

    • Minor: This is kind of a gross approach.
      • It really feels like I'm doing something wrong, but I can't see an alternative.
      • It feels brittle, with things like async svelte being able to break previously working code
    • Minor-ish: The documentation for the imperative component API provides no explanation on how to use it. From what I have managed to figure out: mount is basically inferior to hydrate and doesn't really have a use. From that, render should be called on the server and inserted into the component anchor with {@html ...}. And then hydrate should be called on the client inside of the parent components onMount callback.
    • Major: I can't figure out how to support async svelte
      • I know this is brand new and experimental so I don't exactly expect docs, but the docs make no mention of async
      • For render() it seems I can simply await it
        • Side note: I think the return type RenderOutput may be incorrect, and also is not exported
      • hydrate() I can't figure it out. When there is server rendered HTML inside of the anchor then hydrate will throw for async components.
      • I'm not really sure how to handle the fact that async svelte is experimental and consumers of my library may or may not have it turned on and be giving me async components
    • Major: Mimicking the behaviour of bind:, despite being common from what I've gathered in other issues, is internal behaviour and not a publicly guaranteed contract that I would like to be depending on

    Have a missed a better approach? Or is this something that svelte just doesn't really support at the moment? Any help is appreciated.

    I'm happy to provide more information or playground reproductions if it helps in any way.

  • Wrong version mentioned in docs ?

    Exporting snippets something is wrong here

    Note: This requires Svelte **5.5.0** or newer No ?

    REF docs snippet export

  • Bun plugin to use SvelteKit imports in standalone scripts

    When using Bun with a SvelteKit application, you often need to run standalone scripts that reuse code from your app. But SvelteKit uses special module imports that don't work outside the SvelteKit context:

    // In SvelteKit:
    import { DATABASE_URL } from '$env/static/private';
    
    // In Bun scripts:
    const DATABASE_URL = process.env.DATABASE_URL; // or Bun.env.DATABASE_URL
    

    This makes it hard to share utility functions between your SvelteKit app and CLI scripts without duplicating code or creating environment-specific wrappers.

    I created a simple Bun plugin that resolves SvelteKit's virtual modules, allowing you to use the same imports everywhere:

    • $env/static/private → maps to Bun.env
    • $app/environment → returns { dev: true }

    Now you can write shared code once and use it in both your SvelteKit app and Bun scripts without any modifications.

    https://github.com/mquandalle/bun-plugin-sveltekit

  • FYI: It seems Amazon is being flooded by Svelte 4 AI generated books

  • Anyone uses Svelte and Bun without problems?

    So, I'm learning Svelte and Sveltekit, and I was wondering if anyone has success using it with bun as, svelte-adapter-bun seems to be abandoned and hasn't been updated for 2 years.

    I'm at the point where I'm learning Postgres and if bun doesn't work, I should know to not invest in their SQL API and use a JP library, until (and if) a proper adapter fully merges.

  • Async SSR

    The Svelte team has been hard at work on asynchronous rendering, with client-side support and remote functions as our first two efforts. It’s time for the third: SSR.

    Background

    There are three core pieces to the async problem:

    1. Server-side rendering (the process of running code on the server and creating HTML/JS/CSS from that code)
    2. Hydration (the process of taking server-rendered code and attaching interactive JavaScript processes to it)
    3. Client-side rendering (the ongoing process of state management and DOM coordination after hydration)

    The interplay between these creates a number of challenges for anyone seeking to create a seamless end-to-end experience.

    Design

    When asynchronously rendering on the server, any await expressions not contained in a svelte:boundary with a pending snippet will block until their associated promise resolves. Await expressions behind a svelte:boundary with a pending snippet will not be reached — but more on that later. This means that if you write the following:

    <div>{await delayed("Hey y'all!", 1000)</div>
    

    The resulting HTML output will look like this:

    <div>Hey y'all!</div>
    

    …and if you had a boundary with a pending snippet:

    <div>{await delayed("Hey y'all!", 1000)</div>
    <svelte:boundary>
      <div>{await delayed("What's up?", 1000)</div>
      {#snippet pending()}
        <div>Loading...</div>
      {/snippet}
    </svelte:boundary>
    

    …the output would look like this:

    <div>Hey y'all!</div>
    <div>Loading...</div>
    

    Because we have cool compiler superpowers, we can also optimize your code. The following would take one second to render, not two:

    <div>{await delayed("Hey y'all!", 1000)</div>
    <div>{await delayed("What's up?", 1000)</div>
    

    You can use await everywhere — in component <script> blocks, in $derived expressions, in templates, and in normal modules and async functions.

    What about hydration?

    When you render asynchronous content on the server, then send it to the client and hydrate it, one of two things will happen:

    • If you rendered a pending snippet on the server, the client will kick off the asynchronous work, replacing the pending snippet when the asynchronous work is done
      • This is… fine… but it means you have to make two server round-trips to finish rendering your content. The first trip gets your SSRed page, the second gets the asynchronous stuff behind the boundary. See the next section for our answer to this.
    • If you rendered blocking asynchronous content (anything not behind a pending boundary), that content will be “normally” hydrated

    The latter behavior might raise some eyebrows. What it means, practically, is that this:

    <div>I slept for {await sleep(Math.random() * 1000)} milliseconds!</div>
    

    Would output something like this on the server:

    <div>I slept for 567 milliseconds!</div>
    

    …and then, on the client during hydration, we’d wait for another random amount of time and you’d see it change to:

    <div>I slept for 243 milliseconds!</div>
    

    This really isn’t very desirable behavior. During hydration, you typically want to stick with the stuff you rendered on the server unless it actually needs to change! What we need to be able to do is render something asynchronously on the server, then hydrate it synchronously on the client based on what we rendered on the server. This requires serialization at some point. Somehow, we have to get the data you’ve rendered over the wire in such a way that we can retrieve it on the client and hydrate it into reactive JavaScript.

    React solves this problem by making the serialization boundary be the client component. Data passed from a server component to a client component has to be serializable so that it can be sent over the wire and used in hydration. The downside of this approach is that React has to live in two worlds, where some of your components are server components (and therefore only run on the server) and some of them are client components (and therefore run on both the server, for initial renders, and the client for subsequent client-side ones). Svelte has always been a very isomorphic framework — we believe the Svelte code you write should be able to run equally well on the server and the client. Keeping to these roots, we think the more logical place to put this serialization boundary is at the resource level — at the actual place you’re fetching the data.

    Thankfully, we’ve already taken care of this problem for you with remote functions in SvelteKit. Given a setup like this:

    export const getUser = query(v.string(), (id) => getUserFromDatabase(id))
    
    <script>
      import { getUser } from './get-user.remote.js';
      import { page } from '$app/state';
    </script>
    
    <h1>Hi, {(await getUser(page.params.userId).name}</h1>
    

    …when server rendering, the result of getUser will be inlined into the resulting HTML, and during hydration, getUser will simply return the data synchronously — no delays or additional requests involved.

    “But Elliott, I don’t want to use SvelteKit!” That’s fine! Remote functions have been our exploration into what the best possible version of data-fetching in SvelteKit could be. Now that we’ve had that exploration, we’re working on bringing some of that goodness into Svelte core, so that other framework authors can build similar solutions, or you can make your own.

    But what about pending snippets?

    The above behavior could be kind of annoying! It means that you have to send your server-rendered content to the browser, then kick off whatever asynchronous work needs to happen to render the non-pending contents of your boundary. We plan to fix this with streaming. In the future, this:

    <div>{await delayed("Hey y'all!", 1000)</div>
    <svelte:boundary>
      <div>{await delayed("What's up?", 1000)</div>
      {#snippet pending()}
        <div>Loading...</div>
      {/snippet}
    </svelte:boundary>
    

    will immediately render the pending snippet, but start rendering the non-pending content in the background. This non-pending content can then be sent to the browser after the initial response. This is the best of both worlds, where you can de-prioritize nonessential content by rendering a skeleton without needing multiple server round trips to fully hydrate your application.

    Okay, how do I try it?

    It’s out in the latest version of svelte! Just set experimental.async: true in your Svelte compile options. Once you’ve done this, awaiting or calling .then on the result of render will render your component asynchronously. If you’re using a framework, that framework will have to implement support. In the very near future, we’ll release an update to SvelteKit to pick up your compileOptions and automatically use async server rendering if you’ve turned the experimental compile option on.

Loading Svelte Themes