Skip to content

Upgrading to Svelte 5

If you are upgrading to SveltePixi v8 from a Svelte 4 project, this guide will try to help you through the migration process. Please note that this it not an official Svelte 5 migration guide (that can be found here), but rather one that aims to help within the context of SveltePixi.

Try the Svelte 5 migration script

Before doing anything else, you should try the Svelte 5 migration script. If all goes well, all of your Svelte code migrated successfully and you can concern yourself with the Pixi-related breaking changes in SveltePixi v8

If all does not go well, keep reading!

Incrementally upgrading to Svelte 5

Svelte 5 can still run Svelte 4 code so you should be able to update to svelte@5 manually (& tooling etc) and leave your Svelte code as-is. This will allow you to incrementally upgrade your components to Svelte 5, and in the meantime, use SveltePixi v8 with the svelte-pixi/svelte-4 import. It fully supports all the same features as the Svelte 5 components (however, these will be removed in the next major version of SveltePixi).

<script>
import { Application, Text } from 'svelte-pixi/svelte-4'
</script>
<Application width={400} height={400} antialias>
<Text
x={200}
y={200}
anchor={0.5}
text="Hello World"
style={{ fill: 'white' }}
/>
</Application>

Svelte 4 and 5 interop

You can mix SveltePixi components that use Svelte 4 and Svelte 5. However, there are some caveats to be aware of.

Snippets / Slots

Svelte 5 introduced “snippets” to replace slots. Their documentation claims you can mix and match snippets/slots, but I have found that named slots do not work with snippets.

<script>
// receives Svelte 5 snippets
import SnippetComponent from './SnippetComponent.svelte'
// receives Svelte 4 slots
import SlotComponent from './SlotComponent.svelte'
</script>
<!-- passing snippets to slots -->
<SlotComponent>
<!-- both of these work -->
{#snippet a()}
<div>named slot</div>
{/snippet}
<div>children</div>
</SlotComponent>
<!-- passing slots to snippets -->
<SnippetComponent>
<!-- named slot does not work! -->
<div slot="a">named snippet</div>
<div>children</div>
</SnippetComponent>

Svelte playground

There may be other scenarios that cause issue too. In SveltePixi only Application, Renderer, and AssetsLoader take named slots, but if you have custom components that take named slots you will need to keep this in mind.

Events

In Svelte 5 events are now callback props. If you are using the svelte-pixi/svelte-4 import it still uses the on: syntax for events. If you are using the default svelte-pixi import, you will need to use the new callback syntax (which is much more performant as now it only listens for the events you actually use).

<Sprite on:pointermove={handlePointerMove} />
<!-- is now -->
<Sprite onpointermove={handlePointerMove} />

Svelte 4 Function Reactivity

This may be a Svelte bug, I’m not too sure, but I wanted to mention this finding. There are some scenarios where a function that was previously reactive in Svelte 4 syntax may no longer be reactive when using svelte@5.

For example, SveltePixi has a Graphics component that has a draw function prop.

<script>
import { Graphics, onTick } from 'svelte-pixi/svelte-4'
let size = 100
onTick(() => {
size += 1
})
</script>
<Graphics
draw={g => g.drawRect(0, 0, size, size)}
/>

In svelte@4, draw would be called again whenever size changed. The Graphics component would call it like this:

Graphics.svelte
<script>
export let instance = new PIXI.Graphics()
export let draw
$: draw(instance)
</script>

In svelte@5 this no longer works. Instead, draw needs to explicilty be declared as a reactive variable:

<script>
import { Graphics, onTick } from 'svelte-pixi/svelte-4'
let size = 100
onTick(() => {
size += 1
})
$: draw = g => g.drawRect(0, 0, size, size)
</script>
<Graphics {draw} />

If you migrate to the Svelte 5 SveltePixi component, simply declaring it as a function will work:

<script>
import { Graphics, onTick } from 'svelte-pixi'
let size = $state(100)
onTick(() => {
size += 1
})
function draw(g) {
g.drawRect(0, 0, size, size)
}
</script>
<Graphics
x={375}
y={200}
{draw}
/>