npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

svelte4-bc

v0.0.6

Published

Svelte 4 Backward Compatibility for Svelte 5

Downloads

351

Readme

Svelte 4 Backward Compatibility for Svelte 5

svelte4-bc is a plugin that improves Svelte 4 backwards compatibility in Svelte 5

Goals

The purpose of this package is to enable a step-by-step migration of components, by maintaining backward compatibility from caller's code, even after converting a component to the new Svelte 5 syntax (snippets/handlers).

This allows you to migrate a component without breaking all the code that uses it.

Why ?

Svelte 5 is already backwards compatible with the Svelte 4 syntax (slots, on:events directives), but only for Svelte 4 components.

When a component is migrated to the new syntax (snippet/handlers), all the calling codes that use this component should also be migrated in order to replace slots/on:events by snippets/handlers. This can be problematic on large projects, where we may want to make slower transitions.

svelte4-bc allows to use snippets/handlers within a component, while still accepting slots/on:events from the outside.

[!TIP] See this demo REPL for a quick preview !

How to install / configure ?

In a Svelte 5 project, install the package svelte4-bc :

npm i svelte4-bc

And edit the file vite.config.js in order to add the plugin :

import { sveltekit } from '@sveltejs/kit/vite';
+import { svelte4BCPlugin } from 'svelte4-bc/plugin';
import { defineConfig } from 'vite';

export default defineConfig({
-	plugins: [sveltekit()]
+	plugins: [sveltekit(), svelte4BCPlugin()]
});

This plugin will transform all *.svelte files all components whose exports a variable named svelte4_bc :

<script module>
  export const svelte4_bc = {
    slots: {
      // slots config
    },
    events: {
      // events config
    }
  }
</script>
<script>
    // Your code
</script>
<!-- Your template -->

Examples

Basic Example

Let's take this simple Svelte 4 component with a slot named prefix and an on:click event :

<!-- Button.svelte -->
<button on:click>
	{#if $$slots.prefix}
		<span><slot name="prefix"/></span>
	{/if}
	<slot/>
</button>

The Svelte 5 version of this component would be :

<!-- Button.svelte -->
<script>
	let { onclick, prefix, children } = $props();
</script>

<button {onclick}>
	{#if prefix}
		<span>{@render prefix()}</span>
	{/if}
	{@render children?.()}
</button>

But now, this component requires the use of snippets/handlers, and slots/on:events will be ignored :

<!-- This works -->
<Button onclick={onclick}>
	{#snippet prefix()}<i>(icon)</i>{/snippet}
	click
</Button>

<!-- This will compile normally, but slots/on:events will be ignored -->
<Button on:click={onclick}>
	<i slot="prefix">(icon)</i>
	click
</Button>

In order to "fix" this, we can add a <script module> with the configuration for Svelte4-BC :

<script module>
  export const svelte4_bc = {
    slots: {
      // The slot 'prefix' will be mapped onto the prop 'prefix'
      prefix: true
    },
    events: {
      // The event 'click' will be mapped onto the prop 'onclick'
      click: true
    }
  }
</script>

Now, the slots/on:events declared on the config will not be ignored, and they will be mapped to the corresponding props.

See and try the online demo on Stackblitz (since this is a plugin for ViteJS, it cannot be tested on the Svelte5 REPL)

An alternative would be to use the function Svelte4BCWrapper to manually wrap a component. See this Demo REPL

Name conflict

On Svelte 4, slots and on:events have their own namespaces separate from the props namespace.

<!-- Svelte 4 -->
<script>
	export let title;
</script>
<slot name="title" />

So we can encounter conflicts when migrating to Svelte 5, requiring to rename the snippets/handlers.

<!-- Svelte 5 -->
<script>
	let { title, title_snippet } = $props();
</script>
{@render title_snippet?.()}

We can use the config to define a new name for the slots/on:events :

<script module>
  export const svelte4_bc = {
    slots: {
      // The slot 'title' will be mapped onto the prop 'title_snippet'
      title: "title_snippet"
    }
  }
</script>

Slot's parameters

In Svelte 4, the slot variables are managed via an object :

<!-- Svelte 4 -->
<slot name="header" {title} {option} />

So a slot with parameters will have to be migrated to a snippet with an single object with the specified properties :

<!-- Svelte 5 -->
<script>
	let { header } = $props();
</script>

{@render header?.({ title, option })}

This is also the default behavior of this plugin.

But it is still possible to use multiples parameters, by configuring this plugin to remap the slot variables to the correct parameters :

<script module>
  export const svelte4_bc = {
    slots: {
      // The slot 'header' will be mapped onto the prop 'header'
      // The first param will be mapped to the slot variable 'title'
      // The second param will be mapped to the slot variable 'option'
      header: ['title', 'option']
    }
  }
</script>
<!-- Svelte 5 -->
<script>
	let { header } = $props();
</script>

{@render header?.(title, option)}

[!TIP] It is possible to use an object to define both the props and parameters of a slot :

<script module>
 export const svelte4_bc = {
   slots: {
     header: {
       // The slot 'header' will be mapped onto the prop 'new_name'
       prop: 'new_name',
       // The first param will be mapped to the slot variable 'title'
       // The second param will be mapped to the slot variable 'option'
       args: ['title', 'option']
   }
 }
</script>

Event dispatcher

<!-- Svelte 4 -->
<script>
	import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();

  // ...
  dispatch("custom");
</script>

createEventDispatcher is deprecated in Svelte 5, and should be replaced by callback props.

<!-- Svelte 5 -->
<script>
  let { oncustom } = $props();

  // ...
  oncustom?.();
</script>

However, it's possible to enable a compatibility mode by setting dispatch: true in svelte4_bc. In this mode, the dispatched event will be mapped to the equivalent callback props, like for event.

<script module>
  export const svelte4_bc = {
    events: {
      custom: true
    },
    dispatch: true
  }
</script>
<!-- Svelte 5 -->
<script>
	import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();

  // ...
  dispatch("custom"); // will be equivalent to oncustom?.();
</script>